ReactOS 0.4.15-dev-7994-gb388cb6
ExFastMutex.c
Go to the documentation of this file.
1/*
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>
6 */
7
8#include <kmt_test.h>
9
10//#define NDEBUG
11#include <debug.h>
12
13static
16*pExEnterCriticalRegionAndAcquireFastMutexUnsafe)(
17 _Inout_ PFAST_MUTEX FastMutex
18);
19
20static
21VOID
23*pExReleaseFastMutexUnsafeAndLeaveCriticalRegion)(
24 _Inout_ PFAST_MUTEX FastMutex
25);
26
27static VOID (FASTCALL *pExiAcquireFastMutex)(IN OUT PFAST_MUTEX FastMutex);
28static VOID (FASTCALL *pExiReleaseFastMutex)(IN OUT PFAST_MUTEX FastMutex);
29static BOOLEAN (FASTCALL *pExiTryToAcquireFastMutex)(IN OUT PFAST_MUTEX FastMutex);
30
31#define CheckMutex(Mutex, ExpectedCount, ExpectedOwner, \
32 ExpectedContention, ExpectedOldIrql, \
33 ExpectedIrql) do \
34{ \
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); \
41} while (0)
42
43static
44VOID
47 KIRQL OriginalIrql)
48{
50
51 ok_irql(OriginalIrql);
52
53 /* acquire/release normally */
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);
59 CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql);
60
61 /* ntoskrnl's fastcall version */
62 if (!skip(pExiAcquireFastMutex &&
63 pExiReleaseFastMutex &&
64 pExiTryToAcquireFastMutex, "No fastcall fast mutex functions\n"))
65 {
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);
72 }
73
74 /* try to acquire */
75 ok_bool_true(ExTryToAcquireFastMutex(Mutex), "ExTryToAcquireFastMutex returned");
76 CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL);
78 CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql);
79
80 /* shortcut functions with critical region */
81 if (!skip(pExEnterCriticalRegionAndAcquireFastMutexUnsafe &&
82 pExReleaseFastMutexUnsafeAndLeaveCriticalRegion,
83 "Shortcut functions not available"))
84 {
85 pExEnterCriticalRegionAndAcquireFastMutexUnsafe(Mutex);
86 ok_bool_true(KeAreApcsDisabled(), "KeAreApcsDisabled returned");
87 pExReleaseFastMutexUnsafeAndLeaveCriticalRegion(Mutex);
88 }
89
90 /* acquire/release unsafe */
91 if (!KmtIsCheckedBuild || OriginalIrql == APC_LEVEL)
92 {
94 CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, OriginalIrql);
96 CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql);
97
98 /* mismatched acquire/release */
100 CheckMutex(Mutex, 0L, Thread, 0LU, OriginalIrql, APC_LEVEL);
102 CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, APC_LEVEL);
103 KmtSetIrql(OriginalIrql);
104 CheckMutex(Mutex, 1L, NULL, 0LU, OriginalIrql, OriginalIrql);
105
106 Mutex->OldIrql = 0x55555555LU;
108 CheckMutex(Mutex, 0L, Thread, 0LU, 0x55555555LU, OriginalIrql);
109 Mutex->OldIrql = PASSIVE_LEVEL;
112 KmtSetIrql(OriginalIrql);
113 CheckMutex(Mutex, 1L, NULL, 0LU, PASSIVE_LEVEL, OriginalIrql);
114 }
115
117 {
118 /* release without acquire */
120 CheckMutex(Mutex, 2L, NULL, 0LU, PASSIVE_LEVEL, OriginalIrql);
121 --Mutex->Count;
122 Mutex->OldIrql = OriginalIrql;
124 CheckMutex(Mutex, 2L, NULL, 0LU, OriginalIrql, OriginalIrql);
126 CheckMutex(Mutex, 3L, NULL, 0LU, OriginalIrql, OriginalIrql);
127 Mutex->Count -= 2;
128 }
129
130 /* make sure we survive this in case of error */
131 ok_eq_long(Mutex->Count, 1L);
132 Mutex->Count = 1;
133 ok_irql(OriginalIrql);
134 KmtSetIrql(OriginalIrql);
135}
136
139
140typedef struct
141{
154
155static
156VOID
157NTAPI
160{
162 KIRQL Irql;
163 BOOLEAN Ret = FALSE;
165
166 KeRaiseIrql(ThreadData->Irql, &Irql);
167
168 if (ThreadData->Try)
169 {
170 Ret = ThreadData->TryAcquire(ThreadData->Mutex);
171 ok_eq_bool(Ret, ThreadData->RetExpected);
172 }
173 else
174 ThreadData->Acquire(ThreadData->Mutex);
175
176 ok_bool_false(KeSetEvent(&ThreadData->OutEvent, 0, TRUE), "KeSetEvent returned");
179
180 if (!ThreadData->Try || Ret)
181 ThreadData->Release(ThreadData->Mutex);
182
184}
185
186static
187VOID
191 PMUTEX_FUNCTION Acquire,
192 PMUTEX_TRY_FUNCTION TryAcquire,
194{
195 ThreadData->Mutex = Mutex;
198 ThreadData->Acquire = Acquire;
199 ThreadData->TryAcquire = TryAcquire;
200 ThreadData->Release = Release;
201}
202
203static
208 KIRQL Irql,
209 BOOLEAN Try,
210 BOOLEAN RetExpected)
211{
214
215 ThreadData->Try = Try;
216 ThreadData->Irql = Irql;
217 ThreadData->RetExpected = RetExpected;
223
225}
226
227static
228VOID
231{
233
234 KeSetEvent(&ThreadData->InEvent, 0, TRUE);
237
241 KeClearEvent(&ThreadData->InEvent);
242 KeClearEvent(&ThreadData->OutEvent);
243}
244
245static
246VOID
249{
252 THREAD_DATA ThreadData2;
253 THREAD_DATA ThreadDataUnsafe;
254 THREAD_DATA ThreadDataTry;
256 Timeout.QuadPart = -50 * MILLISECOND;
257
262
263 /* have a thread acquire the mutex */
267 /* have a second thread try to acquire it -- should fail */
268 Status = StartThread(&ThreadDataTry, NULL, PASSIVE_LEVEL, TRUE, FALSE);
271 FinishThread(&ThreadDataTry);
272
273 /* have another thread acquire it -- should block */
274 Status = StartThread(&ThreadData2, &Timeout, APC_LEVEL, FALSE, FALSE);
277
278 /* finish the first thread -- now the second should become available */
282 CheckMutex(Mutex, 0L, ThreadData2.Thread, 1LU, APC_LEVEL, PASSIVE_LEVEL);
283
284 /* block two more threads */
285 Status = StartThread(&ThreadDataUnsafe, &Timeout, APC_LEVEL, FALSE, FALSE);
287 CheckMutex(Mutex, -1L, ThreadData2.Thread, 2LU, APC_LEVEL, PASSIVE_LEVEL);
288
291 CheckMutex(Mutex, -2L, ThreadData2.Thread, 3LU, APC_LEVEL, PASSIVE_LEVEL);
292
293 /* finish 1 */
294 FinishThread(&ThreadData2);
297 CheckMutex(Mutex, -1L, ThreadDataUnsafe.Thread, 3LU, APC_LEVEL, PASSIVE_LEVEL);
298
299 /* finish 2 */
300 FinishThread(&ThreadDataUnsafe);
304
305 /* finish 3 */
307
309}
310
311START_TEST(ExFastMutex)
312{
313#if defined(_M_AMD64)
314 if (TRUE)
315 {
316 skip(FALSE, "ROSTESTS-367: Skipping kmtest:ExFastMutex because it hangs on Windows Server 2003 x64-Testbot.\n");
317 return;
318 }
319#endif
320
322 KIRQL Irql;
323
324 pExEnterCriticalRegionAndAcquireFastMutexUnsafe = KmtGetSystemRoutineAddress(L"ExEnterCriticalRegionAndAcquireFastMutexUnsafe");
325 pExReleaseFastMutexUnsafeAndLeaveCriticalRegion = KmtGetSystemRoutineAddress(L"ExReleaseFastMutexUnsafeAndLeaveCriticalRegion");
326
327 pExiAcquireFastMutex = KmtGetSystemRoutineAddress(L"ExiAcquireFastMutex");
328 pExiReleaseFastMutex = KmtGetSystemRoutineAddress(L"ExiReleaseFastMutex");
329 pExiTryToAcquireFastMutex = KmtGetSystemRoutineAddress(L"ExiTryToAcquireFastMutex");
330
331 memset(&Mutex, 0x55, sizeof Mutex);
333 CheckMutex(&Mutex, 1L, NULL, 0LU, 0x55555555LU, PASSIVE_LEVEL);
334
339 {
344 }
346
348}
#define CheckMutex(Mutex, ExpectedCount, ExpectedOwner, ExpectedContention, ExpectedOldIrql, ExpectedIrql)
Definition: ExFastMutex.c:31
static NTSTATUS StartThread(PTHREAD_DATA ThreadData, PLARGE_INTEGER Timeout, KIRQL Irql, BOOLEAN Try, BOOLEAN RetExpected)
Definition: ExFastMutex.c:205
static VOID NTAPI AcquireMutexThread(PVOID Parameter)
Definition: ExFastMutex.c:158
static VOID FinishThread(PTHREAD_DATA ThreadData)
Definition: ExFastMutex.c:229
BOOLEAN(FASTCALL * PMUTEX_TRY_FUNCTION)(PFAST_MUTEX)
Definition: ExFastMutex.c:138
static VOID TestFastMutex(PFAST_MUTEX Mutex, KIRQL OriginalIrql)
Definition: ExFastMutex.c:45
VOID(FASTCALL * PMUTEX_FUNCTION)(PFAST_MUTEX)
Definition: ExFastMutex.c:137
static VOID TestFastMutexConcurrent(PFAST_MUTEX Mutex)
Definition: ExFastMutex.c:247
struct THREAD_DATA * PTHREAD_DATA
static VOID InitThreadData(PTHREAD_DATA ThreadData, PFAST_MUTEX Mutex, PMUTEX_FUNCTION Acquire, PMUTEX_TRY_FUNCTION TryAcquire, PMUTEX_FUNCTION Release)
Definition: ExFastMutex.c:188
unsigned char BOOLEAN
#define VOID
Definition: acefi.h:82
#define ok_eq_hex(value, expected)
Definition: apitest.h:77
#define ok_eq_long(value, expected)
Definition: apitest.h:62
#define ok_bool_false(value, desc)
Definition: apitest.h:79
#define ok_bool_true(value, desc)
Definition: apitest.h:78
#define ok_eq_bool(value, expected)
Definition: apitest.h:80
#define skip(...)
Definition: atltest.h:64
#define START_TEST(x)
Definition: atltest.h:75
LONG NTSTATUS
Definition: precomp.h:26
#define U(x)
Definition: wordpad.c:45
_In_ BOOLEAN Release
Definition: cdrom.h:920
Definition: Mutex.h:16
_Out_ PKIRQL Irql
Definition: csq.h:179
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
int Try(int arg)
Definition: ehframes.cpp:53
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
#define HIGH_LEVEL
Definition: env_spec_w32.h:703
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
Status
Definition: gdiplustypes.h:25
VOID FASTCALL ExAcquireFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:23
VOID FASTCALL ExReleaseFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:31
BOOLEAN FASTCALL ExTryToAcquireFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:39
#define KeGetCurrentThread
Definition: hal.h:55
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define MILLISECOND
Definition: kmt_test.h:276
PVOID KmtGetSystemRoutineAddress(IN PCWSTR RoutineName)
VOID KmtSetIrql(IN KIRQL NewIrql)
BOOLEAN KmtIsCheckedBuild
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define _Inout_
Definition: ms_sal.h:378
#define KernelMode
Definition: asm.h:34
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
#define SYNCHRONIZE
Definition: nt_native.h:61
#define FASTCALL
Definition: nt_native.h:50
#define GENERIC_ALL
Definition: nt_native.h:92
@ NotificationEvent
VOID FASTCALL ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:86
VOID FASTCALL ExAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:75
BOOLEAN NTAPI KeAreApcsDisabled(VOID)
Definition: apc.c:958
POBJECT_TYPE PsThreadType
Definition: thread.c:20
NTSTATUS NTAPI PsCreateSystemThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, IN PCLIENT_ID ClientId, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext)
Definition: thread.c:602
#define STATUS_TIMEOUT
Definition: ntstatus.h:81
#define L(x)
Definition: ntvdm.h:50
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
#define BOOLEAN
Definition: pedump.c:73
static ULONG Timeout
Definition: ping.c:61
#define memset(x, y, z)
Definition: compat.h:39
#define STATUS_SUCCESS
Definition: shellext.h:65
PKTHREAD Thread
Definition: ExFastMutex.c:143
PMUTEX_TRY_FUNCTION TryAcquire
Definition: ExFastMutex.c:147
PMUTEX_FUNCTION Acquire
Definition: ExFastMutex.c:146
BOOLEAN Try
Definition: ExFastMutex.c:149
BOOLEAN RetExpected
Definition: ExFastMutex.c:150
KEVENT InEvent
Definition: ExFastMutex.c:151
PMUTEX_FUNCTION Release
Definition: ExFastMutex.c:148
PFAST_MUTEX Mutex
Definition: ExFastMutex.c:145
KEVENT OutEvent
Definition: ExFastMutex.c:152
HANDLE Handle
Definition: ExFastMutex.c:142
HANDLE Handle
Definition: drwtsn32.h:25
#define NTAPI
Definition: typedefs.h:36
#define IN
Definition: typedefs.h:39
#define OUT
Definition: typedefs.h:40
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
Definition: exfuncs.h:274
* PFAST_MUTEX
Definition: extypes.h:17
FAST_MUTEX
Definition: extypes.h:17
@ Executive
Definition: ketypes.h:415
#define ObDereferenceObject
Definition: obfuncs.h:203
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:323