ReactOS 0.4.16-dev-251-ga17b6e9
ExFastMutex.c File Reference
#include <kmt_test.h>
#include <debug.h>
Include dependency graph for ExFastMutex.c:

Go to the source code of this file.

Classes

struct  THREAD_DATA
 

Macros

#define CheckMutex(Mutex, ExpectedCount, ExpectedOwner, ExpectedContention, ExpectedOldIrql, ExpectedIrql)
 

Typedefs

typedef VOID(FASTCALLPMUTEX_FUNCTION) (PFAST_MUTEX)
 
typedef BOOLEAN(FASTCALLPMUTEX_TRY_FUNCTION) (PFAST_MUTEX)
 
typedef struct THREAD_DATAPTHREAD_DATA
 

Functions

static VOID (FASTCALL *pExEnterCriticalRegionAndAcquireFastMutexUnsafe)(_Inout_ PFAST_MUTEX FastMutex)
 
static BOOLEAN (FASTCALL *pExiTryToAcquireFastMutex)(IN OUT PFAST_MUTEX FastMutex)
 
static VOID TestFastMutex (PFAST_MUTEX Mutex, KIRQL OriginalIrql)
 
static VOID NTAPI AcquireMutexThread (PVOID Parameter)
 
static VOID InitThreadData (PTHREAD_DATA ThreadData, PFAST_MUTEX Mutex, PMUTEX_FUNCTION Acquire, PMUTEX_TRY_FUNCTION TryAcquire, PMUTEX_FUNCTION Release)
 
static NTSTATUS StartThread (PTHREAD_DATA ThreadData, PLARGE_INTEGER Timeout, KIRQL Irql, BOOLEAN Try, BOOLEAN RetExpected)
 
static VOID FinishThread (PTHREAD_DATA ThreadData)
 
static VOID TestFastMutexConcurrent (PFAST_MUTEX Mutex)
 
 START_TEST (ExFastMutex)
 

Macro Definition Documentation

◆ CheckMutex

#define CheckMutex (   Mutex,
  ExpectedCount,
  ExpectedOwner,
  ExpectedContention,
  ExpectedOldIrql,
  ExpectedIrql 
)
Value:
do \
{ \
ok_eq_long((Mutex)->Count, ExpectedCount); \
ok_eq_pointer((Mutex)->Owner, ExpectedOwner); \
ok_eq_ulong((Mutex)->Contention, ExpectedContention); \
ok_eq_ulong((Mutex)->OldIrql, (ULONG)ExpectedOldIrql); \
ok_bool_false(KeAreApcsDisabled(), "KeAreApcsDisabled returned"); \
ok_irql(ExpectedIrql); \
} while (0)
Definition: Mutex.h:16
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ SaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ OwnerSize PSID Owner
Definition: rtlfuncs.h:1609
int Count
Definition: noreturn.cpp:7
BOOLEAN NTAPI KeAreApcsDisabled(VOID)
Definition: apc.c:958
uint32_t ULONG
Definition: typedefs.h:59
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778

Definition at line 31 of file ExFastMutex.c.

Typedef Documentation

◆ PMUTEX_FUNCTION

typedef VOID(FASTCALL * PMUTEX_FUNCTION) (PFAST_MUTEX)

Definition at line 137 of file ExFastMutex.c.

◆ PMUTEX_TRY_FUNCTION

typedef BOOLEAN(FASTCALL * PMUTEX_TRY_FUNCTION) (PFAST_MUTEX)

Definition at line 138 of file ExFastMutex.c.

◆ PTHREAD_DATA

Function Documentation

◆ AcquireMutexThread()

static VOID NTAPI AcquireMutexThread ( PVOID  Parameter)
static

Definition at line 158 of file ExFastMutex.c.

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}
unsigned char BOOLEAN
#define ok_eq_hex(value, expected)
Definition: apitest.h:77
#define ok_bool_false(value, desc)
Definition: apitest.h:79
#define ok_eq_bool(value, expected)
Definition: apitest.h:80
LONG NTSTATUS
Definition: precomp.h:26
_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
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 KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
Status
Definition: gdiplustypes.h:25
#define KernelMode
Definition: asm.h:34
#define STATUS_SUCCESS
Definition: shellext.h:65
@ Executive
Definition: ketypes.h:415
_Inout_opt_ PVOID Parameter
Definition: rtltypes.h:336

Referenced by StartThread().

◆ BOOLEAN()

static BOOLEAN ( FASTCALL pExiTryToAcquireFastMutex)
static

◆ FinishThread()

static VOID FinishThread ( PTHREAD_DATA  ThreadData)
static

Definition at line 229 of file ExFastMutex.c.

231{
233
234 KeSetEvent(&ThreadData->InEvent, 0, TRUE);
237
241 KeClearEvent(&ThreadData->InEvent);
242 KeClearEvent(&ThreadData->OutEvent);
243}
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
HANDLE Handle
Definition: drwtsn32.h:25
#define ObDereferenceObject
Definition: obfuncs.h:203

Referenced by TestFastMutexConcurrent().

◆ InitThreadData()

static VOID InitThreadData ( PTHREAD_DATA  ThreadData,
PFAST_MUTEX  Mutex,
PMUTEX_FUNCTION  Acquire,
PMUTEX_TRY_FUNCTION  TryAcquire,
PMUTEX_FUNCTION  Release 
)
static

Definition at line 188 of file ExFastMutex.c.

194{
195 ThreadData->Mutex = Mutex;
198 ThreadData->Acquire = Acquire;
199 ThreadData->TryAcquire = TryAcquire;
200 ThreadData->Release = Release;
201}
_In_ BOOLEAN Release
Definition: cdrom.h:920
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
@ NotificationEvent

Referenced by TestFastMutexConcurrent().

◆ START_TEST()

START_TEST ( ExFastMutex  )

Definition at line 311 of file ExFastMutex.c.

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 VOID TestFastMutex(PFAST_MUTEX Mutex, KIRQL OriginalIrql)
Definition: ExFastMutex.c:45
static VOID TestFastMutexConcurrent(PFAST_MUTEX Mutex)
Definition: ExFastMutex.c:247
#define skip(...)
Definition: atltest.h:64
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
#define HIGH_LEVEL
Definition: env_spec_w32.h:703
#define APC_LEVEL
Definition: env_spec_w32.h:695
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
PVOID KmtGetSystemRoutineAddress(IN PCWSTR RoutineName)
BOOLEAN KmtIsCheckedBuild
#define L(x)
Definition: ntvdm.h:50
#define memset(x, y, z)
Definition: compat.h:39
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
Definition: exfuncs.h:274
FAST_MUTEX
Definition: extypes.h:17

◆ StartThread()

static NTSTATUS StartThread ( PTHREAD_DATA  ThreadData,
PLARGE_INTEGER  Timeout,
KIRQL  Irql,
BOOLEAN  Try,
BOOLEAN  RetExpected 
)
static

Definition at line 205 of file ExFastMutex.c.

211{
214
215 ThreadData->Try = Try;
216 ThreadData->Irql = Irql;
217 ThreadData->RetExpected = RetExpected;
223
225}
static VOID NTAPI AcquireMutexThread(PVOID Parameter)
Definition: ExFastMutex.c:158
int Try(int arg)
Definition: ehframes.cpp:53
#define OBJ_KERNEL_HANDLE
Definition: winternl.h:231
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define SYNCHRONIZE
Definition: nt_native.h:61
#define GENERIC_ALL
Definition: nt_native.h:92
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
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
static ULONG Timeout
Definition: ping.c:61
_Must_inspect_result_ _In_ WDFDMAENABLER _In_ _In_opt_ PWDF_OBJECT_ATTRIBUTES Attributes

Referenced by DbgkpPostFakeThreadMessages(), and TestFastMutexConcurrent().

◆ TestFastMutex()

static VOID TestFastMutex ( PFAST_MUTEX  Mutex,
KIRQL  OriginalIrql 
)
static

Definition at line 45 of file ExFastMutex.c.

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}
#define ok_eq_long(value, expected)
Definition: apitest.h:62
#define ok_bool_true(value, desc)
Definition: apitest.h:78
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
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
VOID KmtSetIrql(IN KIRQL NewIrql)
VOID FASTCALL ExReleaseFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:86
VOID FASTCALL ExAcquireFastMutexUnsafe(IN OUT PFAST_MUTEX FastMutex)
Definition: fmutex.c:75

Referenced by START_TEST().

◆ TestFastMutexConcurrent()

static VOID TestFastMutexConcurrent ( PFAST_MUTEX  Mutex)
static

Definition at line 247 of file ExFastMutex.c.

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}
static NTSTATUS StartThread(PTHREAD_DATA ThreadData, PLARGE_INTEGER Timeout, KIRQL Irql, BOOLEAN Try, BOOLEAN RetExpected)
Definition: ExFastMutex.c:205
static VOID FinishThread(PTHREAD_DATA ThreadData)
Definition: ExFastMutex.c:229
static VOID InitThreadData(PTHREAD_DATA ThreadData, PFAST_MUTEX Mutex, PMUTEX_FUNCTION Acquire, PMUTEX_TRY_FUNCTION TryAcquire, PMUTEX_FUNCTION Release)
Definition: ExFastMutex.c:188
#define U(x)
Definition: wordpad.c:45
#define STATUS_TIMEOUT
Definition: d3dkmdt.h:49
#define MILLISECOND
Definition: kmt_test.h:276
PKTHREAD Thread
Definition: ExFastMutex.c:143
KEVENT OutEvent
Definition: ExFastMutex.c:152

Referenced by START_TEST().

◆ VOID()

static VOID ( FASTCALL pExEnterCriticalRegionAndAcquireFastMutexUnsafe)
static