server: Attempt to complete I/O request immediately in send_socket.
Make send_socket alert the async immediately if poll() call detects that there are incoming data in the socket, bypassing the wineserver's main polling loop. For sock_transmit, we always mark the async as pending and set the IOSB (unless async allocation has failed). 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
1c6c90c7e1
commit
65d12984f2
|
@ -868,11 +868,13 @@ static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi
|
|||
const struct WS_sockaddr *addr, unsigned int addr_len, int unix_flags, int force_async )
|
||||
{
|
||||
struct async_send_ioctl *async;
|
||||
ULONG_PTR information;
|
||||
HANDLE wait_handle;
|
||||
DWORD async_size;
|
||||
NTSTATUS status;
|
||||
unsigned int i;
|
||||
ULONG options;
|
||||
BOOL nonblocking, alerted;
|
||||
|
||||
async_size = offsetof( struct async_send_ioctl, iov[count] );
|
||||
|
||||
|
@ -925,16 +927,38 @@ static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi
|
|||
status = wine_server_call( req );
|
||||
wait_handle = wine_server_ptr_handle( reply->wait );
|
||||
options = reply->options;
|
||||
if ((!NT_ERROR(status) || wait_handle) && status != STATUS_PENDING)
|
||||
{
|
||||
io->Status = status;
|
||||
io->Information = async->sent_len;
|
||||
}
|
||||
nonblocking = reply->nonblocking;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (status != STATUS_PENDING) release_fileio( &async->io );
|
||||
alerted = status == STATUS_ALERTED;
|
||||
if (alerted)
|
||||
{
|
||||
status = try_send( fd, async );
|
||||
if (status == STATUS_DEVICE_NOT_READY && (force_async || !nonblocking))
|
||||
status = STATUS_PENDING;
|
||||
|
||||
/* If we had a short write and the socket is nonblocking (and we are
|
||||
* not trying to force the operation to be asynchronous), return
|
||||
* success. Windows actually refuses to send any data in this case,
|
||||
* and returns EWOULDBLOCK, but we have no way of doing that. */
|
||||
if (status == STATUS_DEVICE_NOT_READY && async->sent_len)
|
||||
status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (status != STATUS_PENDING)
|
||||
{
|
||||
information = async->sent_len;
|
||||
if (!NT_ERROR(status) || (wait_handle && !alerted))
|
||||
{
|
||||
io->Status = status;
|
||||
io->Information = information;
|
||||
}
|
||||
release_fileio( &async->io );
|
||||
}
|
||||
else information = 0;
|
||||
|
||||
if (alerted) set_async_direct_result( &wait_handle, status, information, FALSE );
|
||||
if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
|
||||
return status;
|
||||
}
|
||||
|
@ -1055,7 +1079,9 @@ static NTSTATUS sock_transmit( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
|
|||
socklen_t addr_len;
|
||||
HANDLE wait_handle;
|
||||
NTSTATUS status;
|
||||
ULONG_PTR information;
|
||||
ULONG options;
|
||||
BOOL alerted;
|
||||
|
||||
addr_len = sizeof(addr);
|
||||
if (getpeername( fd, &addr.addr, &addr_len ) != 0)
|
||||
|
@ -1105,16 +1131,40 @@ static NTSTATUS sock_transmit( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc,
|
|||
status = wine_server_call( req );
|
||||
wait_handle = wine_server_ptr_handle( reply->wait );
|
||||
options = reply->options;
|
||||
/* In theory we'd fill the iosb here, as above in sock_send(), but it's
|
||||
* actually currently impossible to get STATUS_SUCCESS. The server will
|
||||
* either return STATUS_PENDING or an error code, and in neither case
|
||||
* should the iosb be filled. */
|
||||
if (!status) FIXME( "Unhandled success status." );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (status != STATUS_PENDING) release_fileio( &async->io );
|
||||
alerted = status == STATUS_ALERTED;
|
||||
if (alerted)
|
||||
{
|
||||
status = try_transmit( fd, file_fd, async );
|
||||
if (status == STATUS_DEVICE_NOT_READY)
|
||||
status = STATUS_PENDING;
|
||||
}
|
||||
|
||||
if (status != STATUS_PENDING)
|
||||
{
|
||||
information = async->head_cursor + async->file_cursor + async->tail_cursor;
|
||||
if (!NT_ERROR(status) || wait_handle)
|
||||
{
|
||||
io->Status = status;
|
||||
io->Information = information;
|
||||
}
|
||||
release_fileio( &async->io );
|
||||
}
|
||||
else information = 0;
|
||||
|
||||
if (alerted)
|
||||
{
|
||||
set_async_direct_result( &wait_handle, status, information, TRUE );
|
||||
if (!(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)))
|
||||
{
|
||||
/* Pretend we always do async I/O. The client can always retrieve
|
||||
* the actual I/O status via the IO_STATUS_BLOCK.
|
||||
*/
|
||||
status = STATUS_PENDING;
|
||||
}
|
||||
}
|
||||
if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -1791,6 +1791,8 @@ struct send_socket_reply
|
|||
struct reply_header __header;
|
||||
obj_handle_t wait;
|
||||
unsigned int options;
|
||||
int nonblocking;
|
||||
char __pad_20[4];
|
||||
};
|
||||
|
||||
|
||||
|
@ -6284,7 +6286,7 @@ union generic_reply
|
|||
|
||||
/* ### protocol_version begin ### */
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 747
|
||||
#define SERVER_PROTOCOL_VERSION 748
|
||||
|
||||
/* ### protocol_version end ### */
|
||||
|
||||
|
|
|
@ -1467,6 +1467,7 @@ enum server_fd_type
|
|||
@REPLY
|
||||
obj_handle_t wait; /* handle to wait on for blocking send */
|
||||
unsigned int options; /* device open options */
|
||||
int nonblocking; /* is socket non-blocking? */
|
||||
@END
|
||||
|
||||
|
||||
|
|
|
@ -1056,7 +1056,8 @@ C_ASSERT( FIELD_OFFSET(struct send_socket_request, total) == 60 );
|
|||
C_ASSERT( sizeof(struct send_socket_request) == 64 );
|
||||
C_ASSERT( FIELD_OFFSET(struct send_socket_reply, wait) == 8 );
|
||||
C_ASSERT( FIELD_OFFSET(struct send_socket_reply, options) == 12 );
|
||||
C_ASSERT( sizeof(struct send_socket_reply) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct send_socket_reply, nonblocking) == 16 );
|
||||
C_ASSERT( sizeof(struct send_socket_reply) == 24 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, handle) == 12 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, signal) == 16 );
|
||||
C_ASSERT( FIELD_OFFSET(struct get_next_console_request_request, read) == 20 );
|
||||
|
|
|
@ -3526,6 +3526,25 @@ DECL_HANDLER(send_socket)
|
|||
if ((status == STATUS_PENDING || status == STATUS_DEVICE_NOT_READY) && sock->wr_shutdown)
|
||||
status = STATUS_PIPE_DISCONNECTED;
|
||||
|
||||
if ((status == STATUS_PENDING || status == STATUS_DEVICE_NOT_READY) && !async_queued( &sock->write_q ))
|
||||
{
|
||||
/* If write_q is not empty, we cannot really tell if the already queued
|
||||
* asyncs will not consume all available space; if there's no space
|
||||
* available, the current request won't be immediately satiable.
|
||||
*/
|
||||
struct pollfd pollfd;
|
||||
pollfd.fd = get_unix_fd( sock->fd );
|
||||
pollfd.events = POLLOUT;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if ((async = create_request_async( fd, get_fd_comp_flags( fd ), &req->async )))
|
||||
{
|
||||
struct send_req *send_req;
|
||||
|
@ -3548,7 +3567,7 @@ DECL_HANDLER(send_socket)
|
|||
if (timeout)
|
||||
async_set_timeout( async, timeout, STATUS_IO_TIMEOUT );
|
||||
|
||||
if (status == STATUS_PENDING)
|
||||
if (status == STATUS_PENDING || status == STATUS_ALERTED)
|
||||
{
|
||||
queue_async( &sock->write_q, async );
|
||||
sock_reselect( sock );
|
||||
|
@ -3556,6 +3575,7 @@ DECL_HANDLER(send_socket)
|
|||
|
||||
reply->wait = async_handoff( async, NULL, 0 );
|
||||
reply->options = get_fd_options( fd );
|
||||
reply->nonblocking = sock->nonblocking;
|
||||
release_object( async );
|
||||
}
|
||||
release_object( sock );
|
||||
|
|
|
@ -2053,6 +2053,7 @@ static void dump_send_socket_reply( const struct send_socket_reply *req )
|
|||
{
|
||||
fprintf( stderr, " wait=%04x", req->wait );
|
||||
fprintf( stderr, ", options=%08x", req->options );
|
||||
fprintf( stderr, ", nonblocking=%d", req->nonblocking );
|
||||
}
|
||||
|
||||
static void dump_get_next_console_request_request( const struct get_next_console_request_request *req )
|
||||
|
|
Loading…
Reference in New Issue