Alexandre Julliard : ntoskrnl: Allow IoCompleteRequest to report completion asynchronously.

Alexandre Julliard julliard at wine.codeweavers.com
Wed Mar 11 10:00:44 CDT 2015


Module: wine
Branch: master
Commit: 4c1da45567f861bf23694dc16e94a8bd48e071d9
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=4c1da45567f861bf23694dc16e94a8bd48e071d9

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Wed Mar 11 22:48:22 2015 +0900

ntoskrnl: Allow IoCompleteRequest to report completion asynchronously.

---

 dlls/ntoskrnl.exe/ntoskrnl.c | 99 +++++++++++++++++++++++++++-----------------
 1 file changed, 62 insertions(+), 37 deletions(-)

diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 65702aa..0ba26b2 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -129,55 +129,54 @@ static HANDLE get_device_manager(void)
 }
 
 /* process an ioctl request for a given device */
-static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff, ULONG in_size,
-                               void *out_buff, ULONG *out_size )
+static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff,
+                               ULONG in_size, ULONG out_size, HANDLE ioctl )
 {
     IRP *irp;
-    void *sys_buff = NULL;
+    void *out_buff = NULL;
     FILE_OBJECT file;
-    IO_STATUS_BLOCK iosb;
     LARGE_INTEGER count;
 
-    TRACE( "ioctl %x device %p in_size %u out_size %u\n", code, device, in_size, *out_size );
+    TRACE( "ioctl %x device %p in_size %u out_size %u\n", code, device, in_size, out_size );
 
     /* so we can spot things that we should initialize */
     memset( &file, 0x88, sizeof(file) );
 
-    if ((code & 3) == METHOD_BUFFERED)
+    if ((code & 3) == METHOD_BUFFERED) out_size = max( in_size, out_size );
+
+    if (out_size)
     {
-        if (!(sys_buff = HeapAlloc( GetProcessHeap(), 0, max( in_size, *out_size ) )))
-            return STATUS_NO_MEMORY;
-        memcpy( sys_buff, in_buff, in_size );
+        if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
+        if ((code & 3) == METHOD_BUFFERED)
+        {
+            memcpy( out_buff, in_buff, in_size );
+            in_buff = out_buff;
+        }
     }
 
-    irp = IoBuildDeviceIoControlRequest( code, device, in_buff, in_size, out_buff, *out_size,
-                                         FALSE, NULL, &iosb );
+    /* note: we abuse UserIosb to store the server handle to the ioctl */
+    irp = IoBuildDeviceIoControlRequest( code, device, in_buff, in_size, out_buff, out_size,
+                                         FALSE, NULL, (IO_STATUS_BLOCK *)ioctl );
     if (!irp)
     {
-        HeapFree( GetProcessHeap(), 0, sys_buff );
+        HeapFree( GetProcessHeap(), 0, out_buff );
         return STATUS_NO_MEMORY;
     }
     irp->RequestorMode = UserMode;
-    irp->AssociatedIrp.SystemBuffer = ((code & 3) == METHOD_BUFFERED) ? sys_buff : in_buff;
-    irp->UserBuffer = out_buff;
     irp->Tail.Overlay.OriginalFileObject = &file;
 
     file.FsContext = NULL;
     file.FsContext2 = NULL;
 
-    IoAllocateMdl( out_buff, *out_size, FALSE, FALSE, irp );
+    KeQueryTickCount( &count );  /* update the global KeTickCount */
 
     device->CurrentIrp = irp;
 
-    KeQueryTickCount( &count );  /* update the global KeTickCount */
-
     IoCallDriver( device, irp );
 
-    *out_size = (iosb.u.Status >= 0) ? iosb.Information : 0;
-    if (out_buff && (code & 3) == METHOD_BUFFERED) memcpy( out_buff, sys_buff, *out_size );
+    device->CurrentIrp = NULL;
 
-    HeapFree( GetProcessHeap(), 0, sys_buff );
-    return iosb.u.Status;
+    return STATUS_SUCCESS;
 }
 
 
@@ -187,10 +186,10 @@ static NTSTATUS process_ioctl( DEVICE_OBJECT *device, ULONG code, void *in_buff,
 NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event )
 {
     HANDLE manager = get_device_manager();
-    obj_handle_t ioctl = 0;
+    HANDLE ioctl = 0;
     NTSTATUS status = STATUS_SUCCESS;
     ULONG code = 0;
-    void *in_buff, *out_buff = NULL;
+    void *in_buff;
     DEVICE_OBJECT *device = NULL;
     ULONG in_size = 4096, out_size = 0;
     HANDLE handles[2];
@@ -211,14 +210,13 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event )
         SERVER_START_REQ( get_next_device_request )
         {
             req->manager = wine_server_obj_handle( manager );
-            req->prev = ioctl;
+            req->prev = wine_server_obj_handle( ioctl );
             req->status = status;
-            wine_server_add_data( req, out_buff, out_size );
             wine_server_set_reply( req, in_buff, in_size );
             if (!(status = wine_server_call( req )))
             {
                 code       = reply->code;
-                ioctl      = reply->next;
+                ioctl      = wine_server_ptr_handle( reply->next );
                 device     = wine_server_get_ptr( reply->user_ptr );
                 client_tid = reply->client_tid;
                 client_pid = reply->client_pid;
@@ -237,10 +235,8 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event )
         switch(status)
         {
         case STATUS_SUCCESS:
-            HeapFree( GetProcessHeap(), 0, out_buff );
-            if (out_size) out_buff = HeapAlloc( GetProcessHeap(), 0, out_size );
-            else out_buff = NULL;
-            status = process_ioctl( device, code, in_buff, in_size, out_buff, &out_size );
+            status = process_ioctl( device, code, in_buff, in_size, out_size, ioctl );
+            if (status == STATUS_SUCCESS) ioctl = 0;  /* status reported by IoCompleteRequest */
             break;
         case STATUS_BUFFER_OVERFLOW:
             HeapFree( GetProcessHeap(), 0, in_buff );
@@ -251,7 +247,6 @@ NTSTATUS CDECL wine_ntoskrnl_main_loop( HANDLE stop_event )
             if (WaitForMultipleObjects( 2, handles, FALSE, INFINITE ) == WAIT_OBJECT_0)
             {
                 HeapFree( GetProcessHeap(), 0, in_buff );
-                HeapFree( GetProcessHeap(), 0, out_buff );
                 return STATUS_SUCCESS;
             }
             break;
@@ -504,10 +499,26 @@ PIRP WINAPI IoBuildDeviceIoControlRequest( ULONG code, PDEVICE_OBJECT device,
     irpsp->Parameters.DeviceIoControl.IoControlCode = code;
     irpsp->Parameters.DeviceIoControl.InputBufferLength = in_len;
     irpsp->Parameters.DeviceIoControl.OutputBufferLength = out_len;
-    irpsp->Parameters.DeviceIoControl.Type3InputBuffer = in_buff;
     irpsp->DeviceObject = device;
     irpsp->CompletionRoutine = NULL;
 
+    switch (code & 3)
+    {
+    case METHOD_BUFFERED:
+        irp->AssociatedIrp.SystemBuffer = in_buff;
+        break;
+    case METHOD_IN_DIRECT:
+    case METHOD_OUT_DIRECT:
+        irp->AssociatedIrp.SystemBuffer = in_buff;
+        IoAllocateMdl( out_buff, out_len, FALSE, FALSE, irp );
+        break;
+    case METHOD_NEITHER:
+        irpsp->Parameters.DeviceIoControl.Type3InputBuffer = in_buff;
+        break;
+    }
+
+    irp->RequestorMode = KernelMode;
+    irp->UserBuffer = out_buff;
     irp->UserIosb = iosb;
     irp->UserEvent = event;
     return irp;
@@ -958,13 +969,12 @@ VOID WINAPI IoCompleteRequest( IRP *irp, UCHAR priority_boost )
 {
     IO_STACK_LOCATION *irpsp;
     PIO_COMPLETION_ROUTINE routine;
-    IO_STATUS_BLOCK *iosb;
     NTSTATUS status, stat;
+    HANDLE ioctl;
     int call_flag = 0;
 
     TRACE( "%p %u\n", irp, priority_boost );
 
-    iosb = irp->UserIosb;
     status = irp->IoStatus.u.Status;
     while (irp->CurrentLocation <= irp->StackCount)
     {
@@ -991,11 +1001,26 @@ VOID WINAPI IoCompleteRequest( IRP *irp, UCHAR priority_boost )
                 return;
         }
     }
-    if (iosb)
+
+    ioctl = (HANDLE)irp->UserIosb;
+    if (ioctl)
     {
-        iosb->u.Status = irp->IoStatus.u.Status;
-        if (iosb->u.Status >= 0) iosb->Information = irp->IoStatus.Information;
+        HANDLE manager = get_device_manager();
+        void *out_buff = irp->UserBuffer;
+
+        SERVER_START_REQ( set_ioctl_result )
+        {
+            req->manager = wine_server_obj_handle( manager );
+            req->handle  = wine_server_obj_handle( ioctl );
+            req->status  = irp->IoStatus.u.Status;
+            if (irp->IoStatus.u.Status >= 0 && out_buff)
+                wine_server_add_data( req, out_buff, irp->IoStatus.Information );
+            wine_server_call( req );
+        }
+        SERVER_END_REQ;
+        HeapFree( GetProcessHeap(), 0, out_buff );
     }
+
     IoFreeIrp( irp );
 }
 




More information about the wine-cvs mailing list