ntoskrnl.exe: Cancel IRPs terminated by server.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2019-05-28 14:10:48 +02:00 committed by Alexandre Julliard
parent b724024d5a
commit 9157129fc8
2 changed files with 35 additions and 6 deletions

View File

@ -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;
}

View File

@ -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);
}