From f507ccbf52c6412dadfe4e909cda51cbbf423db5 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 30 Dec 2008 20:51:55 +0100 Subject: [PATCH] server: Specify the user APC to call only once the system APC has executed. --- dlls/ntdll/directory.c | 6 ++--- dlls/ntdll/file.c | 41 +++++++++++++++++++--------------- dlls/ntdll/sync.c | 15 +++++++++---- dlls/ws2_32/socket.c | 17 +++++++------- include/wine/server_protocol.h | 6 ++--- server/async.c | 6 ++--- server/file.h | 2 +- server/protocol.def | 4 ++-- server/thread.c | 4 +++- server/trace.c | 9 ++++---- 10 files changed, 62 insertions(+), 48 deletions(-) diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c index c2453f89344..f2962aa4872 100644 --- a/dlls/ntdll/directory.c +++ b/dlls/ntdll/directory.c @@ -2302,7 +2302,7 @@ static void WINAPI read_changes_user_apc( void *arg, IO_STATUS_BLOCK *io, ULONG RtlFreeHeap( GetProcessHeap(), 0, info ); } -static NTSTATUS read_changes_apc( void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status, ULONG *total ) +static NTSTATUS read_changes_apc( void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status, void **apc ) { struct read_changes_info *info = user; char path[PATH_MAX]; @@ -2347,7 +2347,8 @@ static NTSTATUS read_changes_apc( void *user, PIO_STATUS_BLOCK iosb, NTSTATUS st } iosb->u.Status = ret; - iosb->Information = *total = len; + iosb->Information = len; + *apc = read_changes_user_apc; return ret; } @@ -2403,7 +2404,6 @@ NtNotifyChangeDirectoryFile( HANDLE FileHandle, HANDLE Event, req->async.callback = read_changes_apc; req->async.iosb = IoStatusBlock; req->async.arg = info; - req->async.apc = read_changes_user_apc; req->async.event = wine_server_obj_handle( Event ); req->async.cvalue = cvalue; status = wine_server_call( req ); diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 1dfbd0140c3..eeffff550ec 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -334,7 +334,7 @@ NTSTATUS FILE_GetNtStatus(void) /*********************************************************************** * FILE_AsyncReadService (INTERNAL) */ -static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status, ULONG *total) +static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status, void **apc) { async_fileio_read *fileio = user; int fd, needs_close, result; @@ -385,7 +385,8 @@ static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATU if (status != STATUS_PENDING) { iosb->u.Status = status; - iosb->Information = *total = fileio->already; + iosb->Information = fileio->already; + *apc = fileio_apc; } return status; } @@ -659,7 +660,6 @@ NTSTATUS WINAPI NtReadFile(HANDLE hFile, HANDLE hEvent, req->async.callback = FILE_AsyncReadService; req->async.iosb = io_status; req->async.arg = fileio; - req->async.apc = fileio_apc; req->async.cvalue = cvalue; status = wine_server_call( req ); } @@ -812,7 +812,7 @@ NTSTATUS WINAPI NtReadFileScatter( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap /*********************************************************************** * FILE_AsyncWriteService (INTERNAL) */ -static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status, ULONG *total) +static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status, void **apc) { async_fileio_write *fileio = user; int result, fd, needs_close; @@ -853,7 +853,8 @@ static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTAT if (status != STATUS_PENDING) { iosb->u.Status = status; - iosb->Information = *total = fileio->already; + iosb->Information = fileio->already; + *apc = fileio_apc; } return status; } @@ -983,7 +984,6 @@ NTSTATUS WINAPI NtWriteFile(HANDLE hFile, HANDLE hEvent, req->async.callback = FILE_AsyncWriteService; req->async.iosb = io_status; req->async.arg = fileio; - req->async.apc = fileio_apc; req->async.cvalue = cvalue; status = wine_server_call( req ); } @@ -1139,14 +1139,23 @@ NTSTATUS WINAPI NtWriteFileGather( HANDLE file, HANDLE event, PIO_APC_ROUTINE ap struct async_ioctl { HANDLE handle; /* handle to the device */ + HANDLE event; /* async event */ void *buffer; /* buffer for output */ ULONG size; /* size of buffer */ PIO_APC_ROUTINE apc; /* user apc params */ void *apc_arg; }; +/* callback for ioctl user APC */ +static void WINAPI ioctl_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved ) +{ + struct async_ioctl *async = arg; + if (async->apc) async->apc( async->apc_arg, io, reserved ); + RtlFreeHeap( GetProcessHeap(), 0, async ); +} + /* callback for ioctl async I/O completion */ -static NTSTATUS ioctl_completion( void *arg, IO_STATUS_BLOCK *io, NTSTATUS status, ULONG *total ) +static NTSTATUS ioctl_completion( void *arg, IO_STATUS_BLOCK *io, NTSTATUS status, void **apc ) { struct async_ioctl *async = arg; @@ -1158,22 +1167,18 @@ static NTSTATUS ioctl_completion( void *arg, IO_STATUS_BLOCK *io, NTSTATUS statu req->user_arg = async; wine_server_set_reply( req, async->buffer, async->size ); if (!(status = wine_server_call( req ))) - io->Information = *total = wine_server_reply_size( reply ); + io->Information = wine_server_reply_size( reply ); } SERVER_END_REQ; } - if (status != STATUS_PENDING) io->u.Status = status; + if (status != STATUS_PENDING) + { + io->u.Status = status; + if (async->apc || async->event) *apc = ioctl_apc; + } return status; } -/* callback for ioctl user APC */ -static void WINAPI ioctl_apc( void *arg, IO_STATUS_BLOCK *io, ULONG reserved ) -{ - struct async_ioctl *async = arg; - if (async->apc) async->apc( async->apc_arg, io, reserved ); - RtlFreeHeap( GetProcessHeap(), 0, async ); -} - /* do a ioctl call through the server */ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, PVOID apc_context, @@ -1190,6 +1195,7 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, if (!(async = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*async) ))) return STATUS_NO_MEMORY; async->handle = handle; + async->event = event; async->buffer = out_buffer; async->size = out_size; async->apc = apc; @@ -1203,7 +1209,6 @@ static NTSTATUS server_ioctl_file( HANDLE handle, HANDLE event, req->async.callback = ioctl_completion; req->async.iosb = io; req->async.arg = async; - req->async.apc = (apc || event) ? ioctl_apc : NULL; req->async.event = wine_server_obj_handle( event ); req->async.cvalue = cvalue; wine_server_add_data( req, in_buffer, in_size ); diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index ba8d65b8958..8f1a13518c1 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -865,12 +865,19 @@ static BOOL invoke_apc( const apc_call_t *call, apc_result_t *result ) break; } case APC_ASYNC_IO: + { + void *apc = NULL; + IO_STATUS_BLOCK *iosb = call->async_io.sb; result->type = call->type; - result->async_io.status = call->async_io.func( call->async_io.user, - call->async_io.sb, - call->async_io.status, - &result->async_io.total ); + result->async_io.status = call->async_io.func( call->async_io.user, iosb, + call->async_io.status, &apc ); + if (result->async_io.status != STATUS_PENDING) + { + result->async_io.total = iosb->Information; + result->async_io.apc = apc; + } break; + } case APC_VIRTUAL_ALLOC: result->type = call->type; addr = wine_server_get_ptr( call->virtual_alloc.addr ); diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index e44b2e303f9..0a2ac4e17c5 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1127,7 +1127,7 @@ static int WS2_recv( int fd, struct ws2_async *wsa ) * * Handler for overlapped recv() operations. */ -static NTSTATUS WS2_async_recv( void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status, ULONG *total ) +static NTSTATUS WS2_async_recv( void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status, void **apc) { ws2_async* wsa = user; int result = 0, fd; @@ -1163,7 +1163,8 @@ static NTSTATUS WS2_async_recv( void* user, IO_STATUS_BLOCK* iosb, NTSTATUS stat if (status != STATUS_PENDING) { iosb->u.Status = status; - iosb->Information = *total = result; + iosb->Information = result; + *apc = ws2_async_apc; } return status; } @@ -1228,7 +1229,7 @@ static int WS2_send( int fd, struct ws2_async *wsa ) * * Handler for overlapped send() operations. */ -static NTSTATUS WS2_async_send(void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status, ULONG *total ) +static NTSTATUS WS2_async_send(void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status, void **apc) { ws2_async* wsa = user; int result = 0, fd; @@ -1273,7 +1274,8 @@ static NTSTATUS WS2_async_send(void* user, IO_STATUS_BLOCK* iosb, NTSTATUS statu if (status != STATUS_PENDING) { iosb->u.Status = status; - iosb->Information = *total = result; + iosb->Information = result; + *apc = ws2_async_apc; } return status; } @@ -1283,7 +1285,7 @@ static NTSTATUS WS2_async_send(void* user, IO_STATUS_BLOCK* iosb, NTSTATUS statu * * Handler for shutdown() operations on overlapped sockets. */ -static NTSTATUS WS2_async_shutdown( void* user, PIO_STATUS_BLOCK iosb, NTSTATUS status, ULONG *total ) +static NTSTATUS WS2_async_shutdown( void* user, PIO_STATUS_BLOCK iosb, NTSTATUS status, void **apc ) { ws2_async* wsa = user; int fd, err = 1; @@ -1303,8 +1305,8 @@ static NTSTATUS WS2_async_shutdown( void* user, PIO_STATUS_BLOCK iosb, NTSTATUS status = err ? wsaErrno() : STATUS_SUCCESS; break; } - *total = 0; iosb->u.Status = status; + *apc = ws2_async_apc; return status; } @@ -1335,7 +1337,6 @@ static int WS2_register_async_shutdown( SOCKET s, int type ) req->async.callback = WS2_async_shutdown; req->async.iosb = &wsa->local_iosb; req->async.arg = wsa; - req->async.apc = ws2_async_apc; req->async.cvalue = 0; status = wine_server_call( req ); } @@ -2788,7 +2789,6 @@ INT WINAPI WSASendTo( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, req->async.callback = WS2_async_send; req->async.iosb = iosb; req->async.arg = wsa; - req->async.apc = ws2_async_apc; req->async.event = wine_server_obj_handle( lpCompletionRoutine ? 0 : lpOverlapped->hEvent ); req->async.cvalue = cvalue; err = wine_server_call( req ); @@ -4314,7 +4314,6 @@ INT WINAPI WSARecvFrom( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, req->async.callback = WS2_async_recv; req->async.iosb = iosb; req->async.arg = wsa; - req->async.apc = ws2_async_apc; req->async.event = wine_server_obj_handle( lpCompletionRoutine ? 0 : lpOverlapped->hEvent ); req->async.cvalue = cvalue; err = wine_server_call( req ); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 91656dfd4d4..14c915ebb99 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -169,7 +169,6 @@ typedef struct void *callback; void *iosb; void *arg; - void *apc; apc_param_t cvalue; } async_data_t; @@ -287,7 +286,7 @@ typedef union struct { enum apc_type type; - unsigned int (*func)(void*, void*, unsigned int, unsigned int *); + unsigned int (*func)(void*, void*, unsigned int, void **); void *user; void *sb; unsigned int status; @@ -377,6 +376,7 @@ typedef union { enum apc_type type; unsigned int status; + void *apc; unsigned int total; } async_io; struct @@ -5060,6 +5060,6 @@ union generic_reply struct set_window_layered_info_reply set_window_layered_info_reply; }; -#define SERVER_PROTOCOL_VERSION 371 +#define SERVER_PROTOCOL_VERSION 372 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/async.c b/server/async.c index f3186d77255..3a9ae34a566 100644 --- a/server/async.c +++ b/server/async.c @@ -234,7 +234,7 @@ void async_set_timeout( struct async *async, timeout_t timeout, unsigned int sta } /* store the result of the client-side async callback */ -void async_set_result( struct object *obj, unsigned int status, unsigned int total ) +void async_set_result( struct object *obj, unsigned int status, unsigned int total, void *apc ) { struct async *async = (struct async *)obj; @@ -260,12 +260,12 @@ void async_set_result( struct object *obj, unsigned int status, unsigned int tot async->status = status; if (async->completion && async->data.cvalue) add_completion( async->completion, async->comp_key, async->data.cvalue, status, total ); - if (async->data.apc) + if (apc) { apc_call_t data; memset( &data, 0, sizeof(data) ); data.type = APC_USER; - data.user.func = async->data.apc; + data.user.func = apc; data.user.args[0] = (apc_param_t)(unsigned long)async->data.arg; data.user.args[1] = (apc_param_t)(unsigned long)async->data.iosb; data.user.args[2] = 0; diff --git a/server/file.h b/server/file.h index 3abfc0289f4..c735feaf638 100644 --- a/server/file.h +++ b/server/file.h @@ -138,7 +138,7 @@ extern void free_async_queue( struct async_queue *queue ); extern struct async *create_async( struct thread *thread, struct async_queue *queue, const async_data_t *data ); extern void async_set_timeout( struct async *async, timeout_t timeout, unsigned int status ); -extern void async_set_result( struct object *obj, unsigned int status, unsigned int total ); +extern void async_set_result( struct object *obj, unsigned int status, unsigned int total, void *apc ); extern int async_waiting( struct async_queue *queue ); extern void async_terminate( struct async *async, unsigned int status ); extern void async_wake_up( struct async_queue *queue, unsigned int status ); diff --git a/server/protocol.def b/server/protocol.def index 397c54e1d7f..444178bca4c 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -185,7 +185,6 @@ typedef struct void *callback; /* client-side callback to call upon end of async */ void *iosb; /* I/O status block in client addr space */ void *arg; /* opaque user data to pass to callback */ - void *apc; /* user apc to call */ apc_param_t cvalue; /* completion value to use for completion events */ } async_data_t; @@ -303,7 +302,7 @@ typedef union struct { enum apc_type type; /* APC_ASYNC_IO */ - unsigned int (*func)(void*, void*, unsigned int, unsigned int *); + unsigned int (*func)(void*, void*, unsigned int, void **); void *user; /* user pointer */ void *sb; /* status block */ unsigned int status; /* I/O status */ @@ -393,6 +392,7 @@ typedef union { enum apc_type type; /* APC_ASYNC_IO */ unsigned int status; /* new status of async operation */ + void *apc; /* user APC to call */ unsigned int total; /* bytes transferred */ } async_io; struct diff --git a/server/thread.c b/server/thread.c index 9681c1ab58e..bc4e9e942a5 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1196,7 +1196,9 @@ DECL_HANDLER(select) } else if (apc->result.type == APC_ASYNC_IO) { - if (apc->owner) async_set_result( apc->owner, apc->result.async_io.status, apc->result.async_io.total ); + if (apc->owner) + async_set_result( apc->owner, apc->result.async_io.status, + apc->result.async_io.total, apc->result.async_io.apc ); } wake_up( &apc->obj, 0 ); close_handle( current->process, req->prev_apc ); diff --git a/server/trace.c b/server/trace.c index 60b23183c3d..56b1b2f4079 100644 --- a/server/trace.c +++ b/server/trace.c @@ -218,8 +218,8 @@ static void dump_apc_result( const apc_result_t *result ) case APC_NONE: break; case APC_ASYNC_IO: - fprintf( stderr, "APC_ASYNC_IO,status=%s", - get_status_name( result->async_io.status ) ); + fprintf( stderr, "APC_ASYNC_IO,status=%s,total=%u,apc=%p", + get_status_name( result->async_io.status ), result->async_io.total, result->async_io.apc ); break; case APC_VIRTUAL_ALLOC: fprintf( stderr, "APC_VIRTUAL_ALLOC,status=%s,addr=", @@ -301,9 +301,10 @@ static void dump_apc_result( const apc_result_t *result ) static void dump_async_data( const async_data_t *data ) { - fprintf( stderr, "{handle=%04x,event=%04x,callback=%p,iosb=%p,arg=%p,apc=%p,cvalue=}", - data->handle, data->event, data->callback, data->iosb, data->arg, data->apc ); + fprintf( stderr, "{handle=%04x,event=%04x,callback=%p,iosb=%p,arg=%p,cvalue=", + data->handle, data->event, data->callback, data->iosb, data->arg ); dump_uint64( &data->cvalue ); + fputc( '}', stderr ); } static void dump_luid( const luid_t *luid )