[PATCH 5/5] ntoskrnl.exe/tests: Add tests for ERESOURCE functions.

Zebediah Figura z.figura12 at gmail.com
Tue Apr 9 21:27:44 CDT 2019


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/ntoskrnl.exe/tests/driver.c | 311 ++++++++++++++++++++++++++++++-
 include/ddk/wdm.h                |   2 +
 2 files changed, 312 insertions(+), 1 deletion(-)

diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c
index 81baffa7cc..0dec481be9 100644
--- a/dlls/ntoskrnl.exe/tests/driver.c
+++ b/dlls/ntoskrnl.exe/tests/driver.c
@@ -322,7 +322,14 @@ todo_wine
     ok(ret == STATUS_TIMEOUT, "got %#x\n", ret);
 }
 
-static void run_thread(PKSTART_ROUTINE proc, void *arg)
+static void sleep(void)
+{
+    LARGE_INTEGER timeout;
+    timeout.QuadPart = -2000;
+    KeDelayExecutionThread( KernelMode, FALSE, &timeout );
+}
+
+static HANDLE create_thread(PKSTART_ROUTINE proc, void *arg)
 {
     OBJECT_ATTRIBUTES attr = {0};
     HANDLE thread;
@@ -333,12 +340,25 @@ static void run_thread(PKSTART_ROUTINE proc, void *arg)
     ret = PsCreateSystemThread(&thread, THREAD_ALL_ACCESS, &attr, NULL, NULL, proc, arg);
     ok(!ret, "got %#x\n", ret);
 
+    return thread;
+}
+
+static void join_thread(HANDLE thread)
+{
+    NTSTATUS ret;
+
     ret = ZwWaitForSingleObject(thread, FALSE, NULL);
     ok(!ret, "got %#x\n", ret);
     ret = ZwClose(thread);
     ok(!ret, "got %#x\n", ret);
 }
 
+static void run_thread(PKSTART_ROUTINE proc, void *arg)
+{
+    HANDLE thread = create_thread(proc, arg);
+    join_thread(thread);
+}
+
 static KMUTEX test_mutex;
 
 static void WINAPI mutex_thread(void *arg)
@@ -853,6 +873,294 @@ static void test_ob_reference(const WCHAR *test_path)
     ok(!status, "ZwClose failed: %#x\n", status);
 }
 
+static void check_resource_(int line, ERESOURCE *resource, ULONG exclusive_waiters,
+        ULONG shared_waiters, BOOLEAN exclusive, ULONG shared_count)
+{
+    BOOLEAN ret;
+    ULONG count;
+
+    count = ExGetExclusiveWaiterCount(resource);
+    ok_(__FILE__, line, count == exclusive_waiters,
+            "expected %u exclusive waiters, got %u\n", exclusive_waiters, count);
+    count = ExGetSharedWaiterCount(resource);
+    ok_(__FILE__, line, count == shared_waiters,
+            "expected %u shared waiters, got %u\n", shared_waiters, count);
+    ret = ExIsResourceAcquiredExclusiveLite(resource);
+    ok_(__FILE__, line, ret == exclusive,
+            "expected exclusive %u, got %u\n", exclusive, ret);
+    count = ExIsResourceAcquiredSharedLite(resource);
+    ok_(__FILE__, line, count == shared_count,
+            "expected shared %u, got %u\n", shared_count, count);
+}
+#define check_resource(a,b,c,d,e) check_resource_(__LINE__,a,b,c,d,e)
+
+static KEVENT resource_shared_ready, resource_shared_done, resource_exclusive_ready, resource_exclusive_done;
+
+static void WINAPI resource_shared_thread(void *arg)
+{
+    ERESOURCE *resource = arg;
+    BOOLEAN ret;
+
+    check_resource(resource, 0, 0, FALSE, 0);
+
+    ret = ExAcquireResourceSharedLite(resource, TRUE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+
+    check_resource(resource, 0, 0, FALSE, 1);
+
+    KeSetEvent(&resource_shared_ready, IO_NO_INCREMENT, FALSE);
+    KeWaitForSingleObject(&resource_shared_done, Executive, KernelMode, FALSE, NULL);
+
+    ExReleaseResourceForThreadLite(resource, (ULONG_PTR)PsGetCurrentThread());
+
+    PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+static void WINAPI resource_exclusive_thread(void *arg)
+{
+    ERESOURCE *resource = arg;
+    BOOLEAN ret;
+
+    check_resource(resource, 0, 0, FALSE, 0);
+
+    ret = ExAcquireResourceExclusiveLite(resource, TRUE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+
+    check_resource(resource, 0, 0, TRUE, 1);
+
+    KeSetEvent(&resource_exclusive_ready, IO_NO_INCREMENT, FALSE);
+    KeWaitForSingleObject(&resource_exclusive_done, Executive, KernelMode, FALSE, NULL);
+
+    ExReleaseResourceForThreadLite(resource, (ULONG_PTR)PsGetCurrentThread());
+
+    PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+static void test_resource(void)
+{
+    ERESOURCE resource;
+    NTSTATUS status;
+    BOOLEAN ret;
+    HANDLE thread, thread2;
+
+    memset(&resource, 0xcc, sizeof(resource));
+
+    status = ExInitializeResourceLite(&resource);
+    ok(status == STATUS_SUCCESS, "got status %#x\n", status);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    KeEnterCriticalRegion();
+
+    ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, TRUE, 1);
+
+    ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, TRUE, 2);
+
+    ret = ExAcquireResourceSharedLite(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, TRUE, 3);
+
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    check_resource(&resource, 0, 0, TRUE, 2);
+
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    check_resource(&resource, 0, 0, TRUE, 1);
+
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    ret = ExAcquireResourceSharedLite(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 1);
+
+    ret = ExAcquireResourceSharedLite(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 2);
+
+    ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
+    ok(ret == FALSE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 2);
+
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    check_resource(&resource, 0, 0, FALSE, 1);
+
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    ret = ExAcquireSharedStarveExclusive(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 1);
+
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    ret = ExAcquireSharedWaitForExclusive(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 1);
+
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    /* Do not acquire the resource ourselves, but spawn a shared thread holding it. */
+
+    KeInitializeEvent(&resource_shared_ready, SynchronizationEvent, FALSE);
+    KeInitializeEvent(&resource_shared_done, SynchronizationEvent, FALSE);
+    thread = create_thread(resource_shared_thread, &resource);
+    KeWaitForSingleObject(&resource_shared_ready, Executive, KernelMode, FALSE, NULL);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
+    ok(ret == FALSE, "got ret %u\n", ret);
+
+    ret = ExAcquireResourceSharedLite(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 1);
+
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    ret = ExAcquireSharedStarveExclusive(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 1);
+
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    ret = ExAcquireSharedWaitForExclusive(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 1);
+
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    KeSetEvent(&resource_shared_done, IO_NO_INCREMENT, FALSE);
+    join_thread(thread);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    /* Acquire the resource as exclusive, and then spawn a shared thread. */
+
+    ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, TRUE, 1);
+
+    thread = create_thread(resource_shared_thread, &resource);
+    sleep();
+    check_resource(&resource, 0, 1, TRUE, 1);
+
+    ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 1, TRUE, 2);
+
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    KeWaitForSingleObject(&resource_shared_ready, Executive, KernelMode, FALSE, NULL);
+    KeSetEvent(&resource_shared_done, IO_NO_INCREMENT, FALSE);
+    join_thread(thread);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    /* Do not acquire the resource ourselves, but spawn an exclusive thread holding it. */
+
+    KeInitializeEvent(&resource_exclusive_ready, SynchronizationEvent, FALSE);
+    KeInitializeEvent(&resource_exclusive_done, SynchronizationEvent, FALSE);
+    thread = create_thread(resource_exclusive_thread, &resource);
+    KeWaitForSingleObject(&resource_exclusive_ready, Executive, KernelMode, FALSE, NULL);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
+    ok(ret == FALSE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    ret = ExAcquireResourceSharedLite(&resource, FALSE);
+    ok(ret == FALSE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    ret = ExAcquireSharedStarveExclusive(&resource, FALSE);
+    ok(ret == FALSE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    ret = ExAcquireSharedWaitForExclusive(&resource, FALSE);
+    ok(ret == FALSE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    KeSetEvent(&resource_exclusive_done, IO_NO_INCREMENT, FALSE);
+    join_thread(thread);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    /* Acquire the resource as shared, and then spawn an exclusive waiter. */
+
+    ret = ExAcquireResourceSharedLite(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 0, 0, FALSE, 1);
+
+    thread = create_thread(resource_exclusive_thread, &resource);
+    sleep();
+    check_resource(&resource, 1, 0, FALSE, 1);
+
+    ret = ExAcquireResourceSharedLite(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 1, 0, FALSE, 2);
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+
+    ret = ExAcquireSharedStarveExclusive(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 1, 0, FALSE, 2);
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+
+    ret = ExAcquireSharedWaitForExclusive(&resource, FALSE);
+    ok(ret == FALSE, "got ret %u\n", ret);
+    check_resource(&resource, 1, 0, FALSE, 1);
+
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+    KeWaitForSingleObject(&resource_exclusive_ready, Executive, KernelMode, FALSE, NULL);
+    KeSetEvent(&resource_exclusive_done, IO_NO_INCREMENT, FALSE);
+    join_thread(thread);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    /* Spawn a shared and then exclusive waiter. */
+
+    KeInitializeEvent(&resource_shared_ready, SynchronizationEvent, FALSE);
+    KeInitializeEvent(&resource_shared_done, SynchronizationEvent, FALSE);
+    thread = create_thread(resource_shared_thread, &resource);
+    KeWaitForSingleObject(&resource_shared_ready, Executive, KernelMode, FALSE, NULL);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    thread2 = create_thread(resource_exclusive_thread, &resource);
+    sleep();
+    check_resource(&resource, 1, 0, FALSE, 0);
+
+    ret = ExAcquireResourceExclusiveLite(&resource, FALSE);
+    ok(ret == FALSE, "got ret %u\n", ret);
+    check_resource(&resource, 1, 0, FALSE, 0);
+
+    ret = ExAcquireResourceSharedLite(&resource, FALSE);
+    ok(ret == FALSE, "got ret %u\n", ret);
+    check_resource(&resource, 1, 0, FALSE, 0);
+
+    ret = ExAcquireSharedStarveExclusive(&resource, FALSE);
+    ok(ret == TRUE, "got ret %u\n", ret);
+    check_resource(&resource, 1, 0, FALSE, 1);
+    ExReleaseResourceForThreadLite(&resource, (ULONG_PTR)PsGetCurrentThread());
+
+    ret = ExAcquireSharedWaitForExclusive(&resource, FALSE);
+    ok(ret == FALSE, "got ret %u\n", ret);
+    check_resource(&resource, 1, 0, FALSE, 0);
+
+    KeSetEvent(&resource_shared_done, IO_NO_INCREMENT, FALSE);
+    join_thread(thread);
+    KeWaitForSingleObject(&resource_exclusive_ready, Executive, KernelMode, FALSE, NULL);
+    KeSetEvent(&resource_exclusive_done, IO_NO_INCREMENT, FALSE);
+    join_thread(thread2);
+    check_resource(&resource, 0, 0, FALSE, 0);
+
+    KeLeaveCriticalRegion();
+
+    status = ExDeleteResourceLite(&resource);
+    ok(status == STATUS_SUCCESS, "got status %#x\n", status);
+}
+
 static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info)
 {
     ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength;
@@ -895,6 +1203,7 @@ static NTSTATUS main_test(DEVICE_OBJECT *device, IRP *irp, IO_STACK_LOCATION *st
     test_stack_callout();
     test_lookaside_list();
     test_ob_reference(test_input->path);
+    test_resource();
 
     /* print process report */
     if (winetest_debug)
diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
index dae83afb2e..0faf5ecd47 100644
--- a/include/ddk/wdm.h
+++ b/include/ddk/wdm.h
@@ -1580,6 +1580,7 @@ void      WINAPI KeAcquireSpinLockAtDpcLevel(KSPIN_LOCK*);
 BOOLEAN   WINAPI KeCancelTimer(KTIMER*);
 void      WINAPI KeClearEvent(PRKEVENT);
 NTSTATUS  WINAPI KeDelayExecutionThread(KPROCESSOR_MODE,BOOLEAN,LARGE_INTEGER*);
+void      WINAPI KeEnterCriticalRegion(void);
 PKTHREAD  WINAPI KeGetCurrentThread(void);
 void      WINAPI KeInitializeEvent(PRKEVENT,EVENT_TYPE,BOOLEAN);
 void      WINAPI KeInitializeMutex(PRKMUTEX,ULONG);
@@ -1587,6 +1588,7 @@ void      WINAPI KeInitializeSemaphore(PRKSEMAPHORE,LONG,LONG);
 void      WINAPI KeInitializeSpinLock(KSPIN_LOCK*);
 void      WINAPI KeInitializeTimerEx(PKTIMER,TIMER_TYPE);
 void      WINAPI KeInitializeTimer(KTIMER*);
+void      WINAPI KeLeaveCriticalRegion(void);
 void      WINAPI KeQuerySystemTime(LARGE_INTEGER*);
 void      WINAPI KeQueryTickCount(LARGE_INTEGER*);
 ULONG     WINAPI KeQueryTimeIncrement(void);
-- 
2.21.0




More information about the wine-devel mailing list