[USP10_WINETEST] Sync with Wine Staging 2.9. CORE-13362
[reactos.git] / rostests / kmtests / ntos_ke / KeEvent.c
index adcc85a..2cf1902 100644 (file)
@@ -7,8 +7,6 @@
 
 #include <kmt_test.h>
 
-/* TODO: why does GCC have 3 tests less than MSVC?! */
-
 #define CheckEvent(Event, ExpectedType, State, ExpectedWaitNext,                \
                             Irql, ThreadList, ThreadCount) do                   \
 {                                                                               \
@@ -23,7 +21,7 @@
     for (TheIndex = 0; TheIndex < (ThreadCount); ++TheIndex)                    \
     {                                                                           \
         TheThread = CONTAINING_RECORD(TheEntry, KTHREAD,                        \
-                                        WaitBlock[0].WaitListEntry);            \
+                                      WaitBlock[0].WaitListEntry);              \
         ok_eq_pointer(TheThread, (ThreadList)[TheIndex]);                       \
         ok_eq_pointer(TheEntry->Flink->Blink, TheEntry);                        \
         TheEntry = TheEntry->Flink;                                             \
@@ -153,10 +151,11 @@ TestEventConcurrent(
     KPRIORITY Priority;
     LARGE_INTEGER LongTimeout, ShortTimeout;
     INT i;
-    KWAIT_BLOCK WaitBlock[MAXIMUM_WAIT_OBJECTS];
-    PVOID ThreadObjects[MAXIMUM_WAIT_OBJECTS];
+    KWAIT_BLOCK WaitBlock[RTL_NUMBER_OF(Threads)];
+    PVOID ThreadObjects[RTL_NUMBER_OF(Threads)];
     LONG State;
     PKTHREAD Thread = KeGetCurrentThread();
+    OBJECT_ATTRIBUTES ObjectAttributes;
 
     LongTimeout.QuadPart = -100 * MILLISECOND;
     ShortTimeout.QuadPart = -1 * MILLISECOND;
@@ -167,7 +166,12 @@ TestEventConcurrent(
     {
         Threads[i].Event = Event;
         Threads[i].Signal = FALSE;
-        Status = PsCreateSystemThread(&Threads[i].Handle, GENERIC_ALL, NULL, NULL, NULL, WaitForEventThread, &Threads[i]);
+        InitializeObjectAttributes(&ObjectAttributes,
+                                   NULL,
+                                   OBJ_KERNEL_HANDLE,
+                                   NULL,
+                                   NULL);
+        Status = PsCreateSystemThread(&Threads[i].Handle, GENERIC_ALL, &ObjectAttributes, 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);
@@ -177,7 +181,10 @@ TestEventConcurrent(
         while (!Threads[i].Signal)
         {
             Status = KeDelayExecutionThread(KernelMode, FALSE, &ShortTimeout);
-            ok_eq_hex(Status, STATUS_SUCCESS);
+            if (Status != STATUS_SUCCESS)
+            {
+                ok_eq_hex(Status, STATUS_SUCCESS);
+            }
         }
         CheckEvent(Event, Type, 0L, FALSE, OriginalIrql, ThreadObjects, i + 1);
     }
@@ -221,15 +228,138 @@ TestEventConcurrent(
     }
 }
 
+#define NUM_SCHED_TESTS 1000
+
+typedef struct
+{
+    KEVENT Event;
+    KEVENT WaitEvent;
+    ULONG Counter;
+    KPRIORITY PriorityIncrement;
+    ULONG CounterValues[NUM_SCHED_TESTS];
+} COUNT_THREAD_DATA, *PCOUNT_THREAD_DATA;
+
+static
+VOID
+NTAPI
+CountThread(
+    IN OUT PVOID Context)
+{
+    PCOUNT_THREAD_DATA ThreadData = Context;
+    PKEVENT Event = &ThreadData->Event;
+    volatile ULONG *Counter = &ThreadData->Counter;
+    ULONG *CounterValue = ThreadData->CounterValues;
+    KPRIORITY Priority;
+
+    Priority = KeQueryPriorityThread(KeGetCurrentThread());
+    ok_eq_long(Priority, 8L);
+
+    while (CounterValue < &ThreadData->CounterValues[NUM_SCHED_TESTS])
+    {
+        KeSetEvent(&ThreadData->WaitEvent, IO_NO_INCREMENT, TRUE);
+        KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
+        *CounterValue++ = *Counter;
+    }
+
+    Priority = KeQueryPriorityThread(KeGetCurrentThread());
+    ok_eq_long(Priority, 8L + min(ThreadData->PriorityIncrement, 7));
+}
+
+static
+VOID
+NTAPI
+TestEventScheduling(
+    _In_ PVOID Context)
+{
+    PCOUNT_THREAD_DATA ThreadData;
+    PKTHREAD Thread;
+    NTSTATUS Status;
+    LONG PreviousState;
+    ULONG i;
+    volatile ULONG *Counter;
+    KPRIORITY PriorityIncrement;
+    KPRIORITY Priority;
+
+    UNREFERENCED_PARAMETER(Context);
+
+    ThreadData = ExAllocatePoolWithTag(PagedPool, sizeof(*ThreadData), 'CEmK');
+    if (skip(ThreadData != NULL, "Out of memory\n"))
+    {
+        return;
+    }
+    KeInitializeEvent(&ThreadData->Event, SynchronizationEvent, FALSE);
+    KeInitializeEvent(&ThreadData->WaitEvent, SynchronizationEvent, FALSE);
+    Counter = &ThreadData->Counter;
+
+    for (PriorityIncrement = 0; PriorityIncrement <= 8; PriorityIncrement++)
+    {
+        ThreadData->PriorityIncrement = PriorityIncrement;
+        ThreadData->Counter = 0;
+        RtlFillMemory(ThreadData->CounterValues,
+                      sizeof(ThreadData->CounterValues),
+                      0xFE);
+        Thread = KmtStartThread(CountThread, ThreadData);
+        Priority = KeQueryPriorityThread(KeGetCurrentThread());
+        ok(Priority == 8, "[%lu] Priority = %lu\n", PriorityIncrement, Priority);
+        for (i = 1; i <= NUM_SCHED_TESTS; i++)
+        {
+            Status = KeWaitForSingleObject(&ThreadData->WaitEvent, Executive, KernelMode, FALSE, NULL);
+            ok_eq_hex(Status, STATUS_SUCCESS);
+            PreviousState = KeSetEvent(&ThreadData->Event, PriorityIncrement, FALSE);
+            *Counter = i;
+            ok_eq_long(PreviousState, 0L);
+        }
+        Priority = KeQueryPriorityThread(KeGetCurrentThread());
+        ok(Priority == 8, "[%lu] Priority = %lu\n", PriorityIncrement, Priority);
+        KmtFinishThread(Thread, NULL);
+
+        if (PriorityIncrement == 0)
+        {
+            /* Both threads have the same priority, so either can win the race */
+            ok(ThreadData->CounterValues[0] == 0 || ThreadData->CounterValues[0] == 1,
+               "[%lu] Counter 0 = %lu\n",
+               PriorityIncrement, ThreadData->CounterValues[0]);
+        }
+        else
+        {
+            /* CountThread has the higher priority, it will always win */
+            ok(ThreadData->CounterValues[0] == 0,
+               "[%lu] Counter 0 = %lu\n",
+               PriorityIncrement, ThreadData->CounterValues[0]);
+        }
+        for (i = 1; i < NUM_SCHED_TESTS; i++)
+        {
+            if (PriorityIncrement == 0)
+            {
+                ok(ThreadData->CounterValues[i] == i ||
+                   ThreadData->CounterValues[i] == i + 1,
+                   "[%lu] Counter %lu = %lu, expected %lu or %lu\n",
+                   PriorityIncrement, i,
+                   ThreadData->CounterValues[i], i, i + 1);
+            }
+            else
+            {
+                ok(ThreadData->CounterValues[i] == ThreadData->CounterValues[i - 1] + 1,
+                   "[%lu] Counter %lu = %lu, expected %lu\n",
+                   PriorityIncrement, i,
+                   ThreadData->CounterValues[i], ThreadData->CounterValues[i - 1] + 1);
+            }
+        }
+    }
+
+    ExFreePoolWithTag(ThreadData, 'CEmK');
+}
+
 START_TEST(KeEvent)
 {
+    PKTHREAD Thread;
     KEVENT Event;
     KIRQL Irql;
     KIRQL Irqls[] = { PASSIVE_LEVEL, APC_LEVEL, DISPATCH_LEVEL };
-    INT i;
+    ULONG i;
     KPRIORITY PriorityIncrement;
 
-    for (i = 0; i < sizeof Irqls / sizeof Irqls[0]; ++i)
+    for (i = 0; i < RTL_NUMBER_OF(Irqls); ++i)
     {
         KeRaiseIrql(Irqls[i], &Irql);
         TestEventFunctional(&Event, NotificationEvent, Irqls[i]);
@@ -237,7 +367,7 @@ START_TEST(KeEvent)
         KeLowerIrql(Irql);
     }
 
-    for (i = 0; i < sizeof Irqls / sizeof Irqls[0]; ++i)
+    for (i = 0; i < RTL_NUMBER_OF(Irqls); ++i)
     {
         /* creating threads above DISPATCH_LEVEL... nope */
         if (Irqls[i] >= DISPATCH_LEVEL)
@@ -246,6 +376,8 @@ START_TEST(KeEvent)
         trace("IRQL: %u\n", Irqls[i]);
         for (PriorityIncrement = -1; PriorityIncrement <= 8; ++PriorityIncrement)
         {
+            if (PriorityIncrement < 0 && KmtIsCheckedBuild)
+                continue;
             trace("PriorityIncrement: %ld\n", PriorityIncrement);
             trace("-> Checking KeSetEvent, NotificationEvent\n");
             TestEventConcurrent(&Event, NotificationEvent, Irqls[i], KeSetEvent, PriorityIncrement, 1, TRUE);
@@ -261,4 +393,7 @@ START_TEST(KeEvent)
 
     ok_irql(PASSIVE_LEVEL);
     KmtSetIrql(PASSIVE_LEVEL);
+
+    Thread = KmtStartThread(TestEventScheduling, NULL);
+    KmtFinishThread(Thread, NULL);
 }