Jinoh Kang : server: Attempt to complete I/O request immediately in recv_socket.

Alexandre Julliard julliard at winehq.org
Thu Feb 10 16:10:30 CST 2022


Module: wine
Branch: master
Commit: e5ce4fa917a0e679e5a9444a5e277b141918fb29
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=e5ce4fa917a0e679e5a9444a5e277b141918fb29

Author: Jinoh Kang <jinoh.kang.kr at gmail.com>
Date:   Thu Feb 10 01:17:59 2022 +0900

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 at gmail.com>
Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/ntdll/unix/socket.c       | 22 ++++++++++++++++++----
 dlls/ntdll/unix/sync.c         | 26 ++++++++++++++++++++++++++
 dlls/ntdll/unix/unix_private.h |  1 +
 include/wine/server_protocol.h |  4 +++-
 server/protocol.def            |  1 +
 server/request.h               |  3 ++-
 server/sock.c                  | 21 ++++++++++++++++++++-
 server/trace.c                 |  1 +
 8 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c
index 71dfcdd1114..03a9a93d04a 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 nonblocking, alerted;
 
     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 );
         wait_handle = wine_server_ptr_handle( reply->wait );
         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->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 );
     return status;
 }
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c
index 442243d8bcf..ee25dfd0099 100644
--- a/dlls/ntdll/unix/sync.c
+++ b/dlls/ntdll/unix/sync.c
@@ -2510,3 +2510,29 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG
 }
 
 #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;
+}
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index a79edabc37c..75f03706401 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -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_cpu_info(void) 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;
 
diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
index 5ed95a41c19..be63b290353 100644
--- a/include/wine/server_protocol.h
+++ b/include/wine/server_protocol.h
@@ -1772,6 +1772,8 @@ struct recv_socket_reply
     struct reply_header __header;
     obj_handle_t wait;
     unsigned int options;
+    int          nonblocking;
+    char __pad_20[4];
 };
 
 
@@ -6282,7 +6284,7 @@ union generic_reply
 
 /* ### protocol_version begin ### */
 
-#define SERVER_PROTOCOL_VERSION 744
+#define SERVER_PROTOCOL_VERSION 745
 
 /* ### protocol_version end ### */
 
diff --git a/server/protocol.def b/server/protocol.def
index ce05e9a38c6..5c0f9a86822 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1456,6 +1456,7 @@ enum server_fd_type
 @REPLY
     obj_handle_t wait;          /* handle to wait on for blocking recv */
     unsigned int options;       /* device open options */
+    int          nonblocking;   /* is socket non-blocking? */
 @END
 
 
diff --git a/server/request.h b/server/request.h
index 128b70fe3cf..98e23bfd4ba 100644
--- a/server/request.h
+++ b/server/request.h
@@ -1049,7 +1049,8 @@ C_ASSERT( FIELD_OFFSET(struct recv_socket_request, total) == 60 );
 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, 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, status) == 56 );
 C_ASSERT( FIELD_OFFSET(struct send_socket_request, total) == 60 );
diff --git a/server/sock.c b/server/sock.c
index 512b7c0f78e..38aaaac9e39 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -3422,6 +3422,24 @@ 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). */
+            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 +3456,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 +3464,7 @@ DECL_HANDLER(recv_socket)
 
         reply->wait = async_handoff( async, NULL, 0 );
         reply->options = get_fd_options( fd );
+        reply->nonblocking = sock->nonblocking;
         release_object( async );
     }
     release_object( sock );
diff --git a/server/trace.c b/server/trace.c
index 6b50b9d0d18..1fb39d4f997 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -2040,6 +2040,7 @@ static void dump_recv_socket_reply( const struct recv_socket_reply *req )
 {
     fprintf( stderr, " wait=%04x", req->wait );
     fprintf( stderr, ", options=%08x", req->options );
+    fprintf( stderr, ", nonblocking=%d", req->nonblocking );
 }
 
 static void dump_send_socket_request( const struct send_socket_request *req )




More information about the wine-cvs mailing list