server: Allow async i/o operations to send completion messages.
This commit is contained in:
parent
074281ff6c
commit
c702a91a3c
|
@ -2356,6 +2356,7 @@ NtNotifyChangeDirectoryFile( HANDLE FileHandle, HANDLE Event,
|
||||||
req->async.arg = info;
|
req->async.arg = info;
|
||||||
req->async.apc = read_changes_user_apc;
|
req->async.apc = read_changes_user_apc;
|
||||||
req->async.event = Event;
|
req->async.event = Event;
|
||||||
|
req->async.cvalue = 0;
|
||||||
status = wine_server_call( req );
|
status = wine_server_call( req );
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
|
|
|
@ -650,6 +650,7 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent,
|
||||||
req->async.arg = fileio;
|
req->async.arg = fileio;
|
||||||
req->async.apc = fileio_apc;
|
req->async.apc = fileio_apc;
|
||||||
req->async.event = hEvent;
|
req->async.event = hEvent;
|
||||||
|
req->async.cvalue = 0;
|
||||||
status = wine_server_call( req );
|
status = wine_server_call( req );
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
|
@ -879,6 +880,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent,
|
||||||
req->async.arg = fileio;
|
req->async.arg = fileio;
|
||||||
req->async.apc = fileio_apc;
|
req->async.apc = fileio_apc;
|
||||||
req->async.event = hEvent;
|
req->async.event = hEvent;
|
||||||
|
req->async.cvalue = 0;
|
||||||
status = wine_server_call( req );
|
status = wine_server_call( req );
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
|
@ -1005,6 +1007,7 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event,
|
||||||
req->async.arg = async;
|
req->async.arg = async;
|
||||||
req->async.apc = (apc || event) ? ioctl_apc : NULL;
|
req->async.apc = (apc || event) ? ioctl_apc : NULL;
|
||||||
req->async.event = event;
|
req->async.event = event;
|
||||||
|
req->async.cvalue = 0;
|
||||||
wine_server_add_data( req, in_buffer, in_size );
|
wine_server_add_data( req, in_buffer, in_size );
|
||||||
wine_server_set_reply( req, out_buffer, out_size );
|
wine_server_set_reply( req, out_buffer, out_size );
|
||||||
if (!(status = wine_server_call( req )))
|
if (!(status = wine_server_call( req )))
|
||||||
|
@ -1061,7 +1064,7 @@ NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
|
||||||
PVOID out_buffer, ULONG out_size)
|
PVOID out_buffer, ULONG out_size)
|
||||||
{
|
{
|
||||||
ULONG device = (code >> 16);
|
ULONG device = (code >> 16);
|
||||||
NTSTATUS status;
|
NTSTATUS status = STATUS_NOT_SUPPORTED;
|
||||||
|
|
||||||
TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
|
TRACE("(%p,%p,%p,%p,%p,0x%08x,%p,0x%08x,%p,0x%08x)\n",
|
||||||
handle, event, apc, apc_context, io, code,
|
handle, event, apc, apc_context, io, code,
|
||||||
|
@ -1085,11 +1088,12 @@ NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
|
||||||
status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code,
|
status = TAPE_DeviceIoControl(handle, event, apc, apc_context, io, code,
|
||||||
in_buffer, in_size, out_buffer, out_size);
|
in_buffer, in_size, out_buffer, out_size);
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
|
|
||||||
|
if (status == STATUS_NOT_SUPPORTED)
|
||||||
status = server_ioctl_file( handle, event, apc, apc_context, io, code,
|
status = server_ioctl_file( handle, event, apc, apc_context, io, code,
|
||||||
in_buffer, in_size, out_buffer, out_size );
|
in_buffer, in_size, out_buffer, out_size );
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (status != STATUS_PENDING) io->u.Status = status;
|
if (status != STATUS_PENDING) io->u.Status = status;
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -1807,6 +1811,16 @@ static inline void get_device_info_fstatfs( FILE_FS_DEVICE_INFORMATION *info, co
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline int is_device_placeholder( int fd )
|
||||||
|
{
|
||||||
|
static const char wine_placeholder[] = "Wine device placeholder";
|
||||||
|
char buffer[sizeof(wine_placeholder)-1];
|
||||||
|
|
||||||
|
if (pread( fd, buffer, sizeof(wine_placeholder) - 1, 0 ) != sizeof(wine_placeholder) - 1)
|
||||||
|
return 0;
|
||||||
|
return !memcmp( buffer, wine_placeholder, sizeof(wine_placeholder) - 1 );
|
||||||
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* get_device_info
|
* get_device_info
|
||||||
*
|
*
|
||||||
|
@ -1847,6 +1861,10 @@ static NTSTATUS get_device_info( int fd, FILE_FS_DEVICE_INFORMATION *info )
|
||||||
{
|
{
|
||||||
info->DeviceType = FILE_DEVICE_NAMED_PIPE;
|
info->DeviceType = FILE_DEVICE_NAMED_PIPE;
|
||||||
}
|
}
|
||||||
|
else if (is_device_placeholder( fd ))
|
||||||
|
{
|
||||||
|
info->DeviceType = FILE_DEVICE_DISK;
|
||||||
|
}
|
||||||
else /* regular file or directory */
|
else /* regular file or directory */
|
||||||
{
|
{
|
||||||
#if defined(linux) && defined(HAVE_FSTATFS)
|
#if defined(linux) && defined(HAVE_FSTATFS)
|
||||||
|
|
|
@ -1324,6 +1324,7 @@ static int WS2_register_async_shutdown( SOCKET s, int type )
|
||||||
req->async.iosb = &wsa->local_iosb;
|
req->async.iosb = &wsa->local_iosb;
|
||||||
req->async.arg = wsa;
|
req->async.arg = wsa;
|
||||||
req->async.apc = ws2_async_apc;
|
req->async.apc = ws2_async_apc;
|
||||||
|
req->async.cvalue = 0;
|
||||||
status = wine_server_call( req );
|
status = wine_server_call( req );
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
|
@ -2688,6 +2689,7 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
||||||
req->async.arg = wsa;
|
req->async.arg = wsa;
|
||||||
req->async.apc = ws2_async_apc;
|
req->async.apc = ws2_async_apc;
|
||||||
req->async.event = lpCompletionRoutine ? 0 : lpOverlapped->hEvent;
|
req->async.event = lpCompletionRoutine ? 0 : lpOverlapped->hEvent;
|
||||||
|
req->async.cvalue = 0;
|
||||||
err = wine_server_call( req );
|
err = wine_server_call( req );
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
|
@ -4201,6 +4203,7 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
|
||||||
req->async.arg = wsa;
|
req->async.arg = wsa;
|
||||||
req->async.apc = ws2_async_apc;
|
req->async.apc = ws2_async_apc;
|
||||||
req->async.event = lpCompletionRoutine ? 0 : lpOverlapped->hEvent;
|
req->async.event = lpCompletionRoutine ? 0 : lpOverlapped->hEvent;
|
||||||
|
req->async.cvalue = 0;
|
||||||
err = wine_server_call( req );
|
err = wine_server_call( req );
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
SERVER_END_REQ;
|
||||||
|
|
|
@ -163,6 +163,7 @@ typedef struct
|
||||||
void *arg;
|
void *arg;
|
||||||
void *apc;
|
void *apc;
|
||||||
obj_handle_t event;
|
obj_handle_t event;
|
||||||
|
unsigned long cvalue;
|
||||||
} async_data_t;
|
} async_data_t;
|
||||||
|
|
||||||
|
|
||||||
|
@ -4885,6 +4886,6 @@ union generic_reply
|
||||||
struct set_completion_info_reply set_completion_info_reply;
|
struct set_completion_info_reply set_completion_info_reply;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SERVER_PROTOCOL_VERSION 328
|
#define SERVER_PROTOCOL_VERSION 329
|
||||||
|
|
||||||
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
#endif /* __WINE_WINE_SERVER_PROTOCOL_H */
|
||||||
|
|
|
@ -144,6 +144,10 @@ void async_terminate( struct async *async, unsigned int status )
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* send error completion event */
|
||||||
|
if (status != STATUS_ALERTED && async->data.cvalue && async->queue && async->queue->fd)
|
||||||
|
fd_add_completion( async->queue->fd, async->data.cvalue, status, 0 );
|
||||||
|
|
||||||
memset( &data, 0, sizeof(data) );
|
memset( &data, 0, sizeof(data) );
|
||||||
data.type = APC_ASYNC_IO;
|
data.type = APC_ASYNC_IO;
|
||||||
data.async_io.func = async->data.callback;
|
data.async_io.func = async->data.callback;
|
||||||
|
@ -251,6 +255,8 @@ void async_set_result( struct object *obj, unsigned int status )
|
||||||
if (async->timeout) remove_timeout_user( async->timeout );
|
if (async->timeout) remove_timeout_user( async->timeout );
|
||||||
async->timeout = NULL;
|
async->timeout = NULL;
|
||||||
async->status = status;
|
async->status = status;
|
||||||
|
if (async->data.cvalue && async->queue && async->queue->fd)
|
||||||
|
fd_add_completion( async->queue->fd, async->data.cvalue, status, 0 ); /* TODO pass Information field */
|
||||||
if (async->data.apc)
|
if (async->data.apc)
|
||||||
{
|
{
|
||||||
apc_call_t data;
|
apc_call_t data;
|
||||||
|
|
|
@ -132,7 +132,7 @@ struct completion *get_completion_obj( struct process *process, obj_handle_t han
|
||||||
return (struct completion *) get_handle_obj( process, handle, access, &completion_ops );
|
return (struct completion *) get_handle_obj( process, handle, access, &completion_ops );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_completion( struct completion *completion, unsigned long ckey, unsigned long cvalue, unsigned int status, unsigned long information )
|
void add_completion( struct completion *completion, unsigned long ckey, unsigned long cvalue, unsigned int status, unsigned long information )
|
||||||
{
|
{
|
||||||
struct comp_msg *msg = mem_alloc( sizeof( *msg ) );
|
struct comp_msg *msg = mem_alloc( sizeof( *msg ) );
|
||||||
|
|
||||||
|
|
|
@ -1919,6 +1919,13 @@ static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handl
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* add a completion result to a completion queue attached to the fd */
|
||||||
|
void fd_add_completion( struct fd *fd, unsigned long cvalue, unsigned int status, unsigned long information )
|
||||||
|
{
|
||||||
|
if (fd->completion)
|
||||||
|
add_completion( fd->completion, fd->comp_key, cvalue, status, information );
|
||||||
|
}
|
||||||
|
|
||||||
/* flush a file buffers */
|
/* flush a file buffers */
|
||||||
DECL_HANDLER(flush_file)
|
DECL_HANDLER(flush_file)
|
||||||
{
|
{
|
||||||
|
|
|
@ -122,7 +122,8 @@ extern struct object *create_dir_obj( struct fd *fd );
|
||||||
|
|
||||||
/* completion */
|
/* completion */
|
||||||
|
|
||||||
struct completion *get_completion_obj( struct process *process, obj_handle_t handle, unsigned int access );
|
extern struct completion *get_completion_obj( struct process *process, obj_handle_t handle, unsigned int access );
|
||||||
|
extern void add_completion( struct completion *completion, unsigned long ckey, unsigned long cvalue, unsigned int status, unsigned long information );
|
||||||
|
|
||||||
/* serial port functions */
|
/* serial port functions */
|
||||||
|
|
||||||
|
@ -139,6 +140,7 @@ extern void async_set_result( struct object *obj, unsigned int status );
|
||||||
extern int async_waiting( struct async_queue *queue );
|
extern int async_waiting( struct async_queue *queue );
|
||||||
extern void async_terminate( struct async *async, unsigned int status );
|
extern void async_terminate( struct async *async, unsigned int status );
|
||||||
extern void async_wake_up( struct async_queue *queue, unsigned int status );
|
extern void async_wake_up( struct async_queue *queue, unsigned int status );
|
||||||
|
extern void fd_add_completion( struct fd *fd, unsigned long cvalue, unsigned int status, unsigned long information );
|
||||||
|
|
||||||
/* access rights that require Unix read permission */
|
/* access rights that require Unix read permission */
|
||||||
#define FILE_UNIX_READ_ACCESS (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)
|
#define FILE_UNIX_READ_ACCESS (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)
|
||||||
|
|
|
@ -179,6 +179,7 @@ typedef struct
|
||||||
void *arg; /* opaque user data to pass to callback */
|
void *arg; /* opaque user data to pass to callback */
|
||||||
void *apc; /* user apc to call */
|
void *apc; /* user apc to call */
|
||||||
obj_handle_t event; /* event to signal when done */
|
obj_handle_t event; /* event to signal when done */
|
||||||
|
unsigned long cvalue; /* completion value to use for completion events */
|
||||||
} async_data_t;
|
} async_data_t;
|
||||||
|
|
||||||
/* structures for extra message data */
|
/* structures for extra message data */
|
||||||
|
|
Loading…
Reference in New Issue