mirror of
https://github.com/reactos/reactos.git
synced 2025-01-03 21:09:19 +00:00
[KMTESTS]
- KeEvent: a little concurrent testing (part 2/x) - ExFastMutex: concurrent testing (part 2/2) - Fix copypasta svn path=/branches/GSoC_2011/KMTestSuite/; revision=53091
This commit is contained in:
parent
f2cae03a42
commit
beead78f7b
3 changed files with 269 additions and 2 deletions
|
@ -41,7 +41,7 @@ typedef ULONG LOGICAL, *PLOGICAL;
|
|||
#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 */
|
||||
|
||||
|
|
|
@ -104,6 +104,180 @@ TestFastMutex(
|
|||
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 @@ START_TEST(ExFastMutex)
|
|||
TestFastMutex(&Mutex, HIGH_LEVEL);
|
||||
}
|
||||
KeLowerIrql(PASSIVE_LEVEL);
|
||||
|
||||
TestFastMutexConcurrent(&Mutex);
|
||||
}
|
||||
|
|
|
@ -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 @@ TestEventFunctional(
|
|||
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 @@ START_TEST(KeEvent)
|
|||
KeLowerIrql(Irql);
|
||||
}
|
||||
|
||||
TestEventThreads(&Event, NotificationEvent, PASSIVE_LEVEL);
|
||||
|
||||
ok_irql(PASSIVE_LEVEL);
|
||||
KmtSetIrql(PASSIVE_LEVEL);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue