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>
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
);
48 /* ntoskrnl's fastcall version */
49 ExiAcquireFastMutex(Mutex
);
50 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
51 ok_bool_false(ExiTryToAcquireFastMutex(Mutex
), "ExiTryToAcquireFastMutex returned");
52 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
53 ExiReleaseFastMutex(Mutex
);
54 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
58 ok_bool_true(ExTryToAcquireFastMutex(Mutex
), "ExTryToAcquireFastMutex returned");
59 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
60 ExReleaseFastMutex(Mutex
);
61 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
63 /* shortcut functions with critical region */
64 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(Mutex
);
65 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
66 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(Mutex
);
68 /* acquire/release unsafe */
69 if (!KmtIsCheckedBuild
|| OriginalIrql
== APC_LEVEL
)
71 ExAcquireFastMutexUnsafe(Mutex
);
72 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, OriginalIrql
);
73 ExReleaseFastMutexUnsafe(Mutex
);
74 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
76 /* mismatched acquire/release */
77 ExAcquireFastMutex(Mutex
);
78 CheckMutex(Mutex
, 0L, Thread
, 0LU, OriginalIrql
, APC_LEVEL
);
79 ExReleaseFastMutexUnsafe(Mutex
);
80 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, APC_LEVEL
);
81 KmtSetIrql(OriginalIrql
);
82 CheckMutex(Mutex
, 1L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
84 Mutex
->OldIrql
= 0x55555555LU
;
85 ExAcquireFastMutexUnsafe(Mutex
);
86 CheckMutex(Mutex
, 0L, Thread
, 0LU, 0x55555555LU
, OriginalIrql
);
87 Mutex
->OldIrql
= PASSIVE_LEVEL
;
88 ExReleaseFastMutex(Mutex
);
89 CheckMutex(Mutex
, 1L, NULL
, 0LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
90 KmtSetIrql(OriginalIrql
);
91 CheckMutex(Mutex
, 1L, NULL
, 0LU, PASSIVE_LEVEL
, OriginalIrql
);
94 if (!KmtIsCheckedBuild
)
96 /* release without acquire */
97 ExReleaseFastMutexUnsafe(Mutex
);
98 CheckMutex(Mutex
, 2L, NULL
, 0LU, PASSIVE_LEVEL
, OriginalIrql
);
100 Mutex
->OldIrql
= OriginalIrql
;
101 ExReleaseFastMutex(Mutex
);
102 CheckMutex(Mutex
, 2L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
103 ExReleaseFastMutex(Mutex
);
104 CheckMutex(Mutex
, 3L, NULL
, 0LU, OriginalIrql
, OriginalIrql
);
108 /* make sure we survive this in case of error */
109 ok_eq_long(Mutex
->Count
, 1L);
111 ok_irql(OriginalIrql
);
112 KmtSetIrql(OriginalIrql
);
115 typedef VOID (FASTCALL
*PMUTEX_FUNCTION
)(PFAST_MUTEX
);
116 typedef BOOLEAN (FASTCALL
*PMUTEX_TRY_FUNCTION
)(PFAST_MUTEX
);
124 PMUTEX_FUNCTION Acquire
;
125 PMUTEX_TRY_FUNCTION TryAcquire
;
126 PMUTEX_FUNCTION Release
;
131 } THREAD_DATA
, *PTHREAD_DATA
;
139 PTHREAD_DATA ThreadData
= Parameter
;
144 KeRaiseIrql(ThreadData
->Irql
, &Irql
);
148 Ret
= ThreadData
->TryAcquire(ThreadData
->Mutex
);
149 ok_eq_bool(Ret
, ThreadData
->RetExpected
);
152 ThreadData
->Acquire(ThreadData
->Mutex
);
154 ok_bool_false(KeSetEvent(&ThreadData
->OutEvent
, 0, TRUE
), "KeSetEvent returned");
155 Status
= KeWaitForSingleObject(&ThreadData
->InEvent
, Executive
, KernelMode
, FALSE
, NULL
);
156 ok_eq_hex(Status
, STATUS_SUCCESS
);
158 if (!ThreadData
->Try
|| Ret
)
159 ThreadData
->Release(ThreadData
->Mutex
);
167 PTHREAD_DATA ThreadData
,
169 PMUTEX_FUNCTION Acquire
,
170 PMUTEX_TRY_FUNCTION TryAcquire
,
171 PMUTEX_FUNCTION Release
)
173 ThreadData
->Mutex
= Mutex
;
174 KeInitializeEvent(&ThreadData
->InEvent
, NotificationEvent
, FALSE
);
175 KeInitializeEvent(&ThreadData
->OutEvent
, NotificationEvent
, FALSE
);
176 ThreadData
->Acquire
= Acquire
;
177 ThreadData
->TryAcquire
= TryAcquire
;
178 ThreadData
->Release
= Release
;
184 PTHREAD_DATA ThreadData
,
185 PLARGE_INTEGER Timeout
,
190 NTSTATUS Status
= STATUS_SUCCESS
;
191 OBJECT_ATTRIBUTES Attributes
;
193 ThreadData
->Try
= Try
;
194 ThreadData
->Irql
= Irql
;
195 ThreadData
->RetExpected
= RetExpected
;
196 InitializeObjectAttributes(&Attributes
, NULL
, OBJ_KERNEL_HANDLE
, NULL
, NULL
);
197 Status
= PsCreateSystemThread(&ThreadData
->Handle
, GENERIC_ALL
, &Attributes
, NULL
, NULL
, AcquireMutexThread
, ThreadData
);
198 ok_eq_hex(Status
, STATUS_SUCCESS
);
199 Status
= ObReferenceObjectByHandle(ThreadData
->Handle
, SYNCHRONIZE
, *PsThreadType
, KernelMode
, (PVOID
*)&ThreadData
->Thread
, NULL
);
200 ok_eq_hex(Status
, STATUS_SUCCESS
);
202 return KeWaitForSingleObject(&ThreadData
->OutEvent
, Executive
, KernelMode
, FALSE
, Timeout
);
208 PTHREAD_DATA ThreadData
)
210 NTSTATUS Status
= STATUS_SUCCESS
;
212 KeSetEvent(&ThreadData
->InEvent
, 0, TRUE
);
213 Status
= KeWaitForSingleObject(ThreadData
->Thread
, Executive
, KernelMode
, FALSE
, NULL
);
214 ok_eq_hex(Status
, STATUS_SUCCESS
);
216 ObDereferenceObject(ThreadData
->Thread
);
217 Status
= ZwClose(ThreadData
->Handle
);
218 ok_eq_hex(Status
, STATUS_SUCCESS
);
219 KeClearEvent(&ThreadData
->InEvent
);
220 KeClearEvent(&ThreadData
->OutEvent
);
225 TestFastMutexConcurrent(
229 THREAD_DATA ThreadData
;
230 THREAD_DATA ThreadData2
;
231 THREAD_DATA ThreadDataUnsafe
;
232 THREAD_DATA ThreadDataTry
;
233 LARGE_INTEGER Timeout
;
234 Timeout
.QuadPart
= -10 * 1000 * 10; /* 10 ms */
236 InitThreadData(&ThreadData
, Mutex
, ExAcquireFastMutex
, NULL
, ExReleaseFastMutex
);
237 InitThreadData(&ThreadData2
, Mutex
, ExAcquireFastMutex
, NULL
, ExReleaseFastMutex
);
238 InitThreadData(&ThreadDataUnsafe
, Mutex
, ExAcquireFastMutexUnsafe
, NULL
, ExReleaseFastMutexUnsafe
);
239 InitThreadData(&ThreadDataTry
, Mutex
, NULL
, ExTryToAcquireFastMutex
, ExReleaseFastMutex
);
241 /* have a thread acquire the mutex */
242 Status
= StartThread(&ThreadData
, NULL
, PASSIVE_LEVEL
, FALSE
, FALSE
);
243 ok_eq_hex(Status
, STATUS_SUCCESS
);
244 CheckMutex(Mutex
, 0L, ThreadData
.Thread
, 0LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
245 /* have a second thread try to acquire it -- should fail */
246 Status
= StartThread(&ThreadDataTry
, NULL
, PASSIVE_LEVEL
, TRUE
, FALSE
);
247 ok_eq_hex(Status
, STATUS_SUCCESS
);
248 CheckMutex(Mutex
, 0L, ThreadData
.Thread
, 0LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
249 FinishThread(&ThreadDataTry
);
251 /* have another thread acquire it -- should block */
252 Status
= StartThread(&ThreadData2
, &Timeout
, APC_LEVEL
, FALSE
, FALSE
);
253 ok_eq_hex(Status
, STATUS_TIMEOUT
);
254 CheckMutex(Mutex
, -1L, ThreadData
.Thread
, 1LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
256 /* finish the first thread -- now the second should become available */
257 FinishThread(&ThreadData
);
258 Status
= KeWaitForSingleObject(&ThreadData2
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
259 ok_eq_hex(Status
, STATUS_SUCCESS
);
260 CheckMutex(Mutex
, 0L, ThreadData2
.Thread
, 1LU, APC_LEVEL
, PASSIVE_LEVEL
);
262 /* block two more threads */
263 Status
= StartThread(&ThreadDataUnsafe
, &Timeout
, APC_LEVEL
, FALSE
, FALSE
);
264 ok_eq_hex(Status
, STATUS_TIMEOUT
);
265 CheckMutex(Mutex
, -1L, ThreadData2
.Thread
, 2LU, APC_LEVEL
, PASSIVE_LEVEL
);
267 Status
= StartThread(&ThreadData
, &Timeout
, PASSIVE_LEVEL
, FALSE
, FALSE
);
268 ok_eq_hex(Status
, STATUS_TIMEOUT
);
269 CheckMutex(Mutex
, -2L, ThreadData2
.Thread
, 3LU, APC_LEVEL
, PASSIVE_LEVEL
);
272 FinishThread(&ThreadData2
);
273 Status
= KeWaitForSingleObject(&ThreadDataUnsafe
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
274 ok_eq_hex(Status
, STATUS_SUCCESS
);
275 CheckMutex(Mutex
, -1L, ThreadDataUnsafe
.Thread
, 3LU, APC_LEVEL
, PASSIVE_LEVEL
);
278 FinishThread(&ThreadDataUnsafe
);
279 Status
= KeWaitForSingleObject(&ThreadData
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
280 ok_eq_hex(Status
, STATUS_SUCCESS
);
281 CheckMutex(Mutex
, 0L, ThreadData
.Thread
, 3LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
284 FinishThread(&ThreadData
);
286 CheckMutex(Mutex
, 1L, NULL
, 3LU, PASSIVE_LEVEL
, PASSIVE_LEVEL
);
289 START_TEST(ExFastMutex
)
294 memset(&Mutex
, 0x55, sizeof Mutex
);
295 ExInitializeFastMutex(&Mutex
);
296 CheckMutex(&Mutex
, 1L, NULL
, 0LU, 0x55555555LU
, PASSIVE_LEVEL
);
298 TestFastMutex(&Mutex
, PASSIVE_LEVEL
);
299 KeRaiseIrql(APC_LEVEL
, &Irql
);
300 TestFastMutex(&Mutex
, APC_LEVEL
);
301 if (!KmtIsCheckedBuild
)
303 KeRaiseIrql(DISPATCH_LEVEL
, &Irql
);
304 TestFastMutex(&Mutex
, DISPATCH_LEVEL
);
305 KeRaiseIrql(HIGH_LEVEL
, &Irql
);
306 TestFastMutex(&Mutex
, HIGH_LEVEL
);
308 KeLowerIrql(PASSIVE_LEVEL
);
310 TestFastMutexConcurrent(&Mutex
);