Module: wine Branch: master Commit: a55a287cab25b85c2788e9a07e09057f76e76926 URL: https://source.winehq.org/git/wine.git/?a=commit;h=a55a287cab25b85c2788e9a07...
Author: Jacek Caban jacek@codeweavers.com Date: Thu May 23 19:36:27 2019 +0200
server: Always block overlapped device requests until driver dispatches them.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/ntdll/file.c | 2 +- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 18 ------------------ server/async.c | 21 +++++++++++++++++++++ server/device.c | 9 ++++++--- server/file.h | 1 + 5 files changed, 29 insertions(+), 22 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 1f93c52..1cbaa1b 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -427,7 +427,7 @@ static async_data_t server_async( HANDLE handle, struct async_fileio *user, HAND
static NTSTATUS wait_async( HANDLE handle, BOOL alertable, IO_STATUS_BLOCK *io ) { - NtWaitForSingleObject( handle, alertable, NULL ); + if (NtWaitForSingleObject( handle, alertable, NULL )) return STATUS_PENDING; return io->u.Status; }
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index d47943a..49490bb 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -216,9 +216,7 @@ static void test_overlapped(void)
/* 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()); @@ -228,9 +226,7 @@ static void test_overlapped(void)
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); @@ -238,18 +234,13 @@ static void test_overlapped(void) 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 */ if (pCancelIoEx) { 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()); @@ -261,9 +252,7 @@ static void test_overlapped(void)
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);
@@ -271,9 +260,7 @@ static void test_overlapped(void)
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); } @@ -284,9 +271,7 @@ static void test_overlapped(void) ok(!res && GetLastError() == WAIT_TIMEOUT, "GetQueuedCompletionStatus returned %x(%u)\n", res, GetLastError());
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 = GetQueuedCompletionStatus(port, &size, &key, &o, 0); ok(res, "GetQueuedCompletionStatus failed: %u\n", GetLastError()); ok(o == &overlapped, "o != overlapped\n"); @@ -297,11 +282,8 @@ static void test_overlapped(void) ok(res, "SetFileCompletionNotificationModes failed: %u\n", GetLastError());
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 = GetQueuedCompletionStatus(port, &size, &key, &o, 0); - todo_wine ok(!res && GetLastError() == WAIT_TIMEOUT, "GetQueuedCompletionStatus returned %x(%u)\n", res, GetLastError()); }
diff --git a/server/async.c b/server/async.c index c0b84c2..94cac47 100644 --- a/server/async.c +++ b/server/async.c @@ -121,6 +121,8 @@ static void async_satisfied( struct object *obj, struct wait_queue_entry *entry close_handle( async->thread->process, async->wait_handle ); async->wait_handle = 0; } + + if (async->status == STATUS_PENDING) make_wait_abandoned( entry ); }
static void async_destroy( struct object *obj ) @@ -261,6 +263,19 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da return async; }
+void set_async_pending( struct async *async, int signal ) +{ + if (async->status == STATUS_PENDING) + { + async->pending = 1; + if (signal && !async->signaled) + { + async->signaled = 1; + wake_up( &async->obj, 0 ); + } + } +} + /* create an async associated with iosb for async-based requests * returned async must be passed to async_handoff */ struct async *create_request_async( struct fd *fd, unsigned int comp_flags, const async_data_t *data ) @@ -292,6 +307,12 @@ obj_handle_t async_handoff( struct async *async, int success, data_size_t *resul { if (!success) { + if (get_error() == STATUS_PENDING) + { + /* we don't know the result yet, so client needs to wait */ + async->direct_result = 0; + return async->wait_handle; + } close_handle( async->thread->process, async->wait_handle ); async->wait_handle = 0; return 0; diff --git a/server/device.c b/server/device.c index 6885bf0..1dcd500 100644 --- a/server/device.c +++ b/server/device.c @@ -597,7 +597,7 @@ static int queue_irp( struct device_file *file, const irp_params_t *params, stru add_irp_to_queue( file->device->manager, irp, current ); release_object( irp ); set_error( STATUS_PENDING ); - return 1; + return 0; }
static enum server_fd_type device_file_get_fd_type( struct fd *fd ) @@ -896,8 +896,11 @@ DECL_HANDLER(get_next_device_request)
if (manager->current_call) { - free_irp_params( manager->current_call ); - release_object( manager->current_call ); + irp = manager->current_call; + if (irp->async) + set_async_pending( irp->async, irp->file && is_fd_overlapped( irp->file->fd ) ); + free_irp_params( irp ); + release_object( irp ); manager->current_call = NULL; }
diff --git a/server/file.h b/server/file.h index 0621b47..4341ad3 100644 --- a/server/file.h +++ b/server/file.h @@ -192,6 +192,7 @@ extern obj_handle_t async_handoff( struct async *async, int success, data_size_t extern void queue_async( struct async_queue *queue, struct async *async ); extern void async_set_timeout( struct async *async, timeout_t timeout, unsigned int status ); extern void async_set_result( struct object *obj, unsigned int status, apc_param_t total ); +extern void set_async_pending( struct async *async, int signal ); extern int async_waiting( struct async_queue *queue ); extern void async_terminate( struct async *async, unsigned int status ); extern void async_wake_up( struct async_queue *queue, unsigned int status );