diff --git a/dlls/ntdll/directory.c b/dlls/ntdll/directory.c index ef6802bd043..6af412973d5 100644 --- a/dlls/ntdll/directory.c +++ b/dlls/ntdll/directory.c @@ -2169,7 +2169,7 @@ struct read_changes_info ULONG BufferSize; }; -static void WINAPI read_changes_apc( void *user, PIO_STATUS_BLOCK iosb, ULONG status ) +static NTSTATUS read_changes_apc( void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status ) { struct read_changes_info *info = user; char path[PATH_MAX]; @@ -2222,6 +2222,7 @@ static void WINAPI read_changes_apc( void *user, PIO_STATUS_BLOCK iosb, ULONG st iosb->Information = len; RtlFreeHeap( GetProcessHeap(), 0, info ); + return ret; } #define FILE_NOTIFY_ALL ( \ diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c index 6584a92db64..f3ba690fcfe 100644 --- a/dlls/ntdll/file.c +++ b/dlls/ntdll/file.c @@ -236,8 +236,8 @@ NTSTATUS WINAPI NtCreateFile( PHANDLE handle, ACCESS_MASK access, POBJECT_ATTRIB /*********************************************************************** * Asynchronous file I/O * */ -static void WINAPI FILE_AsyncReadService(void*, PIO_STATUS_BLOCK, ULONG); -static void WINAPI FILE_AsyncWriteService(void*, PIO_STATUS_BLOCK, ULONG); +static NTSTATUS FILE_AsyncReadService(void*, PIO_STATUS_BLOCK, NTSTATUS); +static NTSTATUS FILE_AsyncWriteService(void*, PIO_STATUS_BLOCK, NTSTATUS); typedef struct async_fileio { @@ -264,13 +264,12 @@ static void fileio_terminate(async_fileio *fileio, IO_STATUS_BLOCK* iosb, NTSTAT static ULONG fileio_queue_async(async_fileio* fileio, IO_STATUS_BLOCK* iosb, BOOL do_read) { - PIO_APC_ROUTINE apc = do_read ? FILE_AsyncReadService : FILE_AsyncWriteService; - NTSTATUS status; + NTSTATUS status; SERVER_START_REQ( register_async ) { req->handle = fileio->handle; - req->async.callback = apc; + req->async.callback = do_read ? FILE_AsyncReadService : FILE_AsyncWriteService; req->async.iosb = iosb; req->async.arg = fileio; req->async.apc = fileio->apc; @@ -338,7 +337,7 @@ NTSTATUS FILE_GetNtStatus(void) /*********************************************************************** * FILE_AsyncReadService (INTERNAL) */ -static void WINAPI FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, ULONG status) +static NTSTATUS FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, NTSTATUS status) { async_fileio *fileio = (async_fileio*)user; int fd, needs_close, result; @@ -351,10 +350,8 @@ static void WINAPI FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, ULON /* check to see if the data is ready (non-blocking) */ if ((status = server_get_unix_fd( fileio->handle, FILE_READ_DATA, &fd, &needs_close, NULL, NULL ))) - { - fileio_terminate(fileio, iosb, status); break; - } + result = read(fd, &fileio->buffer[fileio->already], fileio->count - fileio->already); if (needs_close) close( fd ); @@ -390,16 +387,15 @@ static void WINAPI FILE_AsyncReadService(void *user, PIO_STATUS_BLOCK iosb, ULON result, fileio->already, fileio->count, (status == STATUS_SUCCESS) ? "success" : "pending"); } - /* queue another async operation ? */ - if (status == STATUS_PENDING) - fileio_queue_async(fileio, iosb, TRUE); - else - fileio_terminate(fileio, iosb, status); break; - default: - fileio_terminate(fileio, iosb, status); + + case STATUS_TIMEOUT: + case STATUS_IO_TIMEOUT: + if (fileio->already) status = STATUS_SUCCESS; break; } + if (status != STATUS_PENDING) fileio_terminate(fileio, iosb, status); + return status; } struct io_timeouts @@ -664,9 +660,9 @@ done: /*********************************************************************** * FILE_AsyncWriteService (INTERNAL) */ -static void WINAPI FILE_AsyncWriteService(void *ovp, IO_STATUS_BLOCK *iosb, ULONG status) +static NTSTATUS FILE_AsyncWriteService(void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status) { - async_fileio *fileio = (async_fileio *) ovp; + async_fileio *fileio = user; int result, fd, needs_close; enum server_fd_type type; @@ -678,10 +674,8 @@ static void WINAPI FILE_AsyncWriteService(void *ovp, IO_STATUS_BLOCK *iosb, ULON /* write some data (non-blocking) */ if ((status = server_get_unix_fd( fileio->handle, FILE_WRITE_DATA, &fd, &needs_close, &type, NULL ))) - { - fileio_terminate(fileio, iosb, status); break; - } + if (!fileio->count && (type == FD_TYPE_MAILSLOT || type == FD_TYPE_PIPE || type == FD_TYPE_SOCKET)) result = send( fd, fileio->buffer, 0, 0 ); else @@ -700,15 +694,15 @@ static void WINAPI FILE_AsyncWriteService(void *ovp, IO_STATUS_BLOCK *iosb, ULON status = (fileio->already < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS; TRACE("wrote %d more bytes %u/%u so far\n", result, fileio->already, fileio->count); } - if (status == STATUS_PENDING) - fileio_queue_async(fileio, iosb, FALSE); - else - fileio_terminate(fileio, iosb, status); break; - default: - fileio_terminate(fileio, iosb, status); + + case STATUS_TIMEOUT: + case STATUS_IO_TIMEOUT: + if (fileio->already) status = STATUS_SUCCESS; break; } + if (status != STATUS_PENDING) fileio_terminate(fileio, iosb, status); + return status; } /****************************************************************************** @@ -937,10 +931,11 @@ NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event, /*********************************************************************** * pipe_completion_wait (Internal) */ -static void CALLBACK pipe_completion_wait(void *arg, PIO_STATUS_BLOCK iosb, ULONG status) +static NTSTATUS pipe_completion_wait(void *arg, PIO_STATUS_BLOCK iosb, NTSTATUS status) { TRACE("for %p, status=%08x\n", iosb, status); iosb->u.Status = status; + return status; } /************************************************************************** diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index 72d73bb9e66..b2f4a278713 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -680,10 +680,12 @@ static BOOL invoke_apc( const apc_call_t *call, apc_result_t *result ) break; } case APC_ASYNC_IO: - NtCurrentTeb()->num_async_io--; - call->async_io.func( call->async_io.user, call->async_io.sb, call->async_io.status ); result->type = call->type; - result->async_io.status = ((IO_STATUS_BLOCK *)call->async_io.sb)->u.Status; + result->async_io.status = call->async_io.func( call->async_io.user, + call->async_io.sb, + call->async_io.status ); + if (result->async_io.status != STATUS_PENDING) + NtCurrentTeb()->num_async_io--; break; case APC_VIRTUAL_ALLOC: result->type = call->type; diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 87d4afdf039..283a145e583 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -1072,9 +1072,9 @@ static void ws2_async_terminate(ws2_async* as, IO_STATUS_BLOCK* iosb, NTSTATUS s * WS2_make_async (INTERNAL) */ -static void WINAPI WS2_async_recv(void*, IO_STATUS_BLOCK*, ULONG); -static void WINAPI WS2_async_send(void*, IO_STATUS_BLOCK*, ULONG); -static void WINAPI WS2_async_shutdown( void*, IO_STATUS_BLOCK*, ULONG); +static NTSTATUS WS2_async_recv(void*, IO_STATUS_BLOCK*, NTSTATUS); +static NTSTATUS WS2_async_send(void*, IO_STATUS_BLOCK*, NTSTATUS); +static NTSTATUS WS2_async_shutdown( void*, IO_STATUS_BLOCK*, NTSTATUS); static inline struct ws2_async* WS2_make_async(SOCKET s, enum ws2_mode mode, struct iovec *iovec, DWORD dwBufferCount, @@ -1137,7 +1137,7 @@ error: static ULONG ws2_queue_async(struct ws2_async* wsa, IO_STATUS_BLOCK* iosb) { - PIO_APC_ROUTINE apc; + NTSTATUS (*apc)(void *, IO_STATUS_BLOCK *, NTSTATUS); int type; NTSTATUS status; @@ -1239,10 +1239,10 @@ out: * * Handler for overlapped recv() operations. */ -static void WINAPI WS2_async_recv( void* ovp, IO_STATUS_BLOCK* iosb, ULONG status) +static NTSTATUS WS2_async_recv( void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status) { - ws2_async* wsa = (ws2_async*) ovp; - int result, fd, err; + ws2_async* wsa = user; + int result = 0, fd, err; TRACE( "(%p %p %x)\n", wsa, iosb, status ); @@ -1250,10 +1250,8 @@ static void WINAPI WS2_async_recv( void* ovp, IO_STATUS_BLOCK* iosb, ULONG statu { case STATUS_ALERTED: if ((status = wine_server_handle_to_fd( wsa->hSocket, FILE_READ_DATA, &fd, NULL ) )) - { - ws2_async_terminate(wsa, iosb, status, 0); break; - } + result = WS2_recv( fd, wsa->iovec, wsa->n_iovecs, wsa->addr, wsa->addrlen.ptr, &wsa->flags ); wine_server_release_fd( wsa->hSocket, fd ); @@ -1279,15 +1277,10 @@ static void WINAPI WS2_async_recv( void* ovp, IO_STATUS_BLOCK* iosb, ULONG statu TRACE( "Error: %x\n", err ); } } - if (status == STATUS_PENDING) - ws2_queue_async(wsa, iosb); - else - ws2_async_terminate(wsa, iosb, status, result); - break; - default: - ws2_async_terminate(wsa, iosb, status, 0); break; } + if (status != STATUS_PENDING) ws2_async_terminate(wsa, iosb, status, result); + return status; } /*********************************************************************** @@ -1364,10 +1357,10 @@ out: * * Handler for overlapped send() operations. */ -static void WINAPI WS2_async_send(void* as, IO_STATUS_BLOCK* iosb, ULONG status) +static NTSTATUS WS2_async_send(void* user, IO_STATUS_BLOCK* iosb, NTSTATUS status) { - ws2_async* wsa = (ws2_async*) as; - int result, fd; + ws2_async* wsa = user; + int result = 0, fd; TRACE( "(%p %p %x)\n", wsa, iosb, status ); @@ -1375,10 +1368,8 @@ static void WINAPI WS2_async_send(void* as, IO_STATUS_BLOCK* iosb, ULONG status) { case STATUS_ALERTED: if ((status = wine_server_handle_to_fd( wsa->hSocket, FILE_WRITE_DATA, &fd, NULL ) )) - { - ws2_async_terminate(wsa, iosb, status, 0); break; - } + /* check to see if the data is ready (non-blocking) */ result = WS2_send( fd, wsa->iovec, wsa->n_iovecs, wsa->addr, wsa->addrlen.val, wsa->flags ); wine_server_release_fd( wsa->hSocket, fd ); @@ -1407,16 +1398,10 @@ static void WINAPI WS2_async_send(void* as, IO_STATUS_BLOCK* iosb, ULONG status) TRACE( "Error: %x\n", err ); } } - if (status == STATUS_PENDING) - ws2_queue_async(wsa, iosb); - else - ws2_async_terminate(wsa, iosb, status, result); - break; - default: - ws2_async_terminate(wsa, iosb, status, 0); break; } - + if (status != STATUS_PENDING) ws2_async_terminate(wsa, iosb, status, result); + return status; } /*********************************************************************** @@ -1424,9 +1409,9 @@ static void WINAPI WS2_async_send(void* as, IO_STATUS_BLOCK* iosb, ULONG status) * * Handler for shutdown() operations on overlapped sockets. */ -static void WINAPI WS2_async_shutdown( void* as, PIO_STATUS_BLOCK iosb, ULONG status ) +static NTSTATUS WS2_async_shutdown( void* user, PIO_STATUS_BLOCK iosb, NTSTATUS status ) { - ws2_async* wsa = (ws2_async*) as; + ws2_async* wsa = user; int fd, err = 1; TRACE( "async %p %d\n", wsa, wsa->mode ); @@ -1434,10 +1419,8 @@ static void WINAPI WS2_async_shutdown( void* as, PIO_STATUS_BLOCK iosb, ULONG st { case STATUS_ALERTED: if ((status = wine_server_handle_to_fd( wsa->hSocket, 0, &fd, NULL ) )) - { - ws2_async_terminate(wsa, iosb, status, 0); break; - } + switch ( wsa->mode ) { case ws2m_sd_read: err = shutdown( fd, 0 ); break; @@ -1446,13 +1429,10 @@ static void WINAPI WS2_async_shutdown( void* as, PIO_STATUS_BLOCK iosb, ULONG st } wine_server_release_fd( wsa->hSocket, fd ); status = err ? wsaErrno() : STATUS_SUCCESS; - ws2_async_terminate(wsa, iosb, status, 0); - break; - default: - ws2_async_terminate(wsa, iosb, status, 0); break; } - + ws2_async_terminate(wsa, iosb, status, 0); + return status; } /*********************************************************************** diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 2c486e2326a..ce63f0f1c39 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -263,7 +263,7 @@ typedef union struct { enum apc_type type; - void (__stdcall *func)(void*, void*, unsigned int); + unsigned int (*func)(void*, void*, unsigned int); void *user; void *sb; unsigned int status; @@ -4677,6 +4677,6 @@ union generic_reply struct allocate_locally_unique_id_reply allocate_locally_unique_id_reply; }; -#define SERVER_PROTOCOL_VERSION 290 +#define SERVER_PROTOCOL_VERSION 291 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/async.c b/server/async.c index e0877b2e062..8b3049cd476 100644 --- a/server/async.c +++ b/server/async.c @@ -38,6 +38,7 @@ struct async struct thread *thread; /* owning thread */ struct list queue_entry; /* entry in async queue list */ struct async_queue *queue; /* queue containing this async */ + unsigned int status; /* current status */ struct timeout_user *timeout; unsigned int timeout_status; /* status to report upon timeout */ struct event *event; @@ -92,6 +93,11 @@ static const struct object_ops async_queue_ops = }; +static inline void async_reselect( struct async *async ) +{ + if (async->queue->fd) fd_reselect_async( async->queue->fd, async->queue ); +} + static void async_dump( struct object *obj, int verbose ) { struct async *async = (struct async *)obj; @@ -104,10 +110,12 @@ static void async_destroy( struct object *obj ) struct async *async = (struct async *)obj; assert( obj->ops == &async_ops ); + list_remove( &async->queue_entry ); + async_reselect( async ); + if (async->timeout) remove_timeout_user( async->timeout ); if (async->event) release_object( async->event ); release_object( async->queue ); - async->queue = NULL; release_object( async->thread ); } @@ -119,11 +127,19 @@ static void async_queue_dump( struct object *obj, int verbose ) } /* notifies client thread of new status of its async request */ -/* destroys the server side of it */ static void async_terminate( struct async *async, unsigned int status ) { apc_call_t data; + assert( status != STATUS_PENDING ); + + if (async->status != STATUS_PENDING) + { + /* already terminated, just update status */ + async->status = status; + return; + } + memset( &data, 0, sizeof(data) ); data.type = APC_ASYNC_IO; data.async_io.func = async->data.callback; @@ -131,11 +147,9 @@ static void async_terminate( struct async *async, unsigned int status ) data.async_io.sb = async->data.iosb; data.async_io.status = status; thread_queue_apc( async->thread, &async->obj, &data ); - - if (async->timeout) remove_timeout_user( async->timeout ); - async->timeout = NULL; - list_remove( &async->queue_entry ); - release_object( async ); + async->status = status; + async_reselect( async ); + release_object( async ); /* so that it gets destroyed when the async is done */ } /* callback for timeout on an async request */ @@ -184,11 +198,12 @@ struct async *create_async( struct thread *thread, struct async_queue *queue, co return NULL; } - async->thread = (struct thread *)grab_object( thread ); - async->event = event; - async->data = *data; + async->thread = (struct thread *)grab_object( thread ); + async->event = event; + async->status = STATUS_PENDING; + async->data = *data; async->timeout = NULL; - async->queue = (struct async_queue *)grab_object( queue ); + async->queue = (struct async_queue *)grab_object( queue ); list_add_tail( &queue->queue, &async->queue_entry ); grab_object( async ); @@ -214,12 +229,24 @@ void async_set_result( struct object *obj, unsigned int status ) if (obj->ops != &async_ops) return; /* in case the client messed up the APC results */ - if (status == STATUS_PENDING) + assert( async->status != STATUS_PENDING ); /* it must have been woken up if we get a result */ + + if (status == STATUS_PENDING) /* restart it */ { - /* FIXME: restart the async operation */ + status = async->status; + async->status = STATUS_PENDING; + grab_object( async ); + + if (status != STATUS_ALERTED) /* it was terminated in the meantime */ + async_terminate( async, status ); + else + async_reselect( async ); } else { + if (async->timeout) remove_timeout_user( async->timeout ); + async->timeout = NULL; + async->status = status; if (async->data.apc) { apc_call_t data; @@ -238,7 +265,13 @@ void async_set_result( struct object *obj, unsigned int status ) /* check if an async operation is waiting to be alerted */ int async_waiting( struct async_queue *queue ) { - return queue && !list_empty( &queue->queue ); + struct list *ptr; + struct async *async; + + if (!queue) return 0; + if (!(ptr = list_head( &queue->queue ))) return 0; + async = LIST_ENTRY( ptr, struct async, queue_entry ); + return async->status == STATUS_PENDING; } /* wake up async operations on the queue */ diff --git a/server/change.c b/server/change.c index 33034da7b5d..a12c68be103 100644 --- a/server/change.c +++ b/server/change.c @@ -183,12 +183,13 @@ static enum server_fd_type dir_get_info( struct fd *fd, int *flags ); static const struct fd_ops dir_fd_ops = { - dir_get_poll_events, /* get_poll_events */ - default_poll_event, /* poll_event */ - no_flush, /* flush */ - dir_get_info, /* get_file_info */ - default_fd_queue_async, /* queue_async */ - default_fd_cancel_async /* cancel_async */ + dir_get_poll_events, /* get_poll_events */ + default_poll_event, /* poll_event */ + no_flush, /* flush */ + dir_get_info, /* get_file_info */ + default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async /* cancel_async */ }; static struct list change_list = LIST_INIT(change_list); @@ -516,12 +517,13 @@ static void inotify_poll_event( struct fd *fd, int event ); static const struct fd_ops inotify_fd_ops = { - inotify_get_poll_events, /* get_poll_events */ - inotify_poll_event, /* poll_event */ - no_flush, /* flush */ - no_get_file_info, /* get_file_info */ - default_fd_queue_async, /* queue_async */ - default_fd_cancel_async, /* cancel_async */ + inotify_get_poll_events, /* get_poll_events */ + inotify_poll_event, /* poll_event */ + no_flush, /* flush */ + no_get_file_info, /* get_file_info */ + default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ + default_fd_cancel_async, /* cancel_async */ }; static int inotify_get_poll_events( struct fd *fd ) diff --git a/server/fd.c b/server/fd.c index 3a044b21832..504512e392f 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1638,6 +1638,7 @@ int check_fd_events( struct fd *fd, int events ) struct pollfd pfd; if (fd->unix_fd == -1) return POLLERR; + if (fd->inode) return events; /* regular files are always signaled */ pfd.fd = fd->unix_fd; pfd.events = events; @@ -1666,12 +1667,12 @@ int default_fd_get_poll_events( struct fd *fd ) /* default handler for poll() events */ void default_poll_event( struct fd *fd, int event ) { - if (event & POLLIN) async_wake_up( fd->read_q, STATUS_ALERTED ); - if (event & POLLOUT) async_wake_up( fd->write_q, STATUS_ALERTED ); + if (event & (POLLIN | POLLERR | POLLHUP)) async_wake_up( fd->read_q, STATUS_ALERTED ); + if (event & (POLLOUT | POLLERR | POLLHUP)) async_wake_up( fd->write_q, STATUS_ALERTED ); /* if an error occurred, stop polling this fd to avoid busy-looping */ if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 ); - else set_fd_events( fd, fd->fd_ops->get_poll_events( fd ) ); + else if (!fd->inode) set_fd_events( fd, fd->fd_ops->get_poll_events( fd ) ); } struct async *fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) @@ -1725,6 +1726,11 @@ void fd_async_wake_up( struct fd *fd, int type, unsigned int status ) } } +void fd_reselect_async( struct fd *fd, struct async_queue *queue ) +{ + fd->fd_ops->reselect_async( fd, queue ); +} + void default_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ) { int flags; @@ -1743,6 +1749,19 @@ void default_fd_queue_async( struct fd *fd, const async_data_t *data, int type, } } +/* default reselect_async() fd routine */ +void default_fd_reselect_async( struct fd *fd, struct async_queue *queue ) +{ + if (queue != fd->wait_q) + { + int poll_events = fd->fd_ops->get_poll_events( fd ); + int events = check_fd_events( fd, poll_events ); + if (events) fd->fd_ops->poll_event( fd, events ); + else set_fd_events( fd, poll_events ); + } +} + +/* default cancel_async() fd routine */ void default_fd_cancel_async( struct fd *fd ) { async_wake_up( fd->read_q, STATUS_CANCELLED ); diff --git a/server/file.c b/server/file.c index edc92f72a59..e038af37212 100644 --- a/server/file.c +++ b/server/file.c @@ -96,6 +96,7 @@ static const struct fd_ops file_fd_ops = file_flush, /* flush */ file_get_info, /* get_file_info */ default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ }; diff --git a/server/file.h b/server/file.h index 096b9df7741..54d2d730920 100644 --- a/server/file.h +++ b/server/file.h @@ -41,6 +41,8 @@ struct fd_ops enum server_fd_type (*get_file_info)(struct fd *fd, int *flags); /* queue an async operation */ void (*queue_async)(struct fd *, const async_data_t *data, int type, int count); + /* selected events for async i/o need an update */ + void (*reselect_async)( struct fd *, struct async_queue *queue ); /* cancel an async operation */ void (*cancel_async)(struct fd *); }; @@ -70,7 +72,9 @@ extern int default_fd_get_poll_events( struct fd *fd ); extern void default_poll_event( struct fd *fd, int event ); extern struct async *fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); extern void fd_async_wake_up( struct fd *fd, int type, unsigned int status ); +extern void fd_reselect_async( struct fd *fd, struct async_queue *queue ); extern void default_fd_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); +extern void default_fd_reselect_async( struct fd *fd, struct async_queue *queue ); extern void default_fd_cancel_async( struct fd *fd ); extern void no_flush( struct fd *fd, struct event **event ); extern enum server_fd_type no_get_file_info( struct fd *fd, int *flags ); diff --git a/server/mailslot.c b/server/mailslot.c index 2898d1a8070..d130f6e6364 100644 --- a/server/mailslot.c +++ b/server/mailslot.c @@ -97,6 +97,7 @@ static const struct fd_ops mailslot_fd_ops = no_flush, /* flush */ mailslot_get_info, /* get_file_info */ mailslot_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ }; @@ -185,6 +186,7 @@ static const struct fd_ops mailslot_device_fd_ops = no_flush, /* flush */ mailslot_device_get_file_info, /* get_file_info */ default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ }; diff --git a/server/named_pipe.c b/server/named_pipe.c index a736d83e453..4b238166cd9 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -158,11 +158,12 @@ static const struct object_ops pipe_server_ops = static const struct fd_ops pipe_server_fd_ops = { - default_fd_get_poll_events, /* get_poll_events */ + default_fd_get_poll_events, /* get_poll_events */ default_poll_event, /* poll_event */ pipe_server_flush, /* flush */ pipe_server_get_info, /* get_file_info */ default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async, /* cancel_async */ }; @@ -197,6 +198,7 @@ static const struct fd_ops pipe_client_fd_ops = pipe_client_flush, /* flush */ pipe_client_get_info, /* get_file_info */ default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ }; @@ -233,6 +235,7 @@ static const struct fd_ops named_pipe_device_fd_ops = no_flush, /* flush */ named_pipe_device_get_file_info, /* get_file_info */ default_fd_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ }; diff --git a/server/process.c b/server/process.c index f947d6dfd4e..f06f5f46ae6 100644 --- a/server/process.c +++ b/server/process.c @@ -87,6 +87,7 @@ static const struct fd_ops process_fd_ops = no_flush, /* flush */ no_get_file_info, /* get_file_info */ no_queue_async, /* queue_async */ + NULL, /* reselect_async */ no_cancel_async /* cancel async */ }; diff --git a/server/protocol.def b/server/protocol.def index 48d1096589c..e1e504f41c5 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -279,7 +279,7 @@ typedef union struct { enum apc_type type; /* APC_ASYNC_IO */ - void (__stdcall *func)(void*, void*, unsigned int); + unsigned int (*func)(void*, void*, unsigned int); void *user; /* user pointer */ void *sb; /* status block */ unsigned int status; /* I/O status */ diff --git a/server/queue.c b/server/queue.c index 4e66f990e2b..22f4dcd36a6 100644 --- a/server/queue.c +++ b/server/queue.c @@ -169,6 +169,7 @@ static const struct fd_ops msg_queue_fd_ops = no_flush, /* flush */ no_get_file_info, /* get_file_info */ no_queue_async, /* queue_async */ + NULL, /* reselect_async */ no_cancel_async /* cancel async */ }; diff --git a/server/request.c b/server/request.c index 20fe4356fa6..7dac5d11012 100644 --- a/server/request.c +++ b/server/request.c @@ -109,6 +109,7 @@ static const struct fd_ops master_socket_fd_ops = no_flush, /* flush */ no_get_file_info, /* get_file_info */ no_queue_async, /* queue_async */ + NULL, /* reselect_async */ no_cancel_async /* cancel_async */ }; diff --git a/server/serial.c b/server/serial.c index 8dc1d189a86..b9a3bbda17e 100644 --- a/server/serial.c +++ b/server/serial.c @@ -109,6 +109,7 @@ static const struct fd_ops serial_fd_ops = serial_flush, /* flush */ serial_get_info, /* get_file_info */ serial_queue_async, /* queue_async */ + default_fd_reselect_async, /* reselect_async */ default_fd_cancel_async /* cancel_async */ }; diff --git a/server/signal.c b/server/signal.c index 7b388e1305a..238edeface9 100644 --- a/server/signal.c +++ b/server/signal.c @@ -85,6 +85,7 @@ static const struct fd_ops handler_fd_ops = no_flush, /* flush */ no_get_file_info, /* get_file_info */ no_queue_async, /* queue_async */ + NULL, /* reselect_async */ no_cancel_async /* cancel_async */ }; diff --git a/server/sock.c b/server/sock.c index 90103f9a583..51109c35bed 100644 --- a/server/sock.c +++ b/server/sock.c @@ -97,6 +97,7 @@ static int sock_get_poll_events( struct fd *fd ); static void sock_poll_event( struct fd *fd, int event ); static enum server_fd_type sock_get_info( struct fd *fd, int *flags ); static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, int count ); +static void sock_reselect_async( struct fd *fd, struct async_queue *queue ); static void sock_cancel_async( struct fd *fd ); static int sock_get_error( int err ); @@ -126,6 +127,7 @@ static const struct fd_ops sock_fd_ops = no_flush, /* flush */ sock_get_info, /* get_file_info */ sock_queue_async, /* queue_async */ + sock_reselect_async, /* reselect_async */ sock_cancel_async /* cancel_async */ }; @@ -556,6 +558,13 @@ static void sock_queue_async( struct fd *fd, const async_data_t *data, int type, if ( pollev ) sock_try_event( sock, pollev ); } +static void sock_reselect_async( struct fd *fd, struct async_queue *queue ) +{ + struct sock *sock = get_fd_user( fd ); + int events = sock_reselect( sock ); + if (events) sock_try_event( sock, events ); +} + static void sock_cancel_async( struct fd *fd ) { struct sock *sock = get_fd_user( fd ); diff --git a/server/thread.c b/server/thread.c index ec1b16170fc..09e0367ce9b 100644 --- a/server/thread.c +++ b/server/thread.c @@ -132,6 +132,7 @@ static const struct fd_ops thread_fd_ops = no_flush, /* flush */ no_get_file_info, /* get_file_info */ no_queue_async, /* queue_async */ + NULL, /* reselect_async */ no_cancel_async /* cancel_async */ }; diff --git a/server/trace.c b/server/trace.c index 0d11e7cf88d..f1e5aca48fc 100644 --- a/server/trace.c +++ b/server/trace.c @@ -4161,6 +4161,7 @@ static const struct { "MEDIA_WRITE_PROTECTED", STATUS_MEDIA_WRITE_PROTECTED }, { "MUTANT_NOT_OWNED", STATUS_MUTANT_NOT_OWNED }, { "NAME_TOO_LONG", STATUS_NAME_TOO_LONG }, + { "NOTIFY_ENUM_DIR", STATUS_NOTIFY_ENUM_DIR }, { "NOT_ALL_ASSIGNED", STATUS_NOT_ALL_ASSIGNED }, { "NOT_A_DIRECTORY", STATUS_NOT_A_DIRECTORY }, { "NOT_IMPLEMENTED", STATUS_NOT_IMPLEMENTED },