From 60ddf0f09e327df0a492fe1f6b2cdbd6acc1d61e Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Thu, 2 May 2019 13:21:29 +0200 Subject: [PATCH] ntoskrnl.exe/tests: Add CancelIo tests. Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- dlls/ntoskrnl.exe/tests/driver.c | 36 ++++++++++++++ dlls/ntoskrnl.exe/tests/driver.h | 3 ++ dlls/ntoskrnl.exe/tests/ntoskrnl.c | 80 ++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+) diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c index c2ef8903065..6d14a22eaad 100644 --- a/dlls/ntoskrnl.exe/tests/driver.c +++ b/dlls/ntoskrnl.exe/tests/driver.c @@ -770,6 +770,15 @@ static void WINAPI cancel_irp(DEVICE_OBJECT *device, IRP *irp) cancel_cnt++; } +static void WINAPI cancel_ioctl_irp(DEVICE_OBJECT *device, IRP *irp) +{ + IoReleaseCancelSpinLock(irp->CancelIrql); + irp->IoStatus.Status = STATUS_CANCELLED; + irp->IoStatus.Information = 0; + cancel_cnt++; + IoCompleteRequest(irp, IO_NO_INCREMENT); +} + static NTSTATUS WINAPI cancel_test_completion(DEVICE_OBJECT *device, IRP *irp, void *context) { ok(cancel_cnt == 1, "cancel_cnt = %d\n", cancel_cnt); @@ -1505,6 +1514,22 @@ static NTSTATUS test_basic_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR * return STATUS_SUCCESS; } +static NTSTATUS get_cancel_count(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) +{ + ULONG length = stack->Parameters.DeviceIoControl.OutputBufferLength; + char *buffer = irp->AssociatedIrp.SystemBuffer; + + if (!buffer) + return STATUS_ACCESS_VIOLATION; + + if (length < sizeof(DWORD)) + return STATUS_BUFFER_TOO_SMALL; + + *(DWORD*)buffer = cancel_cnt; + *info = sizeof(DWORD); + return STATUS_SUCCESS; +} + static NTSTATUS test_load_driver_ioctl(IRP *irp, IO_STACK_LOCATION *stack, ULONG_PTR *info) { BOOL *load = irp->AssociatedIrp.SystemBuffer; @@ -1549,6 +1574,17 @@ static NTSTATUS WINAPI driver_IoControl(DEVICE_OBJECT *device, IRP *irp) case IOCTL_WINETEST_LOAD_DRIVER: status = test_load_driver_ioctl(irp, stack, &irp->IoStatus.Information); break; + case IOCTL_WINETEST_RESET_CANCEL: + cancel_cnt = 0; + status = STATUS_SUCCESS; + break; + case IOCTL_WINETEST_TEST_CANCEL: + IoSetCancelRoutine(irp, cancel_ioctl_irp); + IoMarkIrpPending(irp); + return STATUS_PENDING; + case IOCTL_WINETEST_GET_CANCEL_COUNT: + status = get_cancel_count(irp, stack, &irp->IoStatus.Information); + break; default: break; } diff --git a/dlls/ntoskrnl.exe/tests/driver.h b/dlls/ntoskrnl.exe/tests/driver.h index be4a9dc8372..1e7552996b7 100644 --- a/dlls/ntoskrnl.exe/tests/driver.h +++ b/dlls/ntoskrnl.exe/tests/driver.h @@ -25,6 +25,9 @@ #define IOCTL_WINETEST_BASIC_IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_WINETEST_MAIN_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS) #define IOCTL_WINETEST_LOAD_DRIVER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_RESET_CANCEL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x803, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_TEST_CANCEL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x804, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define IOCTL_WINETEST_GET_CANCEL_COUNT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x805, METHOD_BUFFERED, FILE_ANY_ACCESS) static const char teststr[] = "Wine is not an emulator"; diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index c17da7f1df3..d9eb28611dc 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -197,6 +197,85 @@ static void test_basic_ioctl(void) ok(!strcmp(buf, teststr), "got '%s'\n", buf); } +static void test_cancel_io(void) +{ + OVERLAPPED overlapped, overlapped2; + DWORD cancel_cnt; + HANDLE file; + BOOL res; + + overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + overlapped2.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL); + + file = CreateFileA("\\\\.\\WineTestDriver", 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + ok(file != INVALID_HANDLE_VALUE, "failed to open device: %u\n", GetLastError()); + + /* test cancelling all device requests */ + res = DeviceIoControl(file, IOCTL_WINETEST_RESET_CANCEL, NULL, 0, NULL, 0, NULL, &overlapped); + todo_wine + ok(res, "DeviceIoControl failed: %u\n", GetLastError()); + if (!res && GetLastError() == ERROR_IO_PENDING) WaitForSingleObject(overlapped.hEvent, INFINITE); + + res = DeviceIoControl(file, IOCTL_WINETEST_TEST_CANCEL, NULL, 0, NULL, 0, NULL, &overlapped); + ok(!res && GetLastError() == ERROR_IO_PENDING, "DeviceIoControl failed: %u\n", GetLastError()); + + res = DeviceIoControl(file, IOCTL_WINETEST_TEST_CANCEL, NULL, 0, NULL, 0, NULL, &overlapped2); + ok(!res && GetLastError() == ERROR_IO_PENDING, "DeviceIoControl failed: %u\n", GetLastError()); + + cancel_cnt = 0xdeadbeef; + res = DeviceIoControl(file, IOCTL_WINETEST_GET_CANCEL_COUNT, NULL, 0, &cancel_cnt, sizeof(cancel_cnt), NULL, &overlapped); + todo_wine + ok(res, "DeviceIoControl failed: %u\n", GetLastError()); + if (!res && GetLastError() == ERROR_IO_PENDING) WaitForSingleObject(overlapped.hEvent, INFINITE); + ok(cancel_cnt == 0, "cancel_cnt = %u\n", cancel_cnt); + + CancelIo(file); + + cancel_cnt = 0xdeadbeef; + res = DeviceIoControl(file, IOCTL_WINETEST_GET_CANCEL_COUNT, NULL, 0, &cancel_cnt, sizeof(cancel_cnt), NULL, &overlapped); + todo_wine + ok(res, "DeviceIoControl failed: %u\n", GetLastError()); + if (!res && GetLastError() == ERROR_IO_PENDING) WaitForSingleObject(overlapped.hEvent, INFINITE); + todo_wine + ok(cancel_cnt == 2, "cancel_cnt = %u\n", cancel_cnt); + + /* test cancelling selected overlapped event */ + res = DeviceIoControl(file, IOCTL_WINETEST_RESET_CANCEL, NULL, 0, NULL, 0, NULL, &overlapped); + todo_wine + ok(res, "DeviceIoControl failed: %u\n", GetLastError()); + if (!res && GetLastError() == ERROR_IO_PENDING) WaitForSingleObject(overlapped.hEvent, INFINITE); + + res = DeviceIoControl(file, IOCTL_WINETEST_TEST_CANCEL, NULL, 0, NULL, 0, NULL, &overlapped); + ok(!res && GetLastError() == ERROR_IO_PENDING, "DeviceIoControl failed: %u\n", GetLastError()); + + res = DeviceIoControl(file, IOCTL_WINETEST_TEST_CANCEL, NULL, 0, NULL, 0, NULL, &overlapped2); + ok(!res && GetLastError() == ERROR_IO_PENDING, "DeviceIoControl failed: %u\n", GetLastError()); + + CancelIoEx(file, &overlapped); + + cancel_cnt = 0xdeadbeef; + res = DeviceIoControl(file, IOCTL_WINETEST_GET_CANCEL_COUNT, NULL, 0, &cancel_cnt, sizeof(cancel_cnt), NULL, &overlapped); + todo_wine + ok(res, "DeviceIoControl failed: %u\n", GetLastError()); + if (!res && GetLastError() == ERROR_IO_PENDING) WaitForSingleObject(overlapped.hEvent, INFINITE); + todo_wine + ok(cancel_cnt == 1, "cancel_cnt = %u\n", cancel_cnt); + + CancelIoEx(file, &overlapped2); + + cancel_cnt = 0xdeadbeef; + res = DeviceIoControl(file, IOCTL_WINETEST_GET_CANCEL_COUNT, NULL, 0, &cancel_cnt, sizeof(cancel_cnt), NULL, &overlapped); + todo_wine + ok(res, "DeviceIoControl failed: %u\n", GetLastError()); + if (!res && GetLastError() == ERROR_IO_PENDING) WaitForSingleObject(overlapped.hEvent, INFINITE); + todo_wine + ok(cancel_cnt == 2, "cancel_cnt = %u\n", cancel_cnt); + + CloseHandle(overlapped.hEvent); + CloseHandle(overlapped2.hEvent); + CloseHandle(file); +} + static void test_load_driver(SC_HANDLE service) { SERVICE_STATUS status; @@ -268,6 +347,7 @@ START_TEST(ntoskrnl) test_basic_ioctl(); main_test(); + test_cancel_io(); test_load_driver(service2); unload_driver(service2);