Author: tfaber
Date: Wed Aug 10 13:49:36 2011
New Revision: 53162
URL:
http://svn.reactos.org/svn/reactos?rev=53162&view=rev
Log:
[KMTESTS/KE]
- KeEvent: part 3/3
Modified:
branches/GSoC_2011/KMTestSuite/kmtests/include/kmt_platform.h
branches/GSoC_2011/KMTestSuite/kmtests/include/kmt_test.h
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/i…
==============================================================================
--- 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] Wed Aug 10
13:49:36 2011
@@ -49,5 +49,6 @@
#include <pseh/pseh2.h>
#include <limits.h>
+#include <stdarg.h>
#endif /* !defined _KMTEST_PLATFORM_H_ */
Modified: branches/GSoC_2011/KMTestSuite/kmtests/include/kmt_test.h
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2011/KMTestSuite/kmtests/i…
==============================================================================
--- branches/GSoC_2011/KMTestSuite/kmtests/include/kmt_test.h [iso-8859-1] (original)
+++ branches/GSoC_2011/KMTestSuite/kmtests/include/kmt_test.h [iso-8859-1] Wed Aug 10
13:49:36 2011
@@ -14,8 +14,6 @@
#define _KMTEST_TEST_H_
#include <kmt_platform.h>
-
-#include <stdarg.h>
typedef VOID KMT_TESTFUNC(VOID);
typedef KMT_TESTFUNC *PKMT_TESTFUNC;
@@ -101,6 +99,10 @@
#endif /* defined KMT_USER_MODE */
extern PKMT_RESULTBUFFER ResultBuffer;
+
+#define MICROSECOND 10
+#define MILLISECOND (1000 * MICROSECOND)
+#define SECOND (1000 * MILLISECOND)
#ifdef __GNUC__
#define KMT_FORMAT(type, fmt, first) __attribute__((__format__(type, fmt, first)))
Modified: branches/GSoC_2011/KMTestSuite/kmtests/ntos_ke/KeEvent.c
URL:
http://svn.reactos.org/svn/reactos/branches/GSoC_2011/KMTestSuite/kmtests/n…
==============================================================================
--- 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] Wed Aug 10
13:49:36 2011
@@ -7,18 +7,29 @@
#include <kmt_test.h>
-/* TODO: more thread testing, exports vs macros */
-
-#define CheckEvent(Event, ExpectedType, State, ExpectedWaitNext, Irql) do \
+/* TODO: why does GCC have 3 tests less than MSVC?! */
+
+#define CheckEvent(Event, ExpectedType, State, ExpectedWaitNext, \
+ Irql, ThreadList, ThreadCount) do \
{ \
+ INT TheIndex; \
+ PLIST_ENTRY TheEntry; \
+ PKTHREAD TheThread; \
ok_eq_uint((Event)->Header.Type, ExpectedType); \
ok_eq_uint((Event)->Header.Hand, sizeof *(Event) / sizeof(ULONG)); \
- ok_eq_long((Event)->Header.Lock & 0xFF00FF00L, 0x55005500L); \
+ ok_eq_hex((Event)->Header.Lock & 0xFF00FF00L, 0x55005500L); \
ok_eq_long((Event)->Header.SignalState, State); \
- ok_eq_pointer((Event)->Header.WaitListHead.Flink, \
- &(Event)->Header.WaitListHead); \
- ok_eq_pointer((Event)->Header.WaitListHead.Blink, \
- &(Event)->Header.WaitListHead); \
+ TheEntry = (Event)->Header.WaitListHead.Flink; \
+ for (TheIndex = 0; TheIndex < (ThreadCount); ++TheIndex) \
+ { \
+ TheThread = CONTAINING_RECORD(TheEntry, KTHREAD, \
+ WaitBlock[0].WaitListEntry); \
+ ok_eq_pointer(TheThread, (ThreadList)[TheIndex]); \
+ ok_eq_pointer(TheEntry->Flink->Blink, TheEntry); \
+ TheEntry = TheEntry->Flink; \
+ } \
+ ok_eq_pointer(TheEntry, &(Event)->Header.WaitListHead); \
+ ok_eq_pointer(TheEntry->Flink->Blink, TheEntry); \
ok_eq_long(KeReadStateEvent(Event), State); \
ok_eq_bool(Thread->WaitNext, ExpectedWaitNext); \
ok_irql(Irql); \
@@ -36,46 +47,49 @@
memset(Event, 0x55, sizeof *Event);
KeInitializeEvent(Event, Type, FALSE);
- CheckEvent(Event, Type, 0L, FALSE, OriginalIrql);
+ CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
memset(Event, 0x55, sizeof *Event);
KeInitializeEvent(Event, Type, TRUE);
- CheckEvent(Event, Type, 1L, FALSE, OriginalIrql);
+ CheckEvent(Event, Type, 1L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
Event->Header.SignalState = 0x12345678L;
- CheckEvent(Event, Type, 0x12345678L, FALSE, OriginalIrql);
+ CheckEvent(Event, Type, 0x12345678L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
State = KePulseEvent(Event, 0, FALSE);
- CheckEvent(Event, Type, 0L, FALSE, OriginalIrql);
+ CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
ok_eq_long(State, 0x12345678L);
Event->Header.SignalState = 0x12345678L;
KeClearEvent(Event);
- CheckEvent(Event, Type, 0L, FALSE, OriginalIrql);
+ CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
State = KeSetEvent(Event, 0, FALSE);
- CheckEvent(Event, Type, 1L, FALSE, OriginalIrql);
+ CheckEvent(Event, Type, 1L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
ok_eq_long(State, 0L);
State = KeResetEvent(Event);
- CheckEvent(Event, Type, 0L, FALSE, OriginalIrql);
+ CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
ok_eq_long(State, 1L);
Event->Header.SignalState = 0x23456789L;
State = KeSetEvent(Event, 0, FALSE);
- CheckEvent(Event, Type, 1L, FALSE, OriginalIrql);
+ CheckEvent(Event, Type, 1L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
ok_eq_long(State, 0x23456789L);
Event->Header.SignalState = 0x3456789AL;
State = KeResetEvent(Event);
- CheckEvent(Event, Type, 0L, FALSE, OriginalIrql);
+ CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, (PVOID *)NULL, 0);
ok_eq_long(State, 0x3456789AL);
- if (OriginalIrql <= DISPATCH_LEVEL || !KmtIsCheckedBuild)
+ /* Irql is raised to DISPATCH_LEVEL here, which kills checked build,
+ * a spinlock is acquired and never released, which kills MP build */
+ if ((OriginalIrql <= DISPATCH_LEVEL || !KmtIsCheckedBuild) &&
+ !KmtIsMultiProcessorBuild)
{
Event->Header.SignalState = 0x456789ABL;
State = KeSetEvent(Event, 0, TRUE);
- CheckEvent(Event, Type, 1L, TRUE, DISPATCH_LEVEL);
+ CheckEvent(Event, Type, 1L, TRUE, DISPATCH_LEVEL, (PVOID *)NULL, 0);
ok_eq_long(State, 0x456789ABL);
ok_eq_uint(Thread->WaitIrql, OriginalIrql);
/* repair the "damage" */
@@ -84,7 +98,7 @@
Event->Header.SignalState = 0x56789ABCL;
State = KePulseEvent(Event, 0, TRUE);
- CheckEvent(Event, Type, 0L, TRUE, DISPATCH_LEVEL);
+ CheckEvent(Event, Type, 0L, TRUE, DISPATCH_LEVEL, (PVOID *)NULL, 0);
ok_eq_long(State, 0x56789ABCL);
ok_eq_uint(Thread->WaitIrql, OriginalIrql);
/* repair the "damage" */
@@ -100,8 +114,7 @@
{
HANDLE Handle;
PKTHREAD Thread;
- PKEVENT Event1;
- PKEVENT Event2;
+ PKEVENT Event;
volatile BOOLEAN Signal;
} THREAD_DATA, *PTHREAD_DATA;
@@ -116,69 +129,92 @@
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);
+ Status = KeWaitForSingleObject(ThreadData->Event, Executive, KernelMode, FALSE,
NULL);
ok_eq_hex(Status, STATUS_SUCCESS);
ok_irql(PASSIVE_LEVEL);
}
+typedef LONG (NTAPI *PSET_EVENT_FUNCTION)(PRKEVENT, KPRIORITY, BOOLEAN);
+
static
VOID
-TestEventThreads(
+TestEventConcurrent(
IN PKEVENT Event,
IN EVENT_TYPE Type,
- IN KIRQL OriginalIrql)
+ IN KIRQL OriginalIrql,
+ PSET_EVENT_FUNCTION SetEvent,
+ KPRIORITY PriorityIncrement,
+ LONG ExpectedState,
+ BOOLEAN SatisfiesAll)
{
NTSTATUS Status;
THREAD_DATA Threads[5];
- LARGE_INTEGER Timeout;
+ const INT ThreadCount = sizeof Threads / sizeof Threads[0];
KPRIORITY Priority;
- KEVENT WaitEvent;
- KEVENT TerminateEvent;
- int i;
- Timeout.QuadPart = -1000 * 10;
+ LARGE_INTEGER LongTimeout, ShortTimeout;
+ INT i;
+ KWAIT_BLOCK WaitBlock[MAXIMUM_WAIT_OBJECTS];
+ PVOID ThreadObjects[MAXIMUM_WAIT_OBJECTS];
+ LONG State;
+ PKTHREAD Thread = KeGetCurrentThread();
+
+ LongTimeout.QuadPart = -100 * MILLISECOND;
+ ShortTimeout.QuadPart = -1 * MILLISECOND;
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;
+
+ for (i = 0; i < ThreadCount; ++i)
+ {
+ Threads[i].Event = Event;
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);
+ ThreadObjects[i] = Threads[i].Thread;
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);
+ Status = KeDelayExecutionThread(KernelMode, FALSE, &ShortTimeout);
+ ok_eq_hex(Status, STATUS_SUCCESS);
}
- Threads[i].Signal = FALSE;
- }
-
- for (i = 0; i < sizeof Threads / sizeof Threads[0]; ++i)
- {
- KeSetEvent(Event, 1, FALSE);
- while (!Threads[i].Signal)
+ CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, ThreadObjects, i + 1);
+ }
+
+ /* the threads shouldn't wake up on their own */
+ Status = KeDelayExecutionThread(KernelMode, FALSE, &ShortTimeout);
+ ok_eq_hex(Status, STATUS_SUCCESS);
+
+ for (i = 0; i < ThreadCount; ++i)
+ {
+ CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, ThreadObjects + i, ThreadCount -
i);
+ State = SetEvent(Event, PriorityIncrement + i, FALSE);
+
+ ok_eq_long(State, 0L);
+ CheckEvent(Event, Type, ExpectedState, FALSE, OriginalIrql, ThreadObjects + i +
1, SatisfiesAll ? 0 : ThreadCount - i - 1);
+ Status = KeWaitForMultipleObjects(ThreadCount, ThreadObjects, SatisfiesAll ?
WaitAll : WaitAny, Executive, KernelMode, FALSE, &LongTimeout, WaitBlock);
+ ok_eq_hex(Status, STATUS_WAIT_0 + i);
+ if (SatisfiesAll)
{
- Status = KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, FALSE,
&Timeout);
- ok_eq_hex(Status, STATUS_TIMEOUT);
+ for (; i < ThreadCount; ++i)
+ {
+ Priority = KeQueryPriorityThread(Threads[i].Thread);
+ ok_eq_long(Priority, max(min(8L + PriorityIncrement, 15L), 8L));
+ }
+ break;
}
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);
-
+ ok_eq_long(Priority, max(min(8L + PriorityIncrement + i, 15L), 8L));
+ /* replace the thread with the current thread - which will never signal */
+ if (!skip((Status & 0x3F) < ThreadCount, "Index out of
bounds"))
+ ThreadObjects[Status & 0x3F] = Thread;
+ Status = KeWaitForMultipleObjects(ThreadCount, ThreadObjects, WaitAny, Executive,
KernelMode, FALSE, &ShortTimeout, WaitBlock);
+ ok_eq_hex(Status, STATUS_TIMEOUT);
+ }
+
+ for (i = 0; i < ThreadCount; ++i)
+ {
ObDereferenceObject(Threads[i].Thread);
Status = ZwClose(Threads[i].Handle);
ok_eq_hex(Status, STATUS_SUCCESS);
@@ -190,17 +226,41 @@
KEVENT Event;
KIRQL Irql;
KIRQL Irqls[] = { PASSIVE_LEVEL, APC_LEVEL, DISPATCH_LEVEL, HIGH_LEVEL };
- int i;
+ INT i;
+ KPRIORITY PriorityIncrement;
for (i = 0; i < sizeof Irqls / sizeof Irqls[0]; ++i)
{
+ /* DRIVER_IRQL_NOT_LESS_OR_EQUAL (TODO: on MP only?) */
+ if (Irqls[i] > DISPATCH_LEVEL && KmtIsCheckedBuild)
+ return;
KeRaiseIrql(Irqls[i], &Irql);
TestEventFunctional(&Event, NotificationEvent, Irqls[i]);
TestEventFunctional(&Event, SynchronizationEvent, Irqls[i]);
KeLowerIrql(Irql);
}
- TestEventThreads(&Event, NotificationEvent, PASSIVE_LEVEL);
+ for (i = 0; i < sizeof Irqls / sizeof Irqls[0]; ++i)
+ {
+ /* creating threads above DISPATCH_LEVEL... nope */
+ if (Irqls[i] >= DISPATCH_LEVEL && KmtIsCheckedBuild)
+ continue;
+ KeRaiseIrql(Irqls[i], &Irql);
+ trace("IRQL: %u\n", Irqls[i]);
+ for (PriorityIncrement = -1; PriorityIncrement <= 8; ++PriorityIncrement)
+ {
+ trace("PriorityIncrement: %ld\n", PriorityIncrement);
+ trace("-> Checking KeSetEvent, NotificationEvent\n");
+ TestEventConcurrent(&Event, NotificationEvent, Irqls[i], KeSetEvent,
PriorityIncrement, 1, TRUE);
+ trace("-> Checking KeSetEvent, SynchronizationEvent\n");
+ TestEventConcurrent(&Event, SynchronizationEvent, Irqls[i], KeSetEvent,
PriorityIncrement, 0, FALSE);
+ trace("-> Checking KePulseEvent, NotificationEvent\n");
+ TestEventConcurrent(&Event, NotificationEvent, Irqls[i], KePulseEvent,
PriorityIncrement, 0, TRUE);
+ trace("-> Checking KePulseEvent, SynchronizationEvent\n");
+ TestEventConcurrent(&Event, SynchronizationEvent, Irqls[i], KePulseEvent,
PriorityIncrement, 0, FALSE);
+ }
+ KeLowerIrql(Irql);
+ }
ok_irql(PASSIVE_LEVEL);
KmtSetIrql(PASSIVE_LEVEL);