ntoskrnl.exe: Implement IoCancelIrp.

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-02 13:21:19 +02:00 committed by Alexandre Julliard
parent da5b97c8b4
commit 5f10c86d5b
4 changed files with 150 additions and 1 deletions

View file

@ -2321,6 +2321,31 @@ void WINAPI IofCompleteRequest( IRP *irp, UCHAR priority_boost )
}
/***********************************************************************
* IoCancelIrp (NTOSKRNL.EXE.@)
*/
BOOLEAN WINAPI IoCancelIrp( IRP *irp )
{
PDRIVER_CANCEL cancel_routine;
KIRQL irql;
TRACE( "(%p)\n", irp );
IoAcquireCancelSpinLock( &irql );
irp->Cancel = TRUE;
if (!(cancel_routine = IoSetCancelRoutine( irp, NULL )))
{
IoReleaseCancelSpinLock( irp->CancelIrql );
return FALSE;
}
/* CancelRoutine is responsible for calling IoReleaseCancelSpinLock */
irp->CancelIrql = irql;
cancel_routine( IoGetCurrentIrpStackLocation(irp)->DeviceObject, irp );
return TRUE;
}
/***********************************************************************
* InterlockedCompareExchange (NTOSKRNL.EXE.@)
*/

View file

@ -336,7 +336,7 @@
@ stdcall IoBuildSynchronousFsdRequest(long ptr ptr long ptr ptr ptr)
@ stdcall IoCallDriver(ptr ptr)
@ stub IoCancelFileOpen
@ stub IoCancelIrp
@ stdcall IoCancelIrp(ptr)
@ stub IoCheckDesiredAccess
@ stub IoCheckEaBufferValidity
@ stub IoCheckFunctionAccess

View file

@ -758,6 +758,125 @@ static void test_call_driver(DEVICE_OBJECT *device)
ok(status == STATUS_SUCCESS, "got %#x\n", status);
}
static int cancel_cnt;
static void WINAPI cancel_irp(DEVICE_OBJECT *device, IRP *irp)
{
IoReleaseCancelSpinLock(irp->CancelIrql);
ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
ok(!irp->CancelRoutine, "CancelRoutine = %p\n", irp->CancelRoutine);
irp->IoStatus.Status = STATUS_CANCELLED;
irp->IoStatus.Information = 0;
cancel_cnt++;
}
static NTSTATUS WINAPI cancel_test_completion(DEVICE_OBJECT *device, IRP *irp, void *context)
{
ok(cancel_cnt == 1, "cancel_cnt = %d\n", cancel_cnt);
*(BOOL*)context = TRUE;
return STATUS_SUCCESS;
}
static void test_cancel_irp(DEVICE_OBJECT *device)
{
IO_STACK_LOCATION *irpsp;
IO_STATUS_BLOCK iosb;
IRP *irp = NULL;
BOOL completion_called;
BOOLEAN r;
NTSTATUS status;
/* cancel IRP with no cancel routine */
irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
r = IoCancelIrp(irp);
ok(!r, "IoCancelIrp returned %x\n", r);
ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
r = IoCancelIrp(irp);
ok(!r, "IoCancelIrp returned %x\n", r);
IoFreeIrp(irp);
irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
/* cancel IRP with cancel routine */
status = IoCallDriver(device, irp);
ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
ok(irp->CurrentLocation == 1, "CurrentLocation = %u\n", irp->CurrentLocation);
irpsp = IoGetCurrentIrpStackLocation(irp);
ok(irpsp->DeviceObject == device, "DeviceObject = %u\n", irpsp->DeviceObject);
IoSetCancelRoutine(irp, cancel_irp);
cancel_cnt = 0;
r = IoCancelIrp(irp);
ok(r == TRUE, "IoCancelIrp returned %x\n", r);
ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
ok(cancel_cnt == 1, "cancel_cnt = %d\n", cancel_cnt);
cancel_cnt = 0;
r = IoCancelIrp(irp);
ok(!r, "IoCancelIrp returned %x\n", r);
ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
ok(!cancel_cnt, "cancel_cnt = %d\n", cancel_cnt);
IoCompleteRequest(irp, IO_NO_INCREMENT);
/* cancel IRP with cancel and completion routines with no SL_INVOKE_ON_ERROR */
irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
IoSetCompletionRoutine(irp, cancel_test_completion, &completion_called, TRUE, FALSE, TRUE);
status = IoCallDriver(device, irp);
ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
IoSetCancelRoutine(irp, cancel_irp);
cancel_cnt = 0;
r = IoCancelIrp(irp);
ok(r == TRUE, "IoCancelIrp returned %x\n", r);
ok(cancel_cnt == 1, "cancel_cnt = %d\n", cancel_cnt);
ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
completion_called = FALSE;
IoCompleteRequest(irp, IO_NO_INCREMENT);
ok(completion_called, "completion not called\n");
/* cancel IRP with cancel and completion routines with no SL_INVOKE_ON_CANCEL flag */
irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
IoSetCompletionRoutine(irp, cancel_test_completion, &completion_called, TRUE, TRUE, FALSE);
status = IoCallDriver(device, irp);
ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
IoSetCancelRoutine(irp, cancel_irp);
cancel_cnt = 0;
r = IoCancelIrp(irp);
ok(r == TRUE, "IoCancelIrp returned %x\n", r);
ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
ok(cancel_cnt == 1, "cancel_cnt = %d\n", cancel_cnt);
completion_called = FALSE;
IoCompleteRequest(irp, IO_NO_INCREMENT);
ok(completion_called, "completion not called\n");
/* cancel IRP with cancel and completion routines, but no SL_INVOKE_ON_ERROR nor SL_INVOKE_ON_CANCEL flag */
irp = IoBuildAsynchronousFsdRequest(IRP_MJ_FLUSH_BUFFERS, device, NULL, 0, NULL, &iosb);
IoSetCompletionRoutine(irp, cancel_test_completion, &completion_called, TRUE, FALSE, FALSE);
status = IoCallDriver(device, irp);
ok(status == STATUS_PENDING, "IoCallDriver returned %#x\n", status);
IoSetCancelRoutine(irp, cancel_irp);
cancel_cnt = 0;
r = IoCancelIrp(irp);
ok(r == TRUE, "IoCancelIrp returned %x\n", r);
ok(irp->Cancel == TRUE, "Cancel = %x\n", irp->Cancel);
ok(cancel_cnt == 1, "cancel_cnt = %d\n", cancel_cnt);
completion_called = FALSE;
IoCompleteRequest(irp, IO_NO_INCREMENT);
ok(!completion_called, "completion not called\n");
}
static int callout_cnt;
static void WINAPI callout(void *parameter)
@ -1294,6 +1413,7 @@ static void WINAPI main_test_task(DEVICE_OBJECT *device, void *context)
test_current_thread(TRUE);
test_call_driver(device);
test_cancel_irp(device);
/* print process report */
if (winetest_debug)

View file

@ -1493,6 +1493,9 @@ NTSTATUS WINAPI ObCloseHandle(IN HANDLE handle);
# endif
#endif
#define IoSetCancelRoutine(irp, routine) \
((PDRIVER_CANCEL)InterlockedExchangePointer((void **)&(irp)->CancelRoutine, routine))
static inline void IoSetCompletionRoutine(IRP *irp, PIO_COMPLETION_ROUTINE routine, void *context,
BOOLEAN on_success, BOOLEAN on_error, BOOLEAN on_cancel)
{
@ -1563,6 +1566,7 @@ PIRP WINAPI IoBuildAsynchronousFsdRequest(ULONG,DEVICE_OBJECT*,void*,ULONG,
PIRP WINAPI IoBuildDeviceIoControlRequest(ULONG,DEVICE_OBJECT*,PVOID,ULONG,PVOID,ULONG,BOOLEAN,PKEVENT,IO_STATUS_BLOCK*);
PIRP WINAPI IoBuildSynchronousFsdRequest(ULONG,DEVICE_OBJECT*,PVOID,ULONG,PLARGE_INTEGER,PKEVENT,IO_STATUS_BLOCK*);
NTSTATUS WINAPI IoCallDriver(DEVICE_OBJECT*,IRP*);
BOOLEAN WINAPI IoCancelIrp(IRP*);
VOID WINAPI IoCompleteRequest(IRP*,UCHAR);
NTSTATUS WINAPI IoCreateDevice(DRIVER_OBJECT*,ULONG,UNICODE_STRING*,DEVICE_TYPE,ULONG,BOOLEAN,DEVICE_OBJECT**);
NTSTATUS WINAPI IoCreateDriver(UNICODE_STRING*,PDRIVER_INITIALIZE);