Jacek Caban : ntoskrnl.exe: Cancel IRPs terminated by server.
Alexandre Julliard
julliard at winehq.org
Tue May 28 15:06:51 CDT 2019
Module: wine
Branch: master
Commit: 9157129fc86c8759e75fc6f68b49b28693c6c9ca
URL: https://source.winehq.org/git/wine.git/?a=commit;h=9157129fc86c8759e75fc6f68b49b28693c6c9ca
Author: Jacek Caban <jacek at codeweavers.com>
Date: Tue May 28 14:10:48 2019 +0200
ntoskrnl.exe: Cancel IRPs terminated by server.
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at 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);
}
More information about the wine-cvs
mailing list