Module: wine Branch: master Commit: 60ddf0f09e327df0a492fe1f6b2cdbd6acc1d61e URL: https://source.winehq.org/git/wine.git/?a=commit;h=60ddf0f09e327df0a492fe1f6...
Author: Jacek Caban jacek@codeweavers.com Date: Thu May 2 13:21:29 2019 +0200
ntoskrnl.exe/tests: Add CancelIo tests.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
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 c2ef890..6d14a22 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 be4a9dc..1e75529 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 c17da7f..d9eb286 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);