Module: wine Branch: master Commit: 9157129fc86c8759e75fc6f68b49b28693c6c9ca URL: https://source.winehq.org/git/wine.git/?a=commit;h=9157129fc86c8759e75fc6f68...
Author: Jacek Caban jacek@codeweavers.com Date: Tue May 28 14:10:48 2019 +0200
ntoskrnl.exe: Cancel IRPs terminated by server.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/ntoskrnl.exe/ntoskrnl.c | 38 +++++++++++++++++++++++++++++++++++--- dlls/ntoskrnl.exe/tests/ntoskrnl.c | 3 --- 2 files changed, 35 insertions(+), 6 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c index 04a3f31..b5d89f6 100644 --- a/dlls/ntoskrnl.exe/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/ntoskrnl.c @@ -523,15 +523,31 @@ static void *create_file_object( HANDLE handle ) return file; }
+DECLARE_CRITICAL_SECTION(irp_completion_cs); + +static void WINAPI cancel_completed_irp( DEVICE_OBJECT *device, IRP *irp ) +{ + TRACE( "(%p %p)\n", device, irp ); + + IoReleaseCancelSpinLock(irp->CancelIrql); + + irp->IoStatus.u.Status = STATUS_CANCELLED; + irp->IoStatus.Information = 0; + IoCompleteRequest(irp, IO_NO_INCREMENT); +} + /* transfer result of IRP back to wineserver */ static NTSTATUS WINAPI dispatch_irp_completion( DEVICE_OBJECT *device, IRP *irp, void *context ) { HANDLE irp_handle = context; void *out_buff = irp->UserBuffer; + NTSTATUS status;
if (irp->Flags & IRP_WRITE_OPERATION) out_buff = NULL; /* do not transfer back input buffer */
+ EnterCriticalSection( &irp_completion_cs ); + SERVER_START_REQ( set_irp_result ) { req->handle = wine_server_obj_handle( irp_handle ); @@ -541,16 +557,29 @@ static NTSTATUS WINAPI dispatch_irp_completion( DEVICE_OBJECT *device, IRP *irp, req->size = irp->IoStatus.Information; if (out_buff) wine_server_add_data( req, out_buff, irp->IoStatus.Information ); } - wine_server_call( req ); + status = wine_server_call( req ); } SERVER_END_REQ;
+ if (status == STATUS_MORE_PROCESSING_REQUIRED) + { + /* IRP is complete, but server may have already ordered cancel call. In such case, + * it will return STATUS_MORE_PROCESSING_REQUIRED, leaving the IRP alive until + * cancel frees it. */ + if (irp->Cancel) + status = STATUS_SUCCESS; + else + IoSetCancelRoutine( irp, cancel_completed_irp ); + } + if (irp->UserBuffer != irp->AssociatedIrp.SystemBuffer) { HeapFree( GetProcessHeap(), 0, irp->UserBuffer ); irp->UserBuffer = NULL; } - return STATUS_SUCCESS; + + LeaveCriticalSection( &irp_completion_cs ); + return status; }
struct dispatch_context @@ -842,8 +871,11 @@ static NTSTATUS dispatch_cancel( struct dispatch_context *context ) { IRP *irp = wine_server_get_ptr( context->params.cancel.irp );
- FIXME( "%p\n", irp ); + TRACE( "%p\n", irp );
+ EnterCriticalSection( &irp_completion_cs ); + IoCancelIrp( irp ); + LeaveCriticalSection( &irp_completion_cs ); return STATUS_SUCCESS; }
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c index d505643..43418f3 100644 --- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c +++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c @@ -234,7 +234,6 @@ 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); ok(res, "DeviceIoControl failed: %u\n", GetLastError()); - todo_wine ok(cancel_cnt == 2, "cancel_cnt = %u\n", cancel_cnt);
/* test cancelling selected overlapped event */ @@ -254,7 +253,6 @@ 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); ok(res, "DeviceIoControl failed: %u\n", GetLastError()); - todo_wine ok(cancel_cnt == 1, "cancel_cnt = %u\n", cancel_cnt);
pCancelIoEx(file, &overlapped2); @@ -262,7 +260,6 @@ 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); ok(res, "DeviceIoControl failed: %u\n", GetLastError()); - todo_wine ok(cancel_cnt == 2, "cancel_cnt = %u\n", cancel_cnt); }