ntoskrnl.exe/tests: Add tests for ERESOURCE functions.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2019-04-09 23:41:11 -05:00 committed by Alexandre Julliard
parent ab22796ab0
commit cc2e8d7cda
2 changed files with 312 additions and 1 deletions

View file

@ -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 = -20 * 10000;
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)

View file

@ -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);