2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Kernel-Mode Test Suite Guarded Mutex test
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
13 #define CheckMutex(Mutex, ExpectedCount, ExpectedOwner, ExpectedContention, \
14 ExpectedKernelApcDisable, ExpectedSpecialApcDisable, \
15 KernelApcsDisabled, SpecialApcsDisabled, AllApcsDisabled, \
18 ok_eq_long((Mutex)->Count, ExpectedCount); \
19 ok_eq_pointer((Mutex)->Owner, ExpectedOwner); \
20 ok_eq_ulong((Mutex)->Contention, ExpectedContention); \
21 ok_eq_int((Mutex)->KernelApcDisable, ExpectedKernelApcDisable); \
22 if (KmtIsCheckedBuild) \
23 ok_eq_int((Mutex)->SpecialApcDisable, ExpectedSpecialApcDisable); \
25 ok_eq_int((Mutex)->SpecialApcDisable, 0x5555); \
26 ok_eq_bool(KeAreApcsDisabled(), KernelApcsDisabled || SpecialApcsDisabled); \
27 ok_eq_int(Thread->KernelApcDisable, KernelApcsDisabled); \
28 ok_eq_bool(KeAreAllApcsDisabled(), AllApcsDisabled); \
29 ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled); \
30 ok_irql(ExpectedIrql); \
36 PKGUARDED_MUTEX Mutex
,
37 SHORT KernelApcsDisabled
,
38 SHORT SpecialApcsDisabled
,
39 SHORT AllApcsDisabled
,
42 PKTHREAD Thread
= KeGetCurrentThread();
44 ok_irql(OriginalIrql
);
45 CheckMutex(Mutex
, 1L, NULL
, 0LU, 0x5555, 0x5555, KernelApcsDisabled
, SpecialApcsDisabled
, AllApcsDisabled
, OriginalIrql
);
48 if (!KmtIsCheckedBuild
|| OriginalIrql
<= APC_LEVEL
)
50 /* acquire/release normally */
51 KeAcquireGuardedMutex(Mutex
);
52 CheckMutex(Mutex
, 0L, Thread
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
- 1, TRUE
, OriginalIrql
);
53 ok_bool_false(KeTryToAcquireGuardedMutex(Mutex
), "KeTryToAcquireGuardedMutex returned");
54 CheckMutex(Mutex
, 0L, Thread
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
- 1, TRUE
, OriginalIrql
);
55 KeReleaseGuardedMutex(Mutex
);
56 CheckMutex(Mutex
, 1L, NULL
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
, AllApcsDisabled
, OriginalIrql
);
59 ok_bool_true(KeTryToAcquireGuardedMutex(Mutex
), "KeTryToAcquireGuardedMutex returned");
60 CheckMutex(Mutex
, 0L, Thread
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
- 1, TRUE
, OriginalIrql
);
61 KeReleaseGuardedMutex(Mutex
);
62 CheckMutex(Mutex
, 1L, NULL
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
, AllApcsDisabled
, OriginalIrql
);
65 /* Make the following test happy */
66 Mutex
->SpecialApcDisable
= SpecialApcsDisabled
- 1;
69 if (!KmtIsCheckedBuild
|| OriginalIrql
== APC_LEVEL
|| SpecialApcsDisabled
< 0)
71 /* acquire/release unsafe */
72 KeAcquireGuardedMutexUnsafe(Mutex
);
73 CheckMutex(Mutex
, 0L, Thread
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
, AllApcsDisabled
, OriginalIrql
);
74 KeReleaseGuardedMutexUnsafe(Mutex
);
75 CheckMutex(Mutex
, 1L, NULL
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
, AllApcsDisabled
, OriginalIrql
);
78 /* Bugchecks >= DISPATCH_LEVEL */
79 if (!KmtIsCheckedBuild
)
81 /* mismatched acquire/release */
82 KeAcquireGuardedMutex(Mutex
);
83 CheckMutex(Mutex
, 0L, Thread
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
- 1, TRUE
, OriginalIrql
);
84 KeReleaseGuardedMutexUnsafe(Mutex
);
85 CheckMutex(Mutex
, 1L, NULL
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
- 1, TRUE
, OriginalIrql
);
86 KeLeaveGuardedRegion();
87 CheckMutex(Mutex
, 1L, NULL
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
, AllApcsDisabled
, OriginalIrql
);
89 KeAcquireGuardedMutexUnsafe(Mutex
);
90 CheckMutex(Mutex
, 0L, Thread
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
, AllApcsDisabled
, OriginalIrql
);
91 KeReleaseGuardedMutex(Mutex
);
92 CheckMutex(Mutex
, 1L, NULL
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
+ 1, OriginalIrql
>= APC_LEVEL
|| SpecialApcsDisabled
!= -1, OriginalIrql
);
93 KeEnterGuardedRegion();
94 CheckMutex(Mutex
, 1L, NULL
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
, AllApcsDisabled
, OriginalIrql
);
96 /* release without acquire */
97 KeReleaseGuardedMutexUnsafe(Mutex
);
98 CheckMutex(Mutex
, 0L, NULL
, 0LU, 0x5555, SpecialApcsDisabled
- 1, KernelApcsDisabled
, SpecialApcsDisabled
, AllApcsDisabled
, OriginalIrql
);
99 KeReleaseGuardedMutex(Mutex
);
100 CheckMutex(Mutex
, 1L, NULL
, 0LU, 0x5555, SpecialApcsDisabled
, KernelApcsDisabled
, SpecialApcsDisabled
+ 1, OriginalIrql
>= APC_LEVEL
|| SpecialApcsDisabled
!= -1, OriginalIrql
);
101 KeReleaseGuardedMutex(Mutex
);
102 /* TODO: here we see that Mutex->Count isn't actually just a count. Test the bits correctly! */
103 CheckMutex(Mutex
, 0L, NULL
, 0LU, 0x5555, SpecialApcsDisabled
, KernelApcsDisabled
, SpecialApcsDisabled
+ 2, OriginalIrql
>= APC_LEVEL
|| SpecialApcsDisabled
!= -2, OriginalIrql
);
104 KeReleaseGuardedMutex(Mutex
);
105 CheckMutex(Mutex
, 1L, NULL
, 0LU, 0x5555, SpecialApcsDisabled
, KernelApcsDisabled
, SpecialApcsDisabled
+ 3, OriginalIrql
>= APC_LEVEL
|| SpecialApcsDisabled
!= -3, OriginalIrql
);
106 Thread
->SpecialApcDisable
-= 3;
109 /* make sure we survive this in case of error */
110 ok_eq_long(Mutex
->Count
, 1L);
112 ok_eq_int(Thread
->KernelApcDisable
, KernelApcsDisabled
);
113 Thread
->KernelApcDisable
= KernelApcsDisabled
;
114 ok_eq_int(Thread
->SpecialApcDisable
, SpecialApcsDisabled
);
115 Thread
->SpecialApcDisable
= SpecialApcsDisabled
;
116 ok_irql(OriginalIrql
);
119 typedef VOID (FASTCALL
*PMUTEX_FUNCTION
)(PKGUARDED_MUTEX
);
120 typedef BOOLEAN (FASTCALL
*PMUTEX_TRY_FUNCTION
)(PKGUARDED_MUTEX
);
127 PKGUARDED_MUTEX Mutex
;
128 PMUTEX_FUNCTION Acquire
;
129 PMUTEX_TRY_FUNCTION TryAcquire
;
130 PMUTEX_FUNCTION Release
;
135 } THREAD_DATA
, *PTHREAD_DATA
;
143 PTHREAD_DATA ThreadData
= Parameter
;
148 DPRINT("Thread starting\n");
149 KeRaiseIrql(ThreadData
->Irql
, &Irql
);
153 Ret
= ThreadData
->TryAcquire(ThreadData
->Mutex
);
154 ok_eq_bool(Ret
, ThreadData
->RetExpected
);
157 ThreadData
->Acquire(ThreadData
->Mutex
);
159 ok_bool_false(KeSetEvent(&ThreadData
->OutEvent
, 0, TRUE
), "KeSetEvent returned");
160 DPRINT("Thread now waiting\n");
161 Status
= KeWaitForSingleObject(&ThreadData
->InEvent
, Executive
, KernelMode
, FALSE
, NULL
);
162 DPRINT("Thread done waiting\n");
163 ok_eq_hex(Status
, STATUS_SUCCESS
);
165 if (!ThreadData
->Try
|| Ret
)
166 ThreadData
->Release(ThreadData
->Mutex
);
169 DPRINT("Thread exiting\n");
175 PTHREAD_DATA ThreadData
,
176 PKGUARDED_MUTEX Mutex
,
177 PMUTEX_FUNCTION Acquire
,
178 PMUTEX_TRY_FUNCTION TryAcquire
,
179 PMUTEX_FUNCTION Release
)
181 ThreadData
->Mutex
= Mutex
;
182 KeInitializeEvent(&ThreadData
->InEvent
, NotificationEvent
, FALSE
);
183 KeInitializeEvent(&ThreadData
->OutEvent
, NotificationEvent
, FALSE
);
184 ThreadData
->Acquire
= Acquire
;
185 ThreadData
->TryAcquire
= TryAcquire
;
186 ThreadData
->Release
= Release
;
192 PTHREAD_DATA ThreadData
,
193 PLARGE_INTEGER Timeout
,
198 NTSTATUS Status
= STATUS_SUCCESS
;
199 OBJECT_ATTRIBUTES Attributes
;
201 ThreadData
->Try
= Try
;
202 ThreadData
->Irql
= Irql
;
203 ThreadData
->RetExpected
= RetExpected
;
204 InitializeObjectAttributes(&Attributes
, NULL
, OBJ_KERNEL_HANDLE
, NULL
, NULL
);
205 Status
= PsCreateSystemThread(&ThreadData
->Handle
, GENERIC_ALL
, &Attributes
, NULL
, NULL
, AcquireMutexThread
, ThreadData
);
206 ok_eq_hex(Status
, STATUS_SUCCESS
);
207 Status
= ObReferenceObjectByHandle(ThreadData
->Handle
, SYNCHRONIZE
, PsThreadType
, KernelMode
, (PVOID
*)&ThreadData
->Thread
, NULL
);
208 ok_eq_hex(Status
, STATUS_SUCCESS
);
210 return KeWaitForSingleObject(&ThreadData
->OutEvent
, Executive
, KernelMode
, FALSE
, Timeout
);
216 PTHREAD_DATA ThreadData
)
218 NTSTATUS Status
= STATUS_SUCCESS
;
220 KeSetEvent(&ThreadData
->InEvent
, 0, TRUE
);
221 Status
= KeWaitForSingleObject(ThreadData
->Thread
, Executive
, KernelMode
, FALSE
, NULL
);
222 ok_eq_hex(Status
, STATUS_SUCCESS
);
224 ObDereferenceObject(ThreadData
->Thread
);
225 Status
= ZwClose(ThreadData
->Handle
);
226 ok_eq_hex(Status
, STATUS_SUCCESS
);
227 KeClearEvent(&ThreadData
->InEvent
);
228 KeClearEvent(&ThreadData
->OutEvent
);
233 TestGuardedMutexConcurrent(
234 PKGUARDED_MUTEX Mutex
)
237 THREAD_DATA ThreadData
;
238 THREAD_DATA ThreadData2
;
239 THREAD_DATA ThreadDataUnsafe
;
240 THREAD_DATA ThreadDataTry
;
241 PKTHREAD Thread
= KeGetCurrentThread();
242 LARGE_INTEGER Timeout
;
243 Timeout
.QuadPart
= -10 * 1000 * 10; /* 10 ms */
245 InitThreadData(&ThreadData
, Mutex
, KeAcquireGuardedMutex
, NULL
, KeReleaseGuardedMutex
);
246 InitThreadData(&ThreadData2
, Mutex
, KeAcquireGuardedMutex
, NULL
, KeReleaseGuardedMutex
);
247 InitThreadData(&ThreadDataUnsafe
, Mutex
, KeAcquireGuardedMutexUnsafe
, NULL
, KeReleaseGuardedMutexUnsafe
);
248 InitThreadData(&ThreadDataTry
, Mutex
, NULL
, KeTryToAcquireGuardedMutex
, KeReleaseGuardedMutex
);
250 /* have a thread acquire the mutex */
251 Status
= StartThread(&ThreadData
, NULL
, PASSIVE_LEVEL
, FALSE
, FALSE
);
252 ok_eq_hex(Status
, STATUS_SUCCESS
);
253 CheckMutex(Mutex
, 0L, ThreadData
.Thread
, 0LU, 0x5555, -1, 0, 0, FALSE
, PASSIVE_LEVEL
);
254 /* have a second thread try to acquire it -- should fail */
255 Status
= StartThread(&ThreadDataTry
, NULL
, PASSIVE_LEVEL
, TRUE
, FALSE
);
256 ok_eq_hex(Status
, STATUS_SUCCESS
);
257 CheckMutex(Mutex
, 0L, ThreadData
.Thread
, 0LU, 0x5555, -1, 0, 0, FALSE
, PASSIVE_LEVEL
);
258 FinishThread(&ThreadDataTry
);
260 /* have another thread acquire it -- should block */
261 Status
= StartThread(&ThreadData2
, &Timeout
, APC_LEVEL
, FALSE
, FALSE
);
262 ok_eq_hex(Status
, STATUS_TIMEOUT
);
263 CheckMutex(Mutex
, 4L, ThreadData
.Thread
, 1LU, 0x5555, -1, 0, 0, FALSE
, PASSIVE_LEVEL
);
265 /* finish the first thread -- now the second should become available */
266 FinishThread(&ThreadData
);
267 Status
= KeWaitForSingleObject(&ThreadData2
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
268 ok_eq_hex(Status
, STATUS_SUCCESS
);
269 CheckMutex(Mutex
, 0L, ThreadData2
.Thread
, 1LU, 0x5555, -1, 0, 0, FALSE
, PASSIVE_LEVEL
);
271 /* block two more threads */
272 Status
= StartThread(&ThreadDataUnsafe
, &Timeout
, APC_LEVEL
, FALSE
, FALSE
);
273 ok_eq_hex(Status
, STATUS_TIMEOUT
);
274 CheckMutex(Mutex
, 4L, ThreadData2
.Thread
, 2LU, 0x5555, -1, 0, 0, FALSE
, PASSIVE_LEVEL
);
276 Status
= StartThread(&ThreadData
, &Timeout
, PASSIVE_LEVEL
, FALSE
, FALSE
);
277 ok_eq_hex(Status
, STATUS_TIMEOUT
);
278 CheckMutex(Mutex
, 8L, ThreadData2
.Thread
, 3LU, 0x5555, -1, 0, 0, FALSE
, PASSIVE_LEVEL
);
281 FinishThread(&ThreadData2
);
282 Status
= KeWaitForSingleObject(&ThreadDataUnsafe
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
283 ok_eq_hex(Status
, STATUS_SUCCESS
);
284 CheckMutex(Mutex
, 4L, ThreadDataUnsafe
.Thread
, 3LU, 0x5555, -1, 0, 0, FALSE
, PASSIVE_LEVEL
);
287 FinishThread(&ThreadDataUnsafe
);
288 Status
= KeWaitForSingleObject(&ThreadData
.OutEvent
, Executive
, KernelMode
, FALSE
, NULL
);
289 ok_eq_hex(Status
, STATUS_SUCCESS
);
290 CheckMutex(Mutex
, 0L, ThreadData
.Thread
, 3LU, 0x5555, -1, 0, 0, FALSE
, PASSIVE_LEVEL
);
293 FinishThread(&ThreadData
);
295 CheckMutex(Mutex
, 1L, NULL
, 3LU, 0x5555, -1, 0, 0, FALSE
, PASSIVE_LEVEL
);
298 START_TEST(KeGuardedMutex
)
300 KGUARDED_MUTEX Mutex
;
302 PKTHREAD Thread
= KeGetCurrentThread();
305 SHORT KernelApcsDisabled
;
306 SHORT SpecialApcsDisabled
;
307 BOOLEAN AllApcsDisabled
;
310 { PASSIVE_LEVEL
, 0, 0, FALSE
},
311 { PASSIVE_LEVEL
, -1, 0, FALSE
},
312 { PASSIVE_LEVEL
, -3, 0, FALSE
},
313 { PASSIVE_LEVEL
, 0, -1, TRUE
},
314 { PASSIVE_LEVEL
, -1, -1, TRUE
},
315 { PASSIVE_LEVEL
, -3, -2, TRUE
},
317 { APC_LEVEL
, 0, 0, TRUE
},
318 { APC_LEVEL
, -1, 0, TRUE
},
319 { APC_LEVEL
, -3, 0, TRUE
},
320 { APC_LEVEL
, 0, -1, TRUE
},
321 { APC_LEVEL
, -1, -1, TRUE
},
322 { APC_LEVEL
, -3, -2, TRUE
},
324 { DISPATCH_LEVEL
, 0, 0, TRUE
},
325 { DISPATCH_LEVEL
, -1, 0, TRUE
},
326 { DISPATCH_LEVEL
, -3, 0, TRUE
},
327 { DISPATCH_LEVEL
, 0, -1, TRUE
},
328 { DISPATCH_LEVEL
, -1, -1, TRUE
},
329 { DISPATCH_LEVEL
, -3, -2, TRUE
},
331 { HIGH_LEVEL
, 0, 0, TRUE
},
332 { HIGH_LEVEL
, -1, 0, TRUE
},
333 { HIGH_LEVEL
, -3, 0, TRUE
},
334 { HIGH_LEVEL
, 0, -1, TRUE
},
335 { HIGH_LEVEL
, -1, -1, TRUE
},
336 { HIGH_LEVEL
, -3, -2, TRUE
},
340 for (i
= 0; i
< sizeof TestIterations
/ sizeof TestIterations
[0]; ++i
)
342 trace("Run %d\n", i
);
343 KeRaiseIrql(TestIterations
[i
].Irql
, &OldIrql
);
344 Thread
->KernelApcDisable
= TestIterations
[i
].KernelApcsDisabled
;
345 Thread
->SpecialApcDisable
= TestIterations
[i
].SpecialApcsDisabled
;
347 RtlFillMemory(&Mutex
, sizeof Mutex
, 0x55);
348 KeInitializeGuardedMutex(&Mutex
);
349 CheckMutex(&Mutex
, 1L, NULL
, 0LU, 0x5555, 0x5555, TestIterations
[i
].KernelApcsDisabled
, TestIterations
[i
].SpecialApcsDisabled
, TestIterations
[i
].AllApcsDisabled
, TestIterations
[i
].Irql
);
350 TestGuardedMutex(&Mutex
, TestIterations
[i
].KernelApcsDisabled
, TestIterations
[i
].SpecialApcsDisabled
, TestIterations
[i
].AllApcsDisabled
, TestIterations
[i
].Irql
);
352 Thread
->SpecialApcDisable
= 0;
353 Thread
->KernelApcDisable
= 0;
354 KeLowerIrql(OldIrql
);
357 trace("Concurrent test\n");
358 RtlFillMemory(&Mutex
, sizeof Mutex
, 0x55);
359 KeInitializeGuardedMutex(&Mutex
);
360 TestGuardedMutexConcurrent(&Mutex
);