Jacek Caban : ntoskrnl.exe: Implement IoCancelIrp.
Alexandre Julliard
julliard at winehq.org
Thu May 2 16:45:09 CDT 2019
Module: wine
Branch: master
Commit: 5f10c86d5bbd20466091a7a54424ad630a8d3812
URL: https://source.winehq.org/git/wine.git/?a=commit;h=5f10c86d5bbd20466091a7a54424ad630a8d3812
Author: Jacek Caban <jacek at codeweavers.com>
Date: Thu May 2 13:21:19 2019 +0200
ntoskrnl.exe: Implement IoCancelIrp.
Signed-off-by: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/ntoskrnl.exe/ntoskrnl.c | 25 ++++++++
dlls/ntoskrnl.exe/ntoskrnl.exe.spec | 2 +-
dlls/ntoskrnl.exe/tests/driver.c | 120 ++++++++++++++++++++++++++++++++++++
include/ddk/wdm.h | 4 ++
4 files changed, 150 insertions(+), 1 deletion(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 63f6647..6ac2a3e 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -2322,6 +2322,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.@)
*/
DEFINE_FASTCALL_WRAPPER( NTOSKRNL_InterlockedCompareExchange, 12 )
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
index 20999d2..af43b2a 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
+++ b/dlls/ntoskrnl.exe/ntoskrnl.exe.spec
@@ -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
diff --git a/dlls/ntoskrnl.exe/tests/driver.c b/dlls/ntoskrnl.exe/tests/driver.c
index 5e6d5ca..c2ef890 100644
--- a/dlls/ntoskrnl.exe/tests/driver.c
+++ b/dlls/ntoskrnl.exe/tests/driver.c
@@ -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)
diff --git a/include/ddk/wdm.h b/include/ddk/wdm.h
index 1f6bdfa..6fb718a 100644
--- a/include/ddk/wdm.h
+++ b/include/ddk/wdm.h
@@ -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);
More information about the wine-cvs
mailing list