Author: tfaber Date: Fri Aug 5 21:12:11 2011 New Revision: 53091
URL: http://svn.reactos.org/svn/reactos?rev=53091&view=rev Log: [KMTESTS] - KeEvent: a little concurrent testing (part 2/x) - ExFastMutex: concurrent testing (part 2/2) - Fix copypasta
Modified: branches/GSoC_2011/KMTestSuite/kmtests/include/kmt_platform.h branches/GSoC_2011/KMTestSuite/kmtests/ntos_ex/ExFastMutex.c branches/GSoC_2011/KMTestSuite/kmtests/ntos_ke/KeEvent.c
Modified: branches/GSoC_2011/KMTestSuite/kmtests/include/kmt_platform.h URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2011/KMTestSuite/kmtests/in... ============================================================================== --- branches/GSoC_2011/KMTestSuite/kmtests/include/kmt_platform.h [iso-8859-1] (original) +++ branches/GSoC_2011/KMTestSuite/kmtests/include/kmt_platform.h [iso-8859-1] Fri Aug 5 21:12:11 2011 @@ -41,7 +41,7 @@ #define ExAllocatePoolWithTag(type, size, tag) HeapAlloc(GetProcessHeap(), 0, size) #define ExFreePool(p) HeapFree(GetProcessHeap(), 0, p) #define ExFreePoolWithTag(p, tag) HeapFree(GetProcessHeap(), 0, p) -#define RtlCopyMemoryNonTemporal(d, s, l) +#define RtlCopyMemoryNonTemporal RtlCopyMemory #define RtlPrefetchMemoryNonTemporal(s, l) #endif /* defined KMT_EMULATE_KERNEL */
Modified: branches/GSoC_2011/KMTestSuite/kmtests/ntos_ex/ExFastMutex.c URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2011/KMTestSuite/kmtests/nt... ============================================================================== --- branches/GSoC_2011/KMTestSuite/kmtests/ntos_ex/ExFastMutex.c [iso-8859-1] (original) +++ branches/GSoC_2011/KMTestSuite/kmtests/ntos_ex/ExFastMutex.c [iso-8859-1] Fri Aug 5 21:12:11 2011 @@ -104,6 +104,180 @@ KmtSetIrql(OriginalIrql); }
+typedef VOID (FASTCALL *PMUTEX_FUNCTION)(PFAST_MUTEX); +typedef BOOLEAN (FASTCALL *PMUTEX_TRY_FUNCTION)(PFAST_MUTEX); + +typedef struct +{ + HANDLE Handle; + PKTHREAD Thread; + KIRQL Irql; + PFAST_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; + + 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"); + Status = KeWaitForSingleObject(&ThreadData->InEvent, Executive, KernelMode, FALSE, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + if (!ThreadData->Try || Ret) + ThreadData->Release(ThreadData->Mutex); + + KeLowerIrql(Irql); +} + +static +VOID +InitThreadData( + PTHREAD_DATA ThreadData, + PFAST_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 +TestFastMutexConcurrent( + PFAST_MUTEX Mutex) +{ + NTSTATUS Status; + THREAD_DATA ThreadData; + THREAD_DATA ThreadData2; + THREAD_DATA ThreadDataUnsafe; + THREAD_DATA ThreadDataTry; + LARGE_INTEGER Timeout; + Timeout.QuadPart = -10 * 1000 * 10; /* 10 ms */ + + InitThreadData(&ThreadData, Mutex, ExAcquireFastMutex, NULL, ExReleaseFastMutex); + InitThreadData(&ThreadData2, Mutex, ExAcquireFastMutex, NULL, ExReleaseFastMutex); + InitThreadData(&ThreadDataUnsafe, Mutex, ExAcquireFastMutexUnsafe, NULL, ExReleaseFastMutexUnsafe); + InitThreadData(&ThreadDataTry, Mutex, NULL, ExTryToAcquireFastMutex, ExReleaseFastMutex); + + /* 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, PASSIVE_LEVEL, 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, PASSIVE_LEVEL, 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, -1L, ThreadData.Thread, 1LU, PASSIVE_LEVEL, 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, APC_LEVEL, PASSIVE_LEVEL); + + /* block two more threads */ + Status = StartThread(&ThreadDataUnsafe, &Timeout, APC_LEVEL, FALSE, FALSE); + ok_eq_hex(Status, STATUS_TIMEOUT); + CheckMutex(Mutex, -1L, ThreadData2.Thread, 2LU, APC_LEVEL, PASSIVE_LEVEL); + + Status = StartThread(&ThreadData, &Timeout, PASSIVE_LEVEL, FALSE, FALSE); + ok_eq_hex(Status, STATUS_TIMEOUT); + CheckMutex(Mutex, -2L, ThreadData2.Thread, 3LU, APC_LEVEL, PASSIVE_LEVEL); + + /* finish 1 */ + FinishThread(&ThreadData2); + Status = KeWaitForSingleObject(&ThreadDataUnsafe.OutEvent, Executive, KernelMode, FALSE, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + CheckMutex(Mutex, -1L, ThreadDataUnsafe.Thread, 3LU, APC_LEVEL, 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, PASSIVE_LEVEL, PASSIVE_LEVEL); + + /* finish 3 */ + FinishThread(&ThreadData); + + CheckMutex(Mutex, 1L, NULL, 3LU, PASSIVE_LEVEL, PASSIVE_LEVEL); +} + START_TEST(ExFastMutex) { FAST_MUTEX Mutex; @@ -124,4 +298,6 @@ TestFastMutex(&Mutex, HIGH_LEVEL); } KeLowerIrql(PASSIVE_LEVEL); -} + + TestFastMutexConcurrent(&Mutex); +}
Modified: branches/GSoC_2011/KMTestSuite/kmtests/ntos_ke/KeEvent.c URL: http://svn.reactos.org/svn/reactos/branches/GSoC_2011/KMTestSuite/kmtests/nt... ============================================================================== --- branches/GSoC_2011/KMTestSuite/kmtests/ntos_ke/KeEvent.c [iso-8859-1] (original) +++ branches/GSoC_2011/KMTestSuite/kmtests/ntos_ke/KeEvent.c [iso-8859-1] Fri Aug 5 21:12:11 2011 @@ -7,7 +7,7 @@
#include <kmt_test.h>
-/* TODO: thread testing, exports vs macros */ +/* TODO: more thread testing, exports vs macros */
#define CheckEvent(Event, ExpectedType, State, ExpectedWaitNext, Irql) do \ { \ @@ -96,6 +96,95 @@ KmtSetIrql(OriginalIrql); }
+typedef struct +{ + HANDLE Handle; + PKTHREAD Thread; + PKEVENT Event1; + PKEVENT Event2; + volatile BOOLEAN Signal; +} THREAD_DATA, *PTHREAD_DATA; + +static +VOID +NTAPI +WaitForEventThread( + IN OUT PVOID Context) +{ + NTSTATUS Status; + PTHREAD_DATA ThreadData = Context; + + ok_irql(PASSIVE_LEVEL); + ThreadData->Signal = TRUE; + Status = KeWaitForSingleObject(ThreadData->Event1, Executive, KernelMode, FALSE, NULL); + ok_irql(PASSIVE_LEVEL); + ok_eq_hex(Status, STATUS_SUCCESS); + ThreadData->Signal = TRUE; + Status = KeWaitForSingleObject(ThreadData->Event2, Executive, KernelMode, FALSE, NULL); + ok_irql(PASSIVE_LEVEL); + ok_eq_hex(Status, STATUS_SUCCESS); + ok_irql(PASSIVE_LEVEL); +} + +static +VOID +TestEventThreads( + IN PKEVENT Event, + IN EVENT_TYPE Type, + IN KIRQL OriginalIrql) +{ + NTSTATUS Status; + THREAD_DATA Threads[5]; + LARGE_INTEGER Timeout; + KPRIORITY Priority; + KEVENT WaitEvent; + KEVENT TerminateEvent; + int i; + Timeout.QuadPart = -1000 * 10; + + KeInitializeEvent(Event, Type, FALSE); + KeInitializeEvent(&WaitEvent, NotificationEvent, FALSE); + KeInitializeEvent(&TerminateEvent, SynchronizationEvent, FALSE); + + for (i = 0; i < sizeof Threads / sizeof Threads[0]; ++i) + { + Threads[i].Event1 = Event; + Threads[i].Event2 = &TerminateEvent; + Threads[i].Signal = FALSE; + Status = PsCreateSystemThread(&Threads[i].Handle, GENERIC_ALL, NULL, NULL, NULL, WaitForEventThread, &Threads[i]); + ok_eq_hex(Status, STATUS_SUCCESS); + Status = ObReferenceObjectByHandle(Threads[i].Handle, SYNCHRONIZE, PsThreadType, KernelMode, (PVOID *)&Threads[i].Thread, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + Priority = KeQueryPriorityThread(Threads[i].Thread); + ok_eq_long(Priority, 8L); + while (!Threads[i].Signal) + { + Status = KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, FALSE, &Timeout); + ok_eq_hex(Status, STATUS_TIMEOUT); + } + Threads[i].Signal = FALSE; + } + + for (i = 0; i < sizeof Threads / sizeof Threads[0]; ++i) + { + KeSetEvent(Event, 1, FALSE); + while (!Threads[i].Signal) + { + Status = KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, FALSE, &Timeout); + ok_eq_hex(Status, STATUS_TIMEOUT); + } + Priority = KeQueryPriorityThread(Threads[i].Thread); + ok_eq_long(Priority, 9L); + KeSetEvent(&TerminateEvent, 0, FALSE); + Status = KeWaitForSingleObject(Threads[i].Thread, Executive, KernelMode, FALSE, NULL); + ok_eq_hex(Status, STATUS_SUCCESS); + + ObDereferenceObject(Threads[i].Thread); + Status = ZwClose(Threads[i].Handle); + ok_eq_hex(Status, STATUS_SUCCESS); + } +} + START_TEST(KeEvent) { KEVENT Event; @@ -111,6 +200,8 @@ KeLowerIrql(Irql); }
+ TestEventThreads(&Event, NotificationEvent, PASSIVE_LEVEL); + ok_irql(PASSIVE_LEVEL); KmtSetIrql(PASSIVE_LEVEL); }