From d496caa76842bc43842bd77b77f56d3fc370c135 Mon Sep 17 00:00:00 2001 From: Thomas Faber Date: Mon, 22 Aug 2011 10:02:12 +0000 Subject: [PATCH] [KMTESTS/KE] - Add concurrent testing to KeGuardedMutex test (part 2/2) svn path=/branches/GSoC_2011/KMTestSuite/; revision=53367 --- kmtests/ntos_ke/KeGuardedMutex.c | 184 +++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/kmtests/ntos_ke/KeGuardedMutex.c b/kmtests/ntos_ke/KeGuardedMutex.c index ecbe50bebdc..6f4101e63b9 100644 --- a/kmtests/ntos_ke/KeGuardedMutex.c +++ b/kmtests/ntos_ke/KeGuardedMutex.c @@ -116,6 +116,185 @@ TestGuardedMutex( ok_irql(OriginalIrql); } +typedef VOID (FASTCALL *PMUTEX_FUNCTION)(PKGUARDED_MUTEX); +typedef BOOLEAN (FASTCALL *PMUTEX_TRY_FUNCTION)(PKGUARDED_MUTEX); + +typedef struct +{ + HANDLE Handle; + PKTHREAD Thread; + KIRQL Irql; + PKGUARDED_MUTEX Mutex; + PMUTEX_FUNCTION Acquire; + PMUTEX_TRY_FUNCTION TryAcquire; + PMUTEX_FUNCTION Release; + BOOLEAN Try; + BOOLEAN RetExpected; + KEVENT InEvent; + KEVENT OutEvent; +} THREAD_DATA, *PTHREAD_DATA; + +static +VOID +NTAPI +AcquireMutexThread( + PVOID Parameter) +{ + PTHREAD_DATA ThreadData = Parameter; + KIRQL Irql; + BOOLEAN Ret = FALSE; + NTSTATUS Status; + + DPRINT("Thread starting\n"); + KeRaiseIrql(ThreadData->Irql, &Irql); + + if (ThreadData->Try) + { + Ret = ThreadData->TryAcquire(ThreadData->Mutex); + ok_eq_bool(Ret, ThreadData->RetExpected); + } + else + ThreadData->Acquire(ThreadData->Mutex); + + ok_bool_false(KeSetEvent(&ThreadData->OutEvent, 0, TRUE), "KeSetEvent returned"); + DPRINT("Thread now waiting\n"); + Status = KeWaitForSingleObject(&ThreadData->InEvent, Executive, KernelMode, FALSE, NULL); + DPRINT("Thread done waiting\n"); + ok_eq_hex(Status, STATUS_SUCCESS); + + if (!ThreadData->Try || Ret) + ThreadData->Release(ThreadData->Mutex); + + KeLowerIrql(Irql); + DPRINT("Thread exiting\n"); +} + +static +VOID +InitThreadData( + PTHREAD_DATA ThreadData, + PKGUARDED_MUTEX Mutex, + PMUTEX_FUNCTION Acquire, + PMUTEX_TRY_FUNCTION TryAcquire, + PMUTEX_FUNCTION Release) +{ + ThreadData->Mutex = Mutex; + KeInitializeEvent(&ThreadData->InEvent, NotificationEvent, FALSE); + KeInitializeEvent(&ThreadData->OutEvent, NotificationEvent, FALSE); + ThreadData->Acquire = Acquire; + ThreadData->TryAcquire = TryAcquire; + ThreadData->Release = Release; +} + +static +NTSTATUS +StartThread( + PTHREAD_DATA ThreadData, + PLARGE_INTEGER Timeout, + KIRQL Irql, + BOOLEAN Try, + BOOLEAN RetExpected) +{ + NTSTATUS Status = STATUS_SUCCESS; + OBJECT_ATTRIBUTES Attributes; + + ThreadData->Try = Try; + ThreadData->Irql = Irql; + ThreadData->RetExpected = RetExpected; + InitializeObjectAttributes(&Attributes, NULL, OBJ_KERNEL_HANDLE, NULL, NULL); + Status = PsCreateSystemThread(&ThreadData->Handle, GENERIC_ALL, &Attributes, NULL, NULL, AcquireMutexThread, ThreadData); + ok_eq_hex(Status, STATUS_SUCCESS); + Status = ObReferenceObjectByHandle(ThreadData->Handle, SYNCHRONIZE, PsThreadType, KernelMode, (PVOID *)&ThreadData->Thread, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + return KeWaitForSingleObject(&ThreadData->OutEvent, Executive, KernelMode, FALSE, Timeout); +} + +static +VOID +FinishThread( + PTHREAD_DATA ThreadData) +{ + NTSTATUS Status = STATUS_SUCCESS; + + KeSetEvent(&ThreadData->InEvent, 0, TRUE); + Status = KeWaitForSingleObject(ThreadData->Thread, Executive, KernelMode, FALSE, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + ObDereferenceObject(ThreadData->Thread); + Status = ZwClose(ThreadData->Handle); + ok_eq_hex(Status, STATUS_SUCCESS); + KeClearEvent(&ThreadData->InEvent); + KeClearEvent(&ThreadData->OutEvent); +} + +static +VOID +TestGuardedMutexConcurrent( + PKGUARDED_MUTEX Mutex) +{ + NTSTATUS Status; + THREAD_DATA ThreadData; + THREAD_DATA ThreadData2; + THREAD_DATA ThreadDataUnsafe; + THREAD_DATA ThreadDataTry; + PKTHREAD Thread = KeGetCurrentThread(); + LARGE_INTEGER Timeout; + Timeout.QuadPart = -10 * 1000 * 10; /* 10 ms */ + + InitThreadData(&ThreadData, Mutex, KeAcquireGuardedMutex, NULL, KeReleaseGuardedMutex); + InitThreadData(&ThreadData2, Mutex, KeAcquireGuardedMutex, NULL, KeReleaseGuardedMutex); + InitThreadData(&ThreadDataUnsafe, Mutex, KeAcquireGuardedMutexUnsafe, NULL, KeReleaseGuardedMutexUnsafe); + InitThreadData(&ThreadDataTry, Mutex, NULL, KeTryToAcquireGuardedMutex, KeReleaseGuardedMutex); + + /* have a thread acquire the mutex */ + Status = StartThread(&ThreadData, NULL, PASSIVE_LEVEL, FALSE, FALSE); + ok_eq_hex(Status, STATUS_SUCCESS); + CheckMutex(Mutex, 0L, ThreadData.Thread, 0LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL); + /* have a second thread try to acquire it -- should fail */ + Status = StartThread(&ThreadDataTry, NULL, PASSIVE_LEVEL, TRUE, FALSE); + ok_eq_hex(Status, STATUS_SUCCESS); + CheckMutex(Mutex, 0L, ThreadData.Thread, 0LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL); + FinishThread(&ThreadDataTry); + + /* have another thread acquire it -- should block */ + Status = StartThread(&ThreadData2, &Timeout, APC_LEVEL, FALSE, FALSE); + ok_eq_hex(Status, STATUS_TIMEOUT); + CheckMutex(Mutex, 4L, ThreadData.Thread, 1LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL); + + /* finish the first thread -- now the second should become available */ + FinishThread(&ThreadData); + Status = KeWaitForSingleObject(&ThreadData2.OutEvent, Executive, KernelMode, FALSE, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + CheckMutex(Mutex, 0L, ThreadData2.Thread, 1LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL); + + /* block two more threads */ + Status = StartThread(&ThreadDataUnsafe, &Timeout, APC_LEVEL, FALSE, FALSE); + ok_eq_hex(Status, STATUS_TIMEOUT); + CheckMutex(Mutex, 4L, ThreadData2.Thread, 2LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL); + + Status = StartThread(&ThreadData, &Timeout, PASSIVE_LEVEL, FALSE, FALSE); + ok_eq_hex(Status, STATUS_TIMEOUT); + CheckMutex(Mutex, 8L, ThreadData2.Thread, 3LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL); + + /* finish 1 */ + FinishThread(&ThreadData2); + Status = KeWaitForSingleObject(&ThreadDataUnsafe.OutEvent, Executive, KernelMode, FALSE, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + CheckMutex(Mutex, 4L, ThreadDataUnsafe.Thread, 3LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL); + + /* finish 2 */ + FinishThread(&ThreadDataUnsafe); + Status = KeWaitForSingleObject(&ThreadData.OutEvent, Executive, KernelMode, FALSE, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + CheckMutex(Mutex, 0L, ThreadData.Thread, 3LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL); + + /* finish 3 */ + FinishThread(&ThreadData); + + CheckMutex(Mutex, 1L, NULL, 3LU, 0x5555, -1, 0, 0, FALSE, PASSIVE_LEVEL); +} + START_TEST(KeGuardedMutex) { KGUARDED_MUTEX Mutex; @@ -174,4 +353,9 @@ START_TEST(KeGuardedMutex) Thread->KernelApcDisable = 0; KeLowerIrql(OldIrql); } + + trace("Concurrent test\n"); + RtlFillMemory(&Mutex, sizeof Mutex, 0x55); + KeInitializeGuardedMutex(&Mutex); + TestGuardedMutexConcurrent(&Mutex); } -- 2.17.1