server: Attempt to complete I/O request immediately in recv_socket.
Make recv_socket alert the async immediately if poll() call detects that there are incoming data in the socket, bypassing the wineserver's main polling loop. Signed-off-by: Jinoh Kang <jinoh.kang.kr@gmail.com> Signed-off-by: Zebediah Figura <zfigura@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
15483b1a12
commit
e5ce4fa917
|
@ -686,6 +686,7 @@ static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
ULONG options;
|
ULONG options;
|
||||||
|
BOOL nonblocking, alerted;
|
||||||
|
|
||||||
if (unix_flags & MSG_OOB)
|
if (unix_flags & MSG_OOB)
|
||||||
{
|
{
|
||||||
|
@ -756,16 +757,29 @@ static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi
|
||||||
status = wine_server_call( req );
|
status = wine_server_call( req );
|
||||||
wait_handle = wine_server_ptr_handle( reply->wait );
|
wait_handle = wine_server_ptr_handle( reply->wait );
|
||||||
options = reply->options;
|
options = reply->options;
|
||||||
if ((!NT_ERROR(status) || wait_handle) && status != STATUS_PENDING)
|
nonblocking = reply->nonblocking;
|
||||||
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
|
||||||
|
alerted = status == STATUS_ALERTED;
|
||||||
|
if (alerted)
|
||||||
|
{
|
||||||
|
status = try_recv( fd, async, &information );
|
||||||
|
if (status == STATUS_DEVICE_NOT_READY && (force_async || !nonblocking))
|
||||||
|
status = STATUS_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != STATUS_PENDING)
|
||||||
|
{
|
||||||
|
if (!NT_ERROR(status) || (wait_handle && !alerted))
|
||||||
{
|
{
|
||||||
io->Status = status;
|
io->Status = status;
|
||||||
io->Information = information;
|
io->Information = information;
|
||||||
}
|
}
|
||||||
|
release_fileio( &async->io );
|
||||||
}
|
}
|
||||||
SERVER_END_REQ;
|
|
||||||
|
|
||||||
if (status != STATUS_PENDING) release_fileio( &async->io );
|
|
||||||
|
|
||||||
|
if (alerted) set_async_direct_result( &wait_handle, status, information );
|
||||||
if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
|
if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2510,3 +2510,29 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* Notify direct completion of async and close the wait handle if it is no longer needed.
|
||||||
|
* This function is a no-op (returns status as-is) if the supplied handle is NULL.
|
||||||
|
*/
|
||||||
|
void set_async_direct_result( HANDLE *optional_handle, NTSTATUS status, ULONG_PTR information )
|
||||||
|
{
|
||||||
|
NTSTATUS ret;
|
||||||
|
|
||||||
|
if (!*optional_handle) return;
|
||||||
|
|
||||||
|
SERVER_START_REQ( set_async_direct_result )
|
||||||
|
{
|
||||||
|
req->handle = wine_server_obj_handle( *optional_handle );
|
||||||
|
req->status = status;
|
||||||
|
req->information = information;
|
||||||
|
ret = wine_server_call( req );
|
||||||
|
if (ret == STATUS_SUCCESS)
|
||||||
|
*optional_handle = wine_server_ptr_handle( reply->handle );
|
||||||
|
}
|
||||||
|
SERVER_END_REQ;
|
||||||
|
|
||||||
|
if (ret != STATUS_SUCCESS)
|
||||||
|
ERR( "cannot report I/O result back to server: %08x\n", ret );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -274,6 +274,7 @@ extern NTSTATUS get_device_info( int fd, struct _FILE_FS_DEVICE_INFORMATION *inf
|
||||||
extern void init_files(void) DECLSPEC_HIDDEN;
|
extern void init_files(void) DECLSPEC_HIDDEN;
|
||||||
extern void init_cpu_info(void) DECLSPEC_HIDDEN;
|
extern void init_cpu_info(void) DECLSPEC_HIDDEN;
|
||||||
extern void add_completion( HANDLE handle, ULONG_PTR value, NTSTATUS status, ULONG info, BOOL async ) DECLSPEC_HIDDEN;
|
extern void add_completion( HANDLE handle, ULONG_PTR value, NTSTATUS status, ULONG info, BOOL async ) DECLSPEC_HIDDEN;
|
||||||
|
extern void set_async_direct_result( HANDLE *optional_handle, NTSTATUS status, ULONG_PTR information );
|
||||||
|
|
||||||
extern void dbg_init(void) DECLSPEC_HIDDEN;
|
extern void dbg_init(void) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
|
|
|
@ -1772,6 +1772,8 @@ struct recv_socket_reply
|
||||||
struct reply_header __header;
|
struct reply_header __header;
|
||||||
obj_handle_t wait;
|
obj_handle_t wait;
|
||||||
unsigned int options;
|
unsigned int options;
|
||||||
|
int nonblocking;
|
||||||
|
char __pad_20[4];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -6282,7 +6284,7 @@ union generic_reply
|
||||||
|
|
||||||
/* ### protocol_version begin ### */
|
/* ### protocol_version begin ### */
|
||||||
|
|
||||||
#define SERVER_PROTOCOL_VERSION 744
|
#define SERVER_PROTOCOL_VERSION 745
|
||||||
|
|
||||||
/* ### protocol_version end ### */
|
/* ### protocol_version end ### */
|
||||||
|
|
||||||
|
|
|
@ -1456,6 +1456,7 @@ enum server_fd_type
|
||||||
@REPLY
|
@REPLY
|
||||||
obj_handle_t wait; /* handle to wait on for blocking recv */
|
obj_handle_t wait; /* handle to wait on for blocking recv */
|
||||||
unsigned int options; /* device open options */
|
unsigned int options; /* device open options */
|
||||||
|
int nonblocking; /* is socket non-blocking? */
|
||||||
@END
|
@END
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1049,7 +1049,8 @@ C_ASSERT( FIELD_OFFSET(struct recv_socket_request, total) == 60 );
|
||||||
C_ASSERT( sizeof(struct recv_socket_request) == 64 );
|
C_ASSERT( sizeof(struct recv_socket_request) == 64 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, wait) == 8 );
|
C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, wait) == 8 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, options) == 12 );
|
C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, options) == 12 );
|
||||||
C_ASSERT( sizeof(struct recv_socket_reply) == 16 );
|
C_ASSERT( FIELD_OFFSET(struct recv_socket_reply, nonblocking) == 16 );
|
||||||
|
C_ASSERT( sizeof(struct recv_socket_reply) == 24 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct send_socket_request, async) == 16 );
|
C_ASSERT( FIELD_OFFSET(struct send_socket_request, async) == 16 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct send_socket_request, status) == 56 );
|
C_ASSERT( FIELD_OFFSET(struct send_socket_request, status) == 56 );
|
||||||
C_ASSERT( FIELD_OFFSET(struct send_socket_request, total) == 60 );
|
C_ASSERT( FIELD_OFFSET(struct send_socket_request, total) == 60 );
|
||||||
|
|
|
@ -3422,6 +3422,24 @@ DECL_HANDLER(recv_socket)
|
||||||
if ((status == STATUS_PENDING || status == STATUS_DEVICE_NOT_READY) && sock->rd_shutdown)
|
if ((status == STATUS_PENDING || status == STATUS_DEVICE_NOT_READY) && sock->rd_shutdown)
|
||||||
status = STATUS_PIPE_DISCONNECTED;
|
status = STATUS_PIPE_DISCONNECTED;
|
||||||
|
|
||||||
|
/* NOTE: If read_q is not empty, we cannot really tell if the already queued asyncs
|
||||||
|
* NOTE: will not consume all available data; if there's no data available,
|
||||||
|
* NOTE: the current request won't be immediately satiable. */
|
||||||
|
if ((status == STATUS_PENDING || status == STATUS_DEVICE_NOT_READY) && !async_queued( &sock->read_q ))
|
||||||
|
{
|
||||||
|
struct pollfd pollfd;
|
||||||
|
pollfd.fd = get_unix_fd( sock->fd );
|
||||||
|
pollfd.events = req->oob ? POLLPRI : POLLIN;
|
||||||
|
pollfd.revents = 0;
|
||||||
|
if (poll(&pollfd, 1, 0) >= 0 && pollfd.revents)
|
||||||
|
{
|
||||||
|
/* Give the client opportunity to complete synchronously.
|
||||||
|
* If it turns out that the I/O request is not actually immediately satiable,
|
||||||
|
* the client may then choose to re-queue the async (with STATUS_PENDING). */
|
||||||
|
status = STATUS_ALERTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sock->pending_events &= ~(req->oob ? AFD_POLL_OOB : AFD_POLL_READ);
|
sock->pending_events &= ~(req->oob ? AFD_POLL_OOB : AFD_POLL_READ);
|
||||||
sock->reported_events &= ~(req->oob ? AFD_POLL_OOB : AFD_POLL_READ);
|
sock->reported_events &= ~(req->oob ? AFD_POLL_OOB : AFD_POLL_READ);
|
||||||
|
|
||||||
|
@ -3438,7 +3456,7 @@ DECL_HANDLER(recv_socket)
|
||||||
if (timeout)
|
if (timeout)
|
||||||
async_set_timeout( async, timeout, STATUS_IO_TIMEOUT );
|
async_set_timeout( async, timeout, STATUS_IO_TIMEOUT );
|
||||||
|
|
||||||
if (status == STATUS_PENDING)
|
if (status == STATUS_PENDING || status == STATUS_ALERTED)
|
||||||
queue_async( &sock->read_q, async );
|
queue_async( &sock->read_q, async );
|
||||||
|
|
||||||
/* always reselect; we changed reported_events above */
|
/* always reselect; we changed reported_events above */
|
||||||
|
@ -3446,6 +3464,7 @@ DECL_HANDLER(recv_socket)
|
||||||
|
|
||||||
reply->wait = async_handoff( async, NULL, 0 );
|
reply->wait = async_handoff( async, NULL, 0 );
|
||||||
reply->options = get_fd_options( fd );
|
reply->options = get_fd_options( fd );
|
||||||
|
reply->nonblocking = sock->nonblocking;
|
||||||
release_object( async );
|
release_object( async );
|
||||||
}
|
}
|
||||||
release_object( sock );
|
release_object( sock );
|
||||||
|
|
|
@ -2040,6 +2040,7 @@ static void dump_recv_socket_reply( const struct recv_socket_reply *req )
|
||||||
{
|
{
|
||||||
fprintf( stderr, " wait=%04x", req->wait );
|
fprintf( stderr, " wait=%04x", req->wait );
|
||||||
fprintf( stderr, ", options=%08x", req->options );
|
fprintf( stderr, ", options=%08x", req->options );
|
||||||
|
fprintf( stderr, ", nonblocking=%d", req->nonblocking );
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dump_send_socket_request( const struct send_socket_request *req )
|
static void dump_send_socket_request( const struct send_socket_request *req )
|
||||||
|
|
Loading…
Reference in New Issue