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