2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Fast Mutex test
5 * PROGRAMMER: Thomas Faber <thfabba@gmx.de>
13 NTKERNELAPI VOID FASTCALL
ExiAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex
);
14 NTKERNELAPI VOID FASTCALL
ExiReleaseFastMutex(IN OUT PFAST_MUTEX FastMutex
);
15 NTKERNELAPI BOOLEAN FASTCALL
ExiTryToAcquireFastMutex(IN OUT PFAST_MUTEX FastMutex
);
17 #define CheckMutex(Mutex, ExpectedCount, ExpectedOwner, \
18 ExpectedContention, ExpectedOldIrql, \
21 ok_eq_long((Mutex)->Count, ExpectedCount); \
22 ok_eq_pointer((Mutex)->Owner, ExpectedOwner); \
23 ok_eq_ulong((Mutex)->Contention, ExpectedContention); \
24 ok_eq_ulong((Mutex)->OldIrql, (ULONG)ExpectedOldIrql); \
25 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); \
26 ok_irql(ExpectedIrql); \
35 PKTHREAD Thread
= KeGetCurrentThread();
37 ok_irql(OriginalIrql
);
39 /* acquire/release normally */
40 ExAcquireFastMutex(Mutex
);
41 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
42 ok_bool_false(ExTryToAcquireFastMutex(Mutex
), "ExTryToAcquireFastMutex returned");
43 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
44 ExReleaseFastMutex(Mutex
);
45 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
47 /* ntoskrnl's fastcall version */
48 ExiAcquireFastMutex(Mutex
);
49 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
50 ok_bool_false(ExiTryToAcquireFastMutex(Mutex
), "ExiTryToAcquireFastMutex returned");
51 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
52 ExiReleaseFastMutex(Mutex
);
53 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
56 ok_bool_true(ExTryToAcquireFastMutex(Mutex
), "ExTryToAcquireFastMutex returned");
57 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
58 ExReleaseFastMutex(Mutex
);
59 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
61 /* shortcut functions with critical region */
62 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(Mutex
);
63 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
64 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(Mutex
);
66 /* acquire/release unsafe */
67 if (!KmtIsCheckedBuild
|| OriginalIrql
== APC_LEVEL
)
69 ExAcquireFastMutexUnsafe(Mutex
);
70 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, OriginalIrql
);
71 ExReleaseFastMutexUnsafe(Mutex
);
72 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
74 /* mismatched acquire/release */
75 ExAcquireFastMutex(Mutex
);
76 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
77 ExReleaseFastMutexUnsafe(Mutex
);
78 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, APC_LEVEL
);
79 KmtSetIrql(OriginalIrql
);
80 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
82 Mutex
->OldIrql
= 0x55555555LU
;
83 ExAcquireFastMutexUnsafe(Mutex
);
84 CheckMutex(Mutex
, 0L, Thread
, 0LU, 0x55555555LU
, OriginalIrql
);
85 Mutex
->OldIrql
= PASSIVE_LEVEL
;
86 ExReleaseFastMutex(Mutex
);
87 CheckMutex(Mutex
, 1L, NULL
, 0LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
88 KmtSetIrql(OriginalIrql
);
89 CheckMutex(Mutex
, 1L, NULL
, 0LU, PASSIVE_LEVEL
, OriginalIrql
);
92 if (!KmtIsCheckedBuild
)
94 /* release without acquire */
95 ExReleaseFastMutexUnsafe(Mutex
);
96 CheckMutex(Mutex
, 2L, NULL
, 0LU, PASSIVE_LEVEL
, OriginalIrql
);
98 Mutex
->OldIrql
= OriginalIrql
;
99 ExReleaseFastMutex(Mutex
);
100 CheckMutex(Mutex
, 2L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
101 ExReleaseFastMutex(Mutex
);
102 CheckMutex(Mutex
, 3L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
106 /* make sure we survive this in case of error */
107 ok_eq_long(Mutex
->Count
, 1L);
109 ok_irql(OriginalIrql
);
110 KmtSetIrql(OriginalIrql
);
113 typedef VOID (FASTCALL
*PMUTEX_FUNCTION
)(PFAST_MUTEX
);
114 typedef BOOLEAN (FASTCALL
*PMUTEX_TRY_FUNCTION
)(PFAST_MUTEX
);
122 PMUTEX_FUNCTION Acquire
;
123 PMUTEX_TRY_FUNCTION TryAcquire
;
124 PMUTEX_FUNCTION Release
;
129 } THREAD_DATA
, *PTHREAD_DATA
;
137 PTHREAD_DATA ThreadData
= Parameter
;
142 KeRaiseIrql(ThreadData
->Irql
, &Irql
);
146 Ret
= ThreadData
->TryAcquire(ThreadData
->Mutex
);
147 ok_eq_bool(Ret
, ThreadData
->RetExpected
);
150 ThreadData
->Acquire(ThreadData
->Mutex
);
152 ok_bool_false(KeSetEvent(&ThreadData
->OutEvent
, 0, TRUE
), "KeSetEvent returned");
153 Status
= KeWaitForSingleObject(&ThreadData
->InEvent
, Executive
, KernelMode
, FALSE
, NULL
);
154 ok_eq_hex(Status
, STATUS_SUCCESS
);
156 if (!ThreadData
->Try
|| Ret
)
157 ThreadData
->Release(ThreadData
->Mutex
);
165 PTHREAD_DATA ThreadData
,
167 PMUTEX_FUNCTION Acquire
,
168 PMUTEX_TRY_FUNCTION TryAcquire
,
169 PMUTEX_FUNCTION Release
)
171 ThreadData
->Mutex
= Mutex
;
172 KeInitializeEvent(&ThreadData
->InEvent
, NotificationEvent
, FALSE
);
173 KeInitializeEvent(&ThreadData
->OutEvent
, NotificationEvent
, FALSE
);
174 ThreadData
->Acquire
= Acquire
;
175 ThreadData
->TryAcquire
= TryAcquire
;
176 ThreadData
->Release
= Release
;
182 PTHREAD_DATA ThreadData
,
183 PLARGE_INTEGER Timeout
,
188 NTSTATUS Status
= STATUS_SUCCESS
;
189 OBJECT_ATTRIBUTES Attributes
;
191 ThreadData
->Try
= Try
;
192 ThreadData
->Irql
= Irql
;
193 ThreadData
->RetExpected
= RetExpected
;
194 InitializeObjectAttributes(&Attributes
, NULL
, OBJ_KERNEL_HANDLE
, NULL
, NULL
);
195 Status
= PsCreateSystemThread(&ThreadData
->Handle
, GENERIC_ALL
, &Attributes
, NULL
, NULL
, AcquireMutexThread
, ThreadData
);
196 ok_eq_hex(Status
, STATUS_SUCCESS
);
197 Status
= ObReferenceObjectByHandle(ThreadData
->Handle
, SYNCHRONIZE
, PsThreadType
, KernelMode
, (PVOID
*)&ThreadData
->Thread
, NULL
);
198 ok_eq_hex(Status
, STATUS_SUCCESS
);
200 return KeWaitForSingleObject(&ThreadData
->OutEvent
, Executive
, KernelMode
, FALSE
, Timeout
);
206 PTHREAD_DATA ThreadData
)
208 NTSTATUS Status
= STATUS_SUCCESS
;
210 KeSetEvent(&ThreadData
->InEvent
, 0, TRUE
);
211 Status
= KeWaitForSingleObject(ThreadData
->Thread
, Executive
, KernelMode
, FALSE
, NULL
);
212 ok_eq_hex(Status
, STATUS_SUCCESS
);
214 ObDereferenceObject(ThreadData
->Thread
);
215 Status
= ZwClose(ThreadData
->Handle
);
216 ok_eq_hex(Status
, STATUS_SUCCESS
);
217 KeClearEvent(&ThreadData
->InEvent
);
218 KeClearEvent(&ThreadData
->OutEvent
);
223 TestFastMutexConcurrent(
227 THREAD_DATA ThreadData
;
228 THREAD_DATA ThreadData2
;
229 THREAD_DATA ThreadDataUnsafe
;
230 THREAD_DATA ThreadDataTry
;
231 LARGE_INTEGER Timeout
;
232 Timeout
.QuadPart
= -10 * 1000 * 10; /* 10 ms */
234 InitThreadData(&ThreadData
, Mutex
, ExAcquireFastMutex
, NULL
, ExReleaseFastMutex
);
235 InitThreadData(&ThreadData2
, Mutex
, ExAcquireFastMutex
, NULL
, ExReleaseFastMutex
);
236 InitThreadData(&ThreadDataUnsafe
, Mutex
, ExAcquireFastMutexUnsafe
, NULL
, ExReleaseFastMutexUnsafe
);
237 InitThreadData(&ThreadDataTry
, Mutex
, NULL
, ExTryToAcquireFastMutex
, ExReleaseFastMutex
);
239 /* have a thread acquire the mutex */
240 Status
= StartThread(&ThreadData
, NULL
, PASSIVE_LEVEL
, FALSE
, FALSE
);
241 ok_eq_hex(Status
, STATUS_SUCCESS
);
242 CheckMutex(Mutex
, 0L, ThreadData
.Thread
, 0LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
243 /* have a second thread try to acquire it -- should fail */
244 Status
= StartThread(&ThreadDataTry
, NULL
, PASSIVE_LEVEL
, TRUE
, FALSE
);
245 ok_eq_hex(Status
, STATUS_SUCCESS
);
246 CheckMutex(Mutex
, 0L, ThreadData
.Thread
, 0LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
247 FinishThread(&ThreadDataTry
);
249 /* have another thread acquire it -- should block */
250 Status
= StartThread(&ThreadData2
, &Timeout
, APC_LEVEL
, FALSE
, FALSE
);
251 ok_eq_hex(Status
, STATUS_TIMEOUT
);
252 CheckMutex(Mutex
, -1L, ThreadData
.Thread
, 1LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
254 /* finish the first thread -- now the second should become available */
255 FinishThread(&ThreadData
);
256 Status
= KeWaitForSingleObject(&ThreadData2
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
257 ok_eq_hex(Status
, STATUS_SUCCESS
);
258 CheckMutex(Mutex
, 0L, ThreadData2
.Thread
, 1LU, APC_LEVEL
, PASSIVE_LEVEL
);
260 /* block two more threads */
261 Status
= StartThread(&ThreadDataUnsafe
, &Timeout
, APC_LEVEL
, FALSE
, FALSE
);
262 ok_eq_hex(Status
, STATUS_TIMEOUT
);
263 CheckMutex(Mutex
, -1L, ThreadData2
.Thread
, 2LU, APC_LEVEL
, PASSIVE_LEVEL
);
265 Status
= StartThread(&ThreadData
, &Timeout
, PASSIVE_LEVEL
, FALSE
, FALSE
);
266 ok_eq_hex(Status
, STATUS_TIMEOUT
);
267 CheckMutex(Mutex
, -2L, ThreadData2
.Thread
, 3LU, APC_LEVEL
, PASSIVE_LEVEL
);
270 FinishThread(&ThreadData2
);
271 Status
= KeWaitForSingleObject(&ThreadDataUnsafe
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
272 ok_eq_hex(Status
, STATUS_SUCCESS
);
273 CheckMutex(Mutex
, -1L, ThreadDataUnsafe
.Thread
, 3LU, APC_LEVEL
, PASSIVE_LEVEL
);
276 FinishThread(&ThreadDataUnsafe
);
277 Status
= KeWaitForSingleObject(&ThreadData
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
278 ok_eq_hex(Status
, STATUS_SUCCESS
);
279 CheckMutex(Mutex
, 0L, ThreadData
.Thread
, 3LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
282 FinishThread(&ThreadData
);
284 CheckMutex(Mutex
, 1L, NULL
, 3LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
287 START_TEST(ExFastMutex
)
292 memset(&Mutex
, 0x55, sizeof Mutex
);
293 ExInitializeFastMutex(&Mutex
);
294 CheckMutex(&Mutex
, 1L, NULL
, 0LU, 0x55555555LU
, PASSIVE_LEVEL
);
296 TestFastMutex(&Mutex
, PASSIVE_LEVEL
);
297 KeRaiseIrql(APC_LEVEL
, &Irql
);
298 TestFastMutex(&Mutex
, APC_LEVEL
);
299 if (!KmtIsCheckedBuild
)
301 KeRaiseIrql(DISPATCH_LEVEL
, &Irql
);
302 TestFastMutex(&Mutex
, DISPATCH_LEVEL
);
303 KeRaiseIrql(HIGH_LEVEL
, &Irql
);
304 TestFastMutex(&Mutex
, HIGH_LEVEL
);
306 KeLowerIrql(PASSIVE_LEVEL
);
308 TestFastMutexConcurrent(&Mutex
);