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 <thomas.faber@reactos.org>
16 *pExEnterCriticalRegionAndAcquireFastMutexUnsafe
)(
17 _Inout_ PFAST_MUTEX FastMutex
23 *pExReleaseFastMutexUnsafeAndLeaveCriticalRegion
)(
24 _Inout_ PFAST_MUTEX FastMutex
27 static VOID (FASTCALL
*pExiAcquireFastMutex
)(IN OUT PFAST_MUTEX FastMutex
);
28 static VOID (FASTCALL
*pExiReleaseFastMutex
)(IN OUT PFAST_MUTEX FastMutex
);
29 static BOOLEAN (FASTCALL
*pExiTryToAcquireFastMutex
)(IN OUT PFAST_MUTEX FastMutex
);
31 #define CheckMutex(Mutex, ExpectedCount, ExpectedOwner, \
32 ExpectedContention, ExpectedOldIrql, \
35 ok_eq_long((Mutex)->Count, ExpectedCount); \
36 ok_eq_pointer((Mutex)->Owner, ExpectedOwner); \
37 ok_eq_ulong((Mutex)->Contention, ExpectedContention); \
38 ok_eq_ulong((Mutex)->OldIrql, (ULONG)ExpectedOldIrql); \
39 ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); \
40 ok_irql(ExpectedIrql); \
49 PKTHREAD Thread
= KeGetCurrentThread();
51 ok_irql(OriginalIrql
);
53 /* acquire/release normally */
54 ExAcquireFastMutex(Mutex
);
55 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
56 ok_bool_false(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 /* ntoskrnl's fastcall version */
62 if (!skip(pExiAcquireFastMutex
&&
63 pExiReleaseFastMutex
&&
64 pExiTryToAcquireFastMutex
, "No fastcall fast mutex functions\n"))
66 pExiAcquireFastMutex(Mutex
);
67 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
68 ok_bool_false(pExiTryToAcquireFastMutex(Mutex
), "ExiTryToAcquireFastMutex returned");
69 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
70 pExiReleaseFastMutex(Mutex
);
71 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
75 ok_bool_true(ExTryToAcquireFastMutex(Mutex
), "ExTryToAcquireFastMutex returned");
76 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
77 ExReleaseFastMutex(Mutex
);
78 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
80 /* shortcut functions with critical region */
81 if (!skip(pExEnterCriticalRegionAndAcquireFastMutexUnsafe
&&
82 pExReleaseFastMutexUnsafeAndLeaveCriticalRegion
,
83 "Shortcut functions not available"))
85 pExEnterCriticalRegionAndAcquireFastMutexUnsafe(Mutex
);
86 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
87 pExReleaseFastMutexUnsafeAndLeaveCriticalRegion(Mutex
);
90 /* acquire/release unsafe */
91 if (!KmtIsCheckedBuild
|| OriginalIrql
== APC_LEVEL
)
93 ExAcquireFastMutexUnsafe(Mutex
);
94 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, OriginalIrql
);
95 ExReleaseFastMutexUnsafe(Mutex
);
96 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
98 /* mismatched acquire/release */
99 ExAcquireFastMutex(Mutex
);
100 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
101 ExReleaseFastMutexUnsafe(Mutex
);
102 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, APC_LEVEL
);
103 KmtSetIrql(OriginalIrql
);
104 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
106 Mutex
->OldIrql
= 0x55555555LU
;
107 ExAcquireFastMutexUnsafe(Mutex
);
108 CheckMutex(Mutex
, 0L, Thread
, 0LU, 0x55555555LU
, OriginalIrql
);
109 Mutex
->OldIrql
= PASSIVE_LEVEL
;
110 ExReleaseFastMutex(Mutex
);
111 CheckMutex(Mutex
, 1L, NULL
, 0LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
112 KmtSetIrql(OriginalIrql
);
113 CheckMutex(Mutex
, 1L, NULL
, 0LU, PASSIVE_LEVEL
, OriginalIrql
);
116 if (!KmtIsCheckedBuild
)
118 /* release without acquire */
119 ExReleaseFastMutexUnsafe(Mutex
);
120 CheckMutex(Mutex
, 2L, NULL
, 0LU, PASSIVE_LEVEL
, OriginalIrql
);
122 Mutex
->OldIrql
= OriginalIrql
;
123 ExReleaseFastMutex(Mutex
);
124 CheckMutex(Mutex
, 2L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
125 ExReleaseFastMutex(Mutex
);
126 CheckMutex(Mutex
, 3L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
130 /* make sure we survive this in case of error */
131 ok_eq_long(Mutex
->Count
, 1L);
133 ok_irql(OriginalIrql
);
134 KmtSetIrql(OriginalIrql
);
137 typedef VOID (FASTCALL
*PMUTEX_FUNCTION
)(PFAST_MUTEX
);
138 typedef BOOLEAN (FASTCALL
*PMUTEX_TRY_FUNCTION
)(PFAST_MUTEX
);
146 PMUTEX_FUNCTION Acquire
;
147 PMUTEX_TRY_FUNCTION TryAcquire
;
148 PMUTEX_FUNCTION Release
;
153 } THREAD_DATA
, *PTHREAD_DATA
;
161 PTHREAD_DATA ThreadData
= Parameter
;
166 KeRaiseIrql(ThreadData
->Irql
, &Irql
);
170 Ret
= ThreadData
->TryAcquire(ThreadData
->Mutex
);
171 ok_eq_bool(Ret
, ThreadData
->RetExpected
);
174 ThreadData
->Acquire(ThreadData
->Mutex
);
176 ok_bool_false(KeSetEvent(&ThreadData
->OutEvent
, 0, TRUE
), "KeSetEvent returned");
177 Status
= KeWaitForSingleObject(&ThreadData
->InEvent
, Executive
, KernelMode
, FALSE
, NULL
);
178 ok_eq_hex(Status
, STATUS_SUCCESS
);
180 if (!ThreadData
->Try
|| Ret
)
181 ThreadData
->Release(ThreadData
->Mutex
);
189 PTHREAD_DATA ThreadData
,
191 PMUTEX_FUNCTION Acquire
,
192 PMUTEX_TRY_FUNCTION TryAcquire
,
193 PMUTEX_FUNCTION Release
)
195 ThreadData
->Mutex
= Mutex
;
196 KeInitializeEvent(&ThreadData
->InEvent
, NotificationEvent
, FALSE
);
197 KeInitializeEvent(&ThreadData
->OutEvent
, NotificationEvent
, FALSE
);
198 ThreadData
->Acquire
= Acquire
;
199 ThreadData
->TryAcquire
= TryAcquire
;
200 ThreadData
->Release
= Release
;
206 PTHREAD_DATA ThreadData
,
207 PLARGE_INTEGER Timeout
,
212 NTSTATUS Status
= STATUS_SUCCESS
;
213 OBJECT_ATTRIBUTES Attributes
;
215 ThreadData
->Try
= Try
;
216 ThreadData
->Irql
= Irql
;
217 ThreadData
->RetExpected
= RetExpected
;
218 InitializeObjectAttributes(&Attributes
, NULL
, OBJ_KERNEL_HANDLE
, NULL
, NULL
);
219 Status
= PsCreateSystemThread(&ThreadData
->Handle
, GENERIC_ALL
, &Attributes
, NULL
, NULL
, AcquireMutexThread
, ThreadData
);
220 ok_eq_hex(Status
, STATUS_SUCCESS
);
221 Status
= ObReferenceObjectByHandle(ThreadData
->Handle
, SYNCHRONIZE
, *PsThreadType
, KernelMode
, (PVOID
*)&ThreadData
->Thread
, NULL
);
222 ok_eq_hex(Status
, STATUS_SUCCESS
);
224 return KeWaitForSingleObject(&ThreadData
->OutEvent
, Executive
, KernelMode
, FALSE
, Timeout
);
230 PTHREAD_DATA ThreadData
)
232 NTSTATUS Status
= STATUS_SUCCESS
;
234 KeSetEvent(&ThreadData
->InEvent
, 0, TRUE
);
235 Status
= KeWaitForSingleObject(ThreadData
->Thread
, Executive
, KernelMode
, FALSE
, NULL
);
236 ok_eq_hex(Status
, STATUS_SUCCESS
);
238 ObDereferenceObject(ThreadData
->Thread
);
239 Status
= ZwClose(ThreadData
->Handle
);
240 ok_eq_hex(Status
, STATUS_SUCCESS
);
241 KeClearEvent(&ThreadData
->InEvent
);
242 KeClearEvent(&ThreadData
->OutEvent
);
247 TestFastMutexConcurrent(
251 THREAD_DATA ThreadData
;
252 THREAD_DATA ThreadData2
;
253 THREAD_DATA ThreadDataUnsafe
;
254 THREAD_DATA ThreadDataTry
;
255 LARGE_INTEGER Timeout
;
256 Timeout
.QuadPart
= -10 * 1000 * 10; /* 10 ms */
258 InitThreadData(&ThreadData
, Mutex
, ExAcquireFastMutex
, NULL
, ExReleaseFastMutex
);
259 InitThreadData(&ThreadData2
, Mutex
, ExAcquireFastMutex
, NULL
, ExReleaseFastMutex
);
260 InitThreadData(&ThreadDataUnsafe
, Mutex
, ExAcquireFastMutexUnsafe
, NULL
, ExReleaseFastMutexUnsafe
);
261 InitThreadData(&ThreadDataTry
, Mutex
, NULL
, ExTryToAcquireFastMutex
, ExReleaseFastMutex
);
263 /* have a thread acquire the mutex */
264 Status
= StartThread(&ThreadData
, NULL
, PASSIVE_LEVEL
, FALSE
, FALSE
);
265 ok_eq_hex(Status
, STATUS_SUCCESS
);
266 CheckMutex(Mutex
, 0L, ThreadData
.Thread
, 0LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
267 /* have a second thread try to acquire it -- should fail */
268 Status
= StartThread(&ThreadDataTry
, NULL
, PASSIVE_LEVEL
, TRUE
, FALSE
);
269 ok_eq_hex(Status
, STATUS_SUCCESS
);
270 CheckMutex(Mutex
, 0L, ThreadData
.Thread
, 0LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
271 FinishThread(&ThreadDataTry
);
273 /* have another thread acquire it -- should block */
274 Status
= StartThread(&ThreadData2
, &Timeout
, APC_LEVEL
, FALSE
, FALSE
);
275 ok_eq_hex(Status
, STATUS_TIMEOUT
);
276 CheckMutex(Mutex
, -1L, ThreadData
.Thread
, 1LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
278 /* finish the first thread -- now the second should become available */
279 FinishThread(&ThreadData
);
280 Status
= KeWaitForSingleObject(&ThreadData2
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
281 ok_eq_hex(Status
, STATUS_SUCCESS
);
282 CheckMutex(Mutex
, 0L, ThreadData2
.Thread
, 1LU, APC_LEVEL
, PASSIVE_LEVEL
);
284 /* block two more threads */
285 Status
= StartThread(&ThreadDataUnsafe
, &Timeout
, APC_LEVEL
, FALSE
, FALSE
);
286 ok_eq_hex(Status
, STATUS_TIMEOUT
);
287 CheckMutex(Mutex
, -1L, ThreadData2
.Thread
, 2LU, APC_LEVEL
, PASSIVE_LEVEL
);
289 Status
= StartThread(&ThreadData
, &Timeout
, PASSIVE_LEVEL
, FALSE
, FALSE
);
290 ok_eq_hex(Status
, STATUS_TIMEOUT
);
291 CheckMutex(Mutex
, -2L, ThreadData2
.Thread
, 3LU, APC_LEVEL
, PASSIVE_LEVEL
);
294 FinishThread(&ThreadData2
);
295 Status
= KeWaitForSingleObject(&ThreadDataUnsafe
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
296 ok_eq_hex(Status
, STATUS_SUCCESS
);
297 CheckMutex(Mutex
, -1L, ThreadDataUnsafe
.Thread
, 3LU, APC_LEVEL
, PASSIVE_LEVEL
);
300 FinishThread(&ThreadDataUnsafe
);
301 Status
= KeWaitForSingleObject(&ThreadData
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
302 ok_eq_hex(Status
, STATUS_SUCCESS
);
303 CheckMutex(Mutex
, 0L, ThreadData
.Thread
, 3LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
306 FinishThread(&ThreadData
);
308 CheckMutex(Mutex
, 1L, NULL
, 3LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
311 START_TEST(ExFastMutex
)
316 pExEnterCriticalRegionAndAcquireFastMutexUnsafe
= KmtGetSystemRoutineAddress(L
"ExEnterCriticalRegionAndAcquireFastMutexUnsafe");
317 pExReleaseFastMutexUnsafeAndLeaveCriticalRegion
= KmtGetSystemRoutineAddress(L
"ExReleaseFastMutexUnsafeAndLeaveCriticalRegion");
319 pExiAcquireFastMutex
= KmtGetSystemRoutineAddress(L
"ExiAcquireFastMutex");
320 pExiReleaseFastMutex
= KmtGetSystemRoutineAddress(L
"ExiReleaseFastMutex");
321 pExiTryToAcquireFastMutex
= KmtGetSystemRoutineAddress(L
"ExiTryToAcquireFastMutex");
323 memset(&Mutex
, 0x55, sizeof Mutex
);
324 ExInitializeFastMutex(&Mutex
);
325 CheckMutex(&Mutex
, 1L, NULL
, 0LU, 0x55555555LU
, PASSIVE_LEVEL
);
327 TestFastMutex(&Mutex
, PASSIVE_LEVEL
);
328 KeRaiseIrql(APC_LEVEL
, &Irql
);
329 TestFastMutex(&Mutex
, APC_LEVEL
);
330 if (!KmtIsCheckedBuild
)
332 KeRaiseIrql(DISPATCH_LEVEL
, &Irql
);
333 TestFastMutex(&Mutex
, DISPATCH_LEVEL
);
334 KeRaiseIrql(HIGH_LEVEL
, &Irql
);
335 TestFastMutex(&Mutex
, HIGH_LEVEL
);
337 KeLowerIrql(PASSIVE_LEVEL
);
339 TestFastMutexConcurrent(&Mutex
);