[PATCH 4/7] server: Introduce a helper to fill an iosb and terminate the async.

Zebediah Figura zfigura at codeweavers.com
Wed Sep 1 17:28:38 CDT 2021


For convenience, and to centralize the STATUS_ALERTED logic into one place.

Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 server/async.c      |  29 +++++++++++
 server/console.c    |  51 +++++++------------
 server/device.c     |  14 ++---
 server/file.h       |   2 +
 server/named_pipe.c |   4 +-
 server/sock.c       | 121 +++++++++++++++++++-------------------------
 6 files changed, 105 insertions(+), 116 deletions(-)

diff --git a/server/async.c b/server/async.c
index d45f234144d..e71dceb201b 100644
--- a/server/async.c
+++ b/server/async.c
@@ -332,6 +332,35 @@ obj_handle_t async_handoff( struct async *async, int success, data_size_t *resul
     return async->wait_handle;
 }
 
+/* complete a request-based async with a pre-allocated buffer */
+void async_request_complete( struct async *async, unsigned int status, data_size_t result,
+                             data_size_t out_size, void *out_data )
+{
+    struct iosb *iosb = async_get_iosb( async );
+
+    /* the async may have already been canceled */
+    if (iosb->status != STATUS_PENDING)
+    {
+        release_object( iosb );
+        free( out_data );
+        return;
+    }
+
+    iosb->status = status;
+    iosb->result = result;
+    iosb->out_data = out_data;
+    iosb->out_size = out_size;
+
+    release_object( iosb );
+
+    /* if the result is nonzero or there is output data, the client needs to
+     * make an extra request to retrieve them; use STATUS_ALERTED to signal
+     * this case */
+    if (result || out_data)
+        status = STATUS_ALERTED;
+    async_terminate( async, status );
+}
+
 /* set the timeout of an async operation */
 void async_set_timeout( struct async *async, timeout_t timeout, unsigned int status )
 {
diff --git a/server/console.c b/server/console.c
index 1e6f6c0f8a3..94f7c37e7c5 100644
--- a/server/console.c
+++ b/server/console.c
@@ -976,7 +976,6 @@ static int console_flush( struct fd *fd, struct async *async )
 static int screen_buffer_write( struct fd *fd, struct async *async, file_pos_t pos )
 {
     struct screen_buffer *screen_buffer = get_fd_user( fd );
-    struct iosb *iosb;
 
     if (!screen_buffer->input || !screen_buffer->input->server)
     {
@@ -984,16 +983,8 @@ static int screen_buffer_write( struct fd *fd, struct async *async, file_pos_t p
         return 0;
     }
 
-    if (!queue_host_ioctl( screen_buffer->input->server, IOCTL_CONDRV_WRITE_FILE,
-                           screen_buffer->id, async, &screen_buffer->ioctl_q ))
-        return 0;
-
-    /* we can't use default async handling, because write result is not
-     * compatible with ioctl result */
-    iosb = async_get_iosb( async );
-    iosb->result = iosb->in_size;
-    release_object( iosb );
-    return 1;
+    return queue_host_ioctl( screen_buffer->input->server, IOCTL_CONDRV_WRITE_FILE,
+                             screen_buffer->id, async, &screen_buffer->ioctl_q );
 }
 
 static int screen_buffer_ioctl( struct fd *fd, ioctl_code_t code, struct async *async )
@@ -1498,36 +1489,28 @@ DECL_HANDLER(get_next_console_request)
 
     if (ioctl)
     {
+        struct async *async = ioctl->async;
         unsigned int status = req->status;
+
         if (status == STATUS_PENDING) status = STATUS_INVALID_PARAMETER;
-        if (ioctl->async)
+        if (async)
         {
-            iosb = async_get_iosb( ioctl->async );
+            iosb = async_get_iosb( async );
             if (iosb->status == STATUS_PENDING)
             {
-                iosb->status = status;
-                iosb->out_size = min( iosb->out_size, get_req_data_size() );
-                if (iosb->out_size)
-                {
-                    if ((iosb->out_data = memdup( get_req_data(), iosb->out_size )))
-                    {
-                        iosb->result = iosb->out_size;
-                    }
-                    else if (!status)
-                    {
-                        iosb->status = STATUS_NO_MEMORY;
-                        iosb->out_size = 0;
-                    }
-                }
-                if (iosb->result) status = STATUS_ALERTED;
-            }
-            else
-            {
-                release_object( ioctl->async );
-                ioctl->async = NULL;
+                data_size_t out_size = min( iosb->out_size, get_req_data_size() );
+                data_size_t result = ioctl->code == IOCTL_CONDRV_WRITE_FILE ? iosb->in_size : out_size;
+                void *out_data;
+
+                if (!out_size || (out_data = memdup( get_req_data(), out_size )))
+                    async_request_complete( async, status, result, out_size, out_data );
+                else
+                    async_terminate( async, STATUS_NO_MEMORY );
             }
+
+            release_object( async );
         }
-        console_host_ioctl_terminate( ioctl, status );
+        free( ioctl );
         if (iosb) release_object( iosb );
 
         if (req->read)
diff --git a/server/device.c b/server/device.c
index a89c03f0fb0..96389a1459b 100644
--- a/server/device.c
+++ b/server/device.c
@@ -385,16 +385,12 @@ static void set_irp_result( struct irp_call *irp, unsigned int status,
     irp->file = NULL;
     if (irp->async)
     {
-        struct iosb *iosb = irp->iosb;
+        void *out_data;
 
-        iosb->status = status;
-        iosb->result = result;
-        iosb->out_size = min( iosb->out_size, out_size );
-        if (iosb->out_size && !(iosb->out_data = memdup( out_data, iosb->out_size )))
-            iosb->out_size = 0;
-
-        if (result) status = STATUS_ALERTED;
-        async_terminate( irp->async, status );
+        out_size = min( irp->iosb->out_size, out_size );
+        if (out_size && !(out_data = memdup( out_data, out_size )))
+            out_size = 0;
+        async_request_complete( irp->async, status, result, out_size, out_data );
         release_object( irp->async );
         irp->async = NULL;
     }
diff --git a/server/file.h b/server/file.h
index f6c5832a733..1c019a0667e 100644
--- a/server/file.h
+++ b/server/file.h
@@ -227,6 +227,8 @@ extern void async_set_completion_callback( struct async *async, async_completion
 extern void set_async_pending( struct async *async, int signal );
 extern int async_waiting( struct async_queue *queue );
 extern void async_terminate( struct async *async, unsigned int status );
+extern void async_request_complete( struct async *async, unsigned int status, data_size_t result,
+                                    data_size_t out_size, void *out_data );
 extern void async_wake_up( struct async_queue *queue, unsigned int status );
 extern struct completion *fd_get_completion( struct fd *fd, apc_param_t *p_key );
 extern void fd_copy_completion( struct fd *src, struct fd *dst );
diff --git a/server/named_pipe.c b/server/named_pipe.c
index df8c7e3170c..da3485dd2bc 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -390,9 +390,7 @@ static void wake_message( struct pipe_message *message, data_size_t result )
     message->async = NULL;
     if (!async) return;
 
-    message->iosb->status = STATUS_SUCCESS;
-    message->iosb->result = result;
-    async_terminate( async, message->iosb->result ? STATUS_ALERTED : STATUS_SUCCESS );
+    async_request_complete( async, STATUS_SUCCESS, result, 0, NULL );
     release_object( async );
 }
 
diff --git a/server/sock.c b/server/sock.c
index 50bfc08e145..00d5d47edff 100644
--- a/server/sock.c
+++ b/server/sock.c
@@ -623,7 +623,8 @@ static void free_accept_req( void *private )
 
 static void fill_accept_output( struct accept_req *req )
 {
-    struct iosb *iosb = req->iosb;
+    const data_size_t out_size = req->iosb->out_size;
+    struct async *async = req->async;
     union unix_sockaddr unix_addr;
     struct WS_sockaddr *win_addr;
     unsigned int remote_len;
@@ -632,7 +633,11 @@ static void fill_accept_output( struct accept_req *req )
     char *out_data;
     int win_len;
 
-    if (!(out_data = mem_alloc( iosb->out_size ))) return;
+    if (!(out_data = mem_alloc( out_size )))
+    {
+        async_terminate( async, get_error() );
+        return;
+    }
 
     fd = get_unix_fd( req->acceptsock->fd );
 
@@ -642,11 +647,10 @@ static void fill_accept_output( struct accept_req *req )
         {
             req->accepted = 1;
             sock_reselect( req->acceptsock );
-            set_error( STATUS_PENDING );
             return;
         }
 
-        set_error( sock_get_ntstatus( errno ) );
+        async_terminate( async, sock_get_ntstatus( errno ) );
         free( out_data );
         return;
     }
@@ -655,7 +659,7 @@ static void fill_accept_output( struct accept_req *req )
     {
         if (req->local_len < sizeof(int))
         {
-            set_error( STATUS_BUFFER_TOO_SMALL );
+            async_terminate( async, STATUS_BUFFER_TOO_SMALL );
             free( out_data );
             return;
         }
@@ -665,7 +669,7 @@ static void fill_accept_output( struct accept_req *req )
         if (getsockname( fd, &unix_addr.addr, &unix_len ) < 0 ||
             (win_len = sockaddr_from_unix( &unix_addr, win_addr, req->local_len - sizeof(int) )) < 0)
         {
-            set_error( sock_get_ntstatus( errno ) );
+            async_terminate( async, sock_get_ntstatus( errno ) );
             free( out_data );
             return;
         }
@@ -674,20 +678,17 @@ static void fill_accept_output( struct accept_req *req )
 
     unix_len = sizeof(unix_addr);
     win_addr = (struct WS_sockaddr *)(out_data + req->recv_len + req->local_len + sizeof(int));
-    remote_len = iosb->out_size - req->recv_len - req->local_len;
+    remote_len = out_size - req->recv_len - req->local_len;
     if (getpeername( fd, &unix_addr.addr, &unix_len ) < 0 ||
         (win_len = sockaddr_from_unix( &unix_addr, win_addr, remote_len - sizeof(int) )) < 0)
     {
-        set_error( sock_get_ntstatus( errno ) );
+        async_terminate( async, sock_get_ntstatus( errno ) );
         free( out_data );
         return;
     }
     memcpy( out_data + req->recv_len + req->local_len, &win_len, sizeof(int) );
 
-    iosb->status = STATUS_SUCCESS;
-    iosb->result = size;
-    iosb->out_data = out_data;
-    set_error( STATUS_ALERTED );
+    async_request_complete( req->async, STATUS_SUCCESS, size, out_size, out_data );
 }
 
 static void complete_async_accept( struct sock *sock, struct accept_req *req )
@@ -699,27 +700,37 @@ static void complete_async_accept( struct sock *sock, struct accept_req *req )
 
     if (acceptsock)
     {
-        if (!accept_into_socket( sock, acceptsock )) return;
+        if (!accept_into_socket( sock, acceptsock ))
+        {
+            async_terminate( async, get_error() );
+            return;
+        }
         fill_accept_output( req );
     }
     else
     {
-        struct iosb *iosb = req->iosb;
         obj_handle_t handle;
+        void *out_data;
 
-        if (!(acceptsock = accept_socket( sock ))) return;
+        if (!(acceptsock = accept_socket( sock )))
+        {
+            async_terminate( async, get_error() );
+            return;
+        }
         handle = alloc_handle_no_access_check( async_get_thread( async )->process, &acceptsock->obj,
                                                GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, OBJ_INHERIT );
         acceptsock->wparam = handle;
         release_object( acceptsock );
-        if (!handle) return;
+        if (!handle)
+        {
+            async_terminate( async, get_error() );
+            return;
+        }
 
-        if (!(iosb->out_data = malloc( sizeof(handle) ))) return;
+        if (!(out_data = malloc( sizeof(handle) ))) return;
 
-        iosb->status = STATUS_SUCCESS;
-        iosb->out_size = sizeof(handle);
-        memcpy( iosb->out_data, &handle, sizeof(handle) );
-        set_error( STATUS_ALERTED );
+        memcpy( out_data, &handle, sizeof(handle) );
+        async_request_complete( req->async, STATUS_SUCCESS, 0, sizeof(handle), out_data );
     }
 }
 
@@ -747,7 +758,6 @@ static void complete_async_connect( struct sock *sock )
 {
     struct connect_req *req = sock->connect_req;
     const char *in_buffer;
-    struct iosb *iosb;
     size_t len;
     int ret;
 
@@ -757,28 +767,20 @@ static void complete_async_connect( struct sock *sock )
 
     if (!req->send_len)
     {
-        set_error( STATUS_SUCCESS );
+        async_terminate( req->async, STATUS_SUCCESS );
         return;
     }
 
-    iosb = req->iosb;
-    in_buffer = (const char *)iosb->in_data + sizeof(struct afd_connect_params) + req->addr_len;
+    in_buffer = (const char *)req->iosb->in_data + sizeof(struct afd_connect_params) + req->addr_len;
     len = req->send_len - req->send_cursor;
 
     ret = send( get_unix_fd( sock->fd ), in_buffer + req->send_cursor, len, 0 );
     if (ret < 0 && errno != EWOULDBLOCK)
-        set_error( sock_get_ntstatus( errno ) );
+        async_terminate( req->async, sock_get_ntstatus( errno ) );
     else if (ret == len)
-    {
-        iosb->result = req->send_len;
-        iosb->status = STATUS_SUCCESS;
-        set_error( STATUS_ALERTED );
-    }
+        async_request_complete( req->async, STATUS_SUCCESS, req->send_len, 0, NULL );
     else
-    {
         req->send_cursor += ret;
-        set_error( STATUS_PENDING );
-    }
 }
 
 static void free_poll_req( void *private )
@@ -840,10 +842,9 @@ static void complete_async_polls( struct sock *sock, int event, int error )
 
     LIST_FOR_EACH_ENTRY_SAFE( req, next, &poll_list, struct poll_req, entry )
     {
-        struct iosb *iosb = req->iosb;
         unsigned int i;
 
-        if (iosb->status != STATUS_PENDING) continue;
+        if (req->iosb->status != STATUS_PENDING) continue;
 
         for (i = 0; i < req->count; ++i)
         {
@@ -857,10 +858,8 @@ static void complete_async_polls( struct sock *sock, int event, int error )
             req->output[i].flags = req->sockets[i].flags & flags;
             req->output[i].status = sock_get_ntstatus( error );
 
-            iosb->status = STATUS_SUCCESS;
-            iosb->out_data = req->output;
-            iosb->out_size = req->count * sizeof(*req->output);
-            async_terminate( req->async, STATUS_ALERTED );
+            async_request_complete( req->async, STATUS_SUCCESS, 0,
+                                    req->count * sizeof(*req->output), req->output );
             break;
         }
     }
@@ -869,16 +868,12 @@ static void complete_async_polls( struct sock *sock, int event, int error )
 static void async_poll_timeout( void *private )
 {
     struct poll_req *req = private;
-    struct iosb *iosb = req->iosb;
 
     req->timeout = NULL;
 
-    if (iosb->status != STATUS_PENDING) return;
+    if (req->iosb->status != STATUS_PENDING) return;
 
-    iosb->status = STATUS_TIMEOUT;
-    iosb->out_data = req->output;
-    iosb->out_size = req->count * sizeof(*req->output);
-    async_terminate( req->async, STATUS_ALERTED );
+    async_request_complete( req->async, STATUS_TIMEOUT, 0, req->count * sizeof(*req->output), req->output );
 }
 
 static int sock_dispatch_asyncs( struct sock *sock, int event, int error )
@@ -892,26 +887,16 @@ static int sock_dispatch_asyncs( struct sock *sock, int event, int error )
             if (req->iosb->status == STATUS_PENDING && !req->accepted)
             {
                 complete_async_accept( sock, req );
-                if (get_error() != STATUS_PENDING)
-                    async_terminate( req->async, get_error() );
                 break;
             }
         }
 
         if (sock->accept_recv_req && sock->accept_recv_req->iosb->status == STATUS_PENDING)
-        {
             complete_async_accept_recv( sock->accept_recv_req );
-            if (get_error() != STATUS_PENDING)
-                async_terminate( sock->accept_recv_req->async, get_error() );
-        }
     }
 
     if ((event & POLLOUT) && sock->connect_req && sock->connect_req->iosb->status == STATUS_PENDING)
-    {
         complete_async_connect( sock );
-        if (get_error() != STATUS_PENDING)
-            async_terminate( sock->connect_req->async, get_error() );
-    }
 
     if (event & (POLLIN | POLLPRI) && async_waiting( &sock->read_q ))
     {
@@ -1323,6 +1308,7 @@ static int sock_close_handle( struct object *obj, struct process *process, obj_h
         LIST_FOR_EACH_ENTRY_SAFE( poll_req, poll_next, &poll_list, struct poll_req, entry )
         {
             struct iosb *iosb = poll_req->iosb;
+            BOOL signaled = FALSE;
             unsigned int i;
 
             if (iosb->status != STATUS_PENDING) continue;
@@ -1331,17 +1317,17 @@ static int sock_close_handle( struct object *obj, struct process *process, obj_h
             {
                 if (poll_req->sockets[i].sock == sock)
                 {
-                    iosb->status = STATUS_SUCCESS;
+                    signaled = TRUE;
                     poll_req->output[i].flags = AFD_POLL_CLOSE;
                     poll_req->output[i].status = 0;
                 }
             }
 
-            if (iosb->status != STATUS_PENDING)
+            if (signaled)
             {
-                iosb->out_data = poll_req->output;
-                iosb->out_size = poll_req->count * sizeof(*poll_req->output);
-                async_terminate( poll_req->async, STATUS_ALERTED );
+                /* pass 0 as result; client will set actual result size */
+                async_request_complete( poll_req->async, STATUS_SUCCESS, 0,
+                                        poll_req->count * sizeof(*poll_req->output), poll_req->output );
             }
         }
     }
@@ -2857,6 +2843,7 @@ static int poll_socket( struct sock *poll_sock, struct async *async, timeout_t t
                         unsigned int count, const struct poll_socket_input *input )
 {
     struct poll_socket_output *output;
+    BOOL signaled = FALSE;
     struct poll_req *req;
     unsigned int i, j;
 
@@ -2902,8 +2889,6 @@ static int poll_socket( struct sock *poll_sock, struct async *async, timeout_t t
     async_set_completion_callback( async, free_poll_req, req );
     queue_async( &poll_sock->poll_q, async );
 
-    if (!timeout) req->iosb->status = STATUS_SUCCESS;
-
     for (i = 0; i < count; ++i)
     {
         struct sock *sock = req->sockets[i].sock;
@@ -2912,7 +2897,7 @@ static int poll_socket( struct sock *poll_sock, struct async *async, timeout_t t
 
         if (flags)
         {
-            req->iosb->status = STATUS_SUCCESS;
+            signaled = TRUE;
             output[i].flags = flags;
             output[i].status = sock_get_ntstatus( sock_error( sock->fd ) );
         }
@@ -2926,12 +2911,8 @@ static int poll_socket( struct sock *poll_sock, struct async *async, timeout_t t
         }
     }
 
-    if (req->iosb->status != STATUS_PENDING)
-    {
-        req->iosb->out_data = output;
-        req->iosb->out_size = count * sizeof(*output);
-        async_terminate( req->async, STATUS_ALERTED );
-    }
+    if (!timeout || signaled)
+        async_request_complete( req->async, STATUS_SUCCESS, 0, count * sizeof(*output), output );
 
     for (i = 0; i < req->count; ++i)
         sock_reselect( req->sockets[i].sock );
-- 
2.33.0




More information about the wine-devel mailing list