[RFC PATCH 4/6] server: Attempt to complete I/O request immediately in recv_socket.

Jinoh Kang jinoh.kang.kr at gmail.com
Sun Jan 23 11:30:08 CST 2022


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 at gmail.com>
---
 dlls/ntdll/unix/socket.c | 24 ++++++++++++++++++------
 server/protocol.def      |  1 +
 server/sock.c            | 23 ++++++++++++++++++++++-
 3 files changed, 41 insertions(+), 7 deletions(-)

diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c
index 71dfcdd1114..241e78888d4 100644
--- a/dlls/ntdll/unix/socket.c
+++ b/dlls/ntdll/unix/socket.c
@@ -686,6 +686,7 @@ static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, voi
     NTSTATUS status;
     unsigned int i;
     ULONG options;
+    BOOL may_restart;
 
     if (unix_flags & MSG_OOB)
     {
@@ -756,17 +757,28 @@ static NTSTATUS sock_recv( 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)
+        may_restart = reply->may_restart;
+    }
+    SERVER_END_REQ;
+
+    if (status == STATUS_ALERTED)
+    {
+        status = try_recv( fd, async, &information );
+        if (status == STATUS_DEVICE_NOT_READY && may_restart)
+            status = STATUS_PENDING;
+    }
+
+    if (status != STATUS_PENDING)
+    {
+        if (!NT_ERROR(status) || wait_handle)
         {
             io->Status = status;
             io->Information = information;
         }
+        release_fileio( &async->io );
+        status = notify_async( wait_handle, status, information );
     }
-    SERVER_END_REQ;
-
-    if (status != STATUS_PENDING) release_fileio( &async->io );
-
-    if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
+    else if (wait_handle) status = wait_async( wait_handle, options & FILE_SYNCHRONOUS_IO_ALERT );
     return status;
 }
 
diff --git a/server/protocol.def b/server/protocol.def
index c4596e0bd58..24b964e7d02 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1440,6 +1440,7 @@ enum server_fd_type
 @REPLY
     obj_handle_t wait;          /* handle to wait on for blocking recv */
     unsigned int options;       /* device open options */
+    int          may_restart;   /* May restart async? */
 @END
 
 
diff --git a/server/sock.c b/server/sock.c
index 650e67a2e0a..947de81723a 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -3397,6 +3397,7 @@ DECL_HANDLER(recv_socket)
 {
     struct sock *sock = (struct sock *)get_handle_obj( current->process, req->async.handle, 0, &sock_ops );
     unsigned int status = req->status;
+    int pending = 0;
     timeout_t timeout = 0;
     struct async *async;
     struct fd *fd;
@@ -3422,6 +3423,25 @@ DECL_HANDLER(recv_socket)
     if ((status == STATUS_PENDING || status == STATUS_DEVICE_NOT_READY) && sock->rd_shutdown)
         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). */
+            pending = status == STATUS_PENDING;
+            status = STATUS_ALERTED;
+        }
+    }
+
     sock->pending_events &= ~(req->oob ? AFD_POLL_OOB : AFD_POLL_READ);
     sock->reported_events &= ~(req->oob ? AFD_POLL_OOB : AFD_POLL_READ);
 
@@ -3438,7 +3458,7 @@ DECL_HANDLER(recv_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->read_q, async );
 
         /* always reselect; we changed reported_events above */
@@ -3446,6 +3466,7 @@ DECL_HANDLER(recv_socket)
 
         reply->wait = async_handoff( async, NULL, 0 );
         reply->options = get_fd_options( fd );
+        reply->may_restart = pending && status == STATUS_ALERTED;
         release_object( async );
     }
     release_object( sock );
-- 
2.31.1




More information about the wine-devel mailing list