ntoskrnl: Allow IoCompleteRequest to report completion asynchronously.

This commit is contained in:
Alexandre Julliard 2015-03-11 22:48:22 +09:00
parent ecf7ed6650
commit 4c1da45567
1 changed files with 62 additions and 37 deletions

View File

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