[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