Author: tfaber
Date: Mon Aug 22 10:02:12 2011
New Revision: 53367
URL:
http://svn.reactos.org/svn/reactos?rev=53367&view=rev
Log:
[KMTESTS/KE]
- Add concurrent testing to KeGuardedMutex test (part 2/2)
Modified:
branches/GSoC_2011/KMTestSuite/kmtests/ntos_ke/KeGuardedMutex.c
Modified: branches/GSoC_2011/KMTestSuite/kmtests/ntos_ke/KeGuardedMutex.c
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2011/KMTestSuite/kmtests/n…
==============================================================================
--- branches/GSoC_2011/KMTestSuite/kmtests/ntos_ke/KeGuardedMutex.c [iso-8859-1]
(original)
+++ branches/GSoC_2011/KMTestSuite/kmtests/ntos_ke/KeGuardedMutex.c [iso-8859-1] Mon Aug
22 10:02:12 2011
@@ -114,6 +114,185 @@
ok_eq_int(Thread->SpecialApcDisable, SpecialApcsDisabled);
Thread->SpecialApcDisable = SpecialApcsDisabled;
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)
@@ -174,4 +353,9 @@
Thread->KernelApcDisable = 0;
KeLowerIrql(OldIrql);
}
-}
+
+ trace("Concurrent test\n");
+ RtlFillMemory(&Mutex, sizeof Mutex, 0x55);
+ KeInitializeGuardedMutex(&Mutex);
+ TestGuardedMutexConcurrent(&Mutex);
+}