[PATCH 6/6] ntdll: Explicitly return whether an async is complete in async_callback_t.

Zebediah Figura zfigura at codeweavers.com
Tue Sep 14 01:02:48 CDT 2021


Signed-off-by: Zebediah Figura <zfigura at codeweavers.com>
---
 dlls/ntdll/unix/file.c             |  92 ++++++++++++-------------
 dlls/ntdll/unix/server.c           |   6 +-
 dlls/ntdll/unix/socket.c           | 104 +++++++++++++----------------
 dlls/ntdll/unix/unix_private.h     |   3 +-
 dlls/ntoskrnl.exe/tests/ntoskrnl.c |  50 +++++---------
 5 files changed, 112 insertions(+), 143 deletions(-)

diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 5da9ca560f6..bcd74c9d6aa 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -4679,34 +4679,34 @@ struct async_fileio *alloc_fileio( DWORD size, async_callback_t callback, HANDLE
 }
 
 /* callback for irp async I/O completion */
-static NTSTATUS irp_completion( void *user, ULONG_PTR *info, NTSTATUS status )
+static BOOL irp_completion( void *user, ULONG_PTR *info, NTSTATUS *status )
 {
     struct async_irp *async = user;
 
-    if (status == STATUS_ALERTED)
+    if (*status == STATUS_ALERTED)
     {
         SERVER_START_REQ( get_async_result )
         {
             req->user_arg = wine_server_client_ptr( async );
             wine_server_set_reply( req, async->buffer, async->size );
-            status = virtual_locked_server_call( req );
+            *status = virtual_locked_server_call( req );
         }
         SERVER_END_REQ;
     }
-    if (status != STATUS_PENDING) release_fileio( &async->io );
-    return status;
+    release_fileio( &async->io );
+    return TRUE;
 }
 
-static NTSTATUS async_read_proc( void *user, ULONG_PTR *info, NTSTATUS status )
+static BOOL async_read_proc( void *user, ULONG_PTR *info, NTSTATUS *status )
 {
     struct async_fileio_read *fileio = user;
     int fd, needs_close, result;
 
-    switch (status)
+    switch (*status)
     {
     case STATUS_ALERTED: /* got some new data */
         /* check to see if the data is ready (non-blocking) */
-        if ((status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
+        if ((*status = server_get_unix_fd( fileio->io.handle, FILE_READ_DATA, &fd,
                                           &needs_close, NULL, NULL )))
             break;
 
@@ -4716,48 +4716,48 @@ static NTSTATUS async_read_proc( void *user, ULONG_PTR *info, NTSTATUS status )
         if (result < 0)
         {
             if (errno == EAGAIN || errno == EINTR)
-                status = STATUS_PENDING;
-            else /* check to see if the transfer is complete */
-                status = errno_to_status( errno );
+                return FALSE;
+
+            /* check to see if the transfer is complete */
+            *status = errno_to_status( errno );
         }
         else if (result == 0)
         {
-            status = fileio->already ? STATUS_SUCCESS : STATUS_PIPE_BROKEN;
+            *status = fileio->already ? STATUS_SUCCESS : STATUS_PIPE_BROKEN;
         }
         else
         {
             fileio->already += result;
-            if (fileio->already >= fileio->count || fileio->avail_mode)
-                status = STATUS_SUCCESS;
-            else
-                status = STATUS_PENDING;
+
+            if (fileio->already < fileio->count && !fileio->avail_mode)
+                return FALSE;
+
+            *status = STATUS_SUCCESS;
         }
         break;
 
     case STATUS_TIMEOUT:
     case STATUS_IO_TIMEOUT:
-        if (fileio->already) status = STATUS_SUCCESS;
+        if (fileio->already) *status = STATUS_SUCCESS;
         break;
     }
-    if (status != STATUS_PENDING)
-    {
-        *info = fileio->already;
-        release_fileio( &fileio->io );
-    }
-    return status;
+
+    *info = fileio->already;
+    release_fileio( &fileio->io );
+    return TRUE;
 }
 
-static NTSTATUS async_write_proc( void *user, ULONG_PTR *info, NTSTATUS status )
+static BOOL async_write_proc( void *user, ULONG_PTR *info, NTSTATUS *status )
 {
     struct async_fileio_write *fileio = user;
     int result, fd, needs_close;
     enum server_fd_type type;
 
-    switch (status)
+    switch (*status)
     {
     case STATUS_ALERTED:
         /* write some data (non-blocking) */
-        if ((status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
+        if ((*status = server_get_unix_fd( fileio->io.handle, FILE_WRITE_DATA, &fd,
                                           &needs_close, &type, NULL )))
             break;
 
@@ -4770,27 +4770,26 @@ static NTSTATUS async_write_proc( void *user, ULONG_PTR *info, NTSTATUS status )
 
         if (result < 0)
         {
-            if (errno == EAGAIN || errno == EINTR) status = STATUS_PENDING;
-            else status = errno_to_status( errno );
+            if (errno == EAGAIN || errno == EINTR) return FALSE;
+            *status = errno_to_status( errno );
         }
         else
         {
             fileio->already += result;
-            status = (fileio->already < fileio->count) ? STATUS_PENDING : STATUS_SUCCESS;
+            if (fileio->already < fileio->count) return FALSE;
+            *status = STATUS_SUCCESS;
         }
         break;
 
     case STATUS_TIMEOUT:
     case STATUS_IO_TIMEOUT:
-        if (fileio->already) status = STATUS_SUCCESS;
+        if (fileio->already) *status = STATUS_SUCCESS;
         break;
     }
-    if (status != STATUS_PENDING)
-    {
-        *info = fileio->already;
-        release_fileio( &fileio->io );
-    }
-    return status;
+
+    *info = fileio->already;
+    release_fileio( &fileio->io );
+    return TRUE;
 }
 
 /* do a read call through the server */
@@ -6054,23 +6053,23 @@ NTSTATUS WINAPI NtUnlockFile( HANDLE handle, IO_STATUS_BLOCK *io_status, LARGE_I
 }
 
 
-static NTSTATUS read_changes_apc( void *user, ULONG_PTR *info, NTSTATUS status )
+static BOOL read_changes_apc( void *user, ULONG_PTR *info, NTSTATUS *status )
 {
     struct async_fileio_read_changes *fileio = user;
     int size = 0;
 
-    if (status == STATUS_ALERTED)
+    if (*status == STATUS_ALERTED)
     {
         SERVER_START_REQ( read_change )
         {
             req->handle = wine_server_obj_handle( fileio->io.handle );
             wine_server_set_reply( req, fileio->data, fileio->data_size );
-            status = wine_server_call( req );
+            *status = wine_server_call( req );
             size = wine_server_reply_size( reply );
         }
         SERVER_END_REQ;
 
-        if (status == STATUS_SUCCESS && fileio->buffer)
+        if (*status == STATUS_SUCCESS && fileio->buffer)
         {
             FILE_NOTIFY_INFORMATION *pfni = fileio->buffer;
             int i, left = fileio->buffer_size;
@@ -6105,7 +6104,7 @@ static NTSTATUS read_changes_apc( void *user, ULONG_PTR *info, NTSTATUS status )
 
             if (size)
             {
-                status = STATUS_NOTIFY_ENUM_DIR;
+                *status = STATUS_NOTIFY_ENUM_DIR;
                 size = 0;
             }
             else
@@ -6116,17 +6115,14 @@ static NTSTATUS read_changes_apc( void *user, ULONG_PTR *info, NTSTATUS status )
         }
         else
         {
-            status = STATUS_NOTIFY_ENUM_DIR;
+            *status = STATUS_NOTIFY_ENUM_DIR;
             size = 0;
         }
     }
 
-    if (status != STATUS_PENDING)
-    {
-        *info = size;
-        release_fileio( &fileio->io );
-    }
-    return status;
+    *info = size;
+    release_fileio( &fileio->io );
+    return TRUE;
 }
 
 #define FILE_NOTIFY_ALL        (  \
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
index 08733fba710..050824a1440 100644
--- a/dlls/ntdll/unix/server.c
+++ b/dlls/ntdll/unix/server.c
@@ -379,11 +379,13 @@ static void invoke_system_apc( const apc_call_t *call, apc_result_t *result, BOO
     {
         struct async_fileio *user = wine_server_get_ptr( call->async_io.user );
         ULONG_PTR info = call->async_io.result;
+        NTSTATUS status;
 
         result->type = call->type;
-        result->async_io.status = user->callback( user, &info, call->async_io.status );
-        if (result->async_io.status != STATUS_PENDING)
+        status = call->async_io.status;
+        if (user->callback( user, &info, &status ))
         {
+            result->async_io.status = status;
             result->async_io.total = info;
             /* the server will pass us NULL if a call failed synchronously */
             set_async_iosb( call->async_io.sb, result->async_io.status, info );
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c
index db58d2e5b12..73d61c0d4e6 100644
--- a/dlls/ntdll/unix/socket.c
+++ b/dlls/ntdll/unix/socket.c
@@ -562,28 +562,27 @@ static NTSTATUS try_recv( int fd, struct async_recv_ioctl *async, ULONG_PTR *siz
     return status;
 }
 
-static NTSTATUS async_recv_proc( void *user, ULONG_PTR *info, NTSTATUS status )
+static BOOL async_recv_proc( void *user, ULONG_PTR *info, NTSTATUS *status )
 {
     struct async_recv_ioctl *async = user;
     int fd, needs_close;
 
-    TRACE( "%#x\n", status );
+    TRACE( "%#x\n", *status );
 
-    if (status == STATUS_ALERTED)
+    if (*status == STATUS_ALERTED)
     {
-        if ((status = server_get_unix_fd( async->io.handle, 0, &fd, &needs_close, NULL, NULL )))
-            return status;
-
-        status = try_recv( fd, async, info );
-        TRACE( "got status %#x, %#lx bytes read\n", status, *info );
-
-        if (status == STATUS_DEVICE_NOT_READY)
-            status = STATUS_PENDING;
+        if ((*status = server_get_unix_fd( async->io.handle, 0, &fd, &needs_close, NULL, NULL )))
+            return TRUE;
 
+        *status = try_recv( fd, async, info );
+        TRACE( "got status %#x, %#lx bytes read\n", *status, *info );
         if (needs_close) close( fd );
+
+        if (*status == STATUS_DEVICE_NOT_READY)
+            return FALSE;
     }
-    if (status != STATUS_PENDING) release_fileio( &async->io );
-    return status;
+    release_fileio( &async->io );
+    return TRUE;
 }
 
 static NTSTATUS sock_recv( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user, IO_STATUS_BLOCK *io,
@@ -696,29 +695,26 @@ static ULONG_PTR fill_poll_output( struct async_poll_ioctl *async, NTSTATUS stat
     return offsetof( struct afd_poll_params, sockets[count] );
 }
 
-static NTSTATUS async_poll_proc( void *user, ULONG_PTR *info, NTSTATUS status )
+static BOOL async_poll_proc( void *user, ULONG_PTR *info, NTSTATUS *status )
 {
     struct async_poll_ioctl *async = user;
 
-    if (status == STATUS_ALERTED)
+    if (*status == STATUS_ALERTED)
     {
         SERVER_START_REQ( get_async_result )
         {
             req->user_arg = wine_server_client_ptr( async );
             wine_server_set_reply( req, async->sockets, async->count * sizeof(async->sockets[0]) );
-            status = wine_server_call( req );
+            *status = wine_server_call( req );
         }
         SERVER_END_REQ;
 
-        *info = fill_poll_output( async, status );
+        *info = fill_poll_output( async, *status );
     }
 
-    if (status != STATUS_PENDING)
-    {
-        free( async->input );
-        release_fileio( &async->io );
-    }
-    return status;
+    free( async->input );
+    release_fileio( &async->io );
+    return TRUE;
 }
 
 
@@ -877,32 +873,29 @@ static NTSTATUS try_send( int fd, struct async_send_ioctl *async )
     return STATUS_SUCCESS;
 }
 
-static NTSTATUS async_send_proc( void *user, ULONG_PTR *info, NTSTATUS status )
+static BOOL async_send_proc( void *user, ULONG_PTR *info, NTSTATUS *status )
 {
     struct async_send_ioctl *async = user;
     int fd, needs_close;
 
-    TRACE( "%#x\n", status );
+    TRACE( "%#x\n", *status );
 
-    if (status == STATUS_ALERTED)
+    if (*status == STATUS_ALERTED)
     {
-        if ((status = server_get_unix_fd( async->io.handle, 0, &fd, &needs_close, NULL, NULL )))
-            return status;
+        if ((*status = server_get_unix_fd( async->io.handle, 0, &fd, &needs_close, NULL, NULL )))
+            return TRUE;
 
-        status = try_send( fd, async );
-        TRACE( "got status %#x\n", status );
-
-        if (status == STATUS_DEVICE_NOT_READY)
-            status = STATUS_PENDING;
+        *status = try_send( fd, async );
+        TRACE( "got status %#x\n", *status );
 
         if (needs_close) close( fd );
+
+        if (*status == STATUS_DEVICE_NOT_READY)
+            return FALSE;
     }
-    if (status != STATUS_PENDING)
-    {
-        *info = async->sent_len;
-        release_fileio( &async->io );
-    }
-    return status;
+    *info = async->sent_len;
+    release_fileio( &async->io );
+    return TRUE;
 }
 
 static NTSTATUS sock_send( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
@@ -1040,39 +1033,36 @@ static NTSTATUS try_transmit( int sock_fd, int file_fd, struct async_transmit_io
     return STATUS_SUCCESS;
 }
 
-static NTSTATUS async_transmit_proc( void *user, ULONG_PTR *info, NTSTATUS status )
+static BOOL async_transmit_proc( void *user, ULONG_PTR *info, NTSTATUS *status )
 {
     int sock_fd, file_fd = -1, sock_needs_close = FALSE, file_needs_close = FALSE;
     struct async_transmit_ioctl *async = user;
 
-    TRACE( "%#x\n", status );
+    TRACE( "%#x\n", *status );
 
-    if (status == STATUS_ALERTED)
+    if (*status == STATUS_ALERTED)
     {
-        if ((status = server_get_unix_fd( async->io.handle, 0, &sock_fd, &sock_needs_close, NULL, NULL )))
-            return status;
+        if ((*status = server_get_unix_fd( async->io.handle, 0, &sock_fd, &sock_needs_close, NULL, NULL )))
+            return TRUE;
 
-        if (async->file && (status = server_get_unix_fd( async->file, 0, &file_fd, &file_needs_close, NULL, NULL )))
+        if (async->file && (*status = server_get_unix_fd( async->file, 0, &file_fd, &file_needs_close, NULL, NULL )))
         {
             if (sock_needs_close) close( sock_fd );
-            return status;
+            return TRUE;
         }
 
-        status = try_transmit( sock_fd, file_fd, async );
-        TRACE( "got status %#x\n", status );
-
-        if (status == STATUS_DEVICE_NOT_READY)
-            status = STATUS_PENDING;
+        *status = try_transmit( sock_fd, file_fd, async );
+        TRACE( "got status %#x\n", *status );
 
         if (sock_needs_close) close( sock_fd );
         if (file_needs_close) close( file_fd );
+
+        if (*status == STATUS_DEVICE_NOT_READY)
+            return FALSE;
     }
-    if (status != STATUS_PENDING)
-    {
-        *info = async->head_cursor + async->file_cursor + async->tail_cursor;
-        release_fileio( &async->io );
-    }
-    return status;
+    *info = async->head_cursor + async->file_cursor + async->tail_cursor;
+    release_fileio( &async->io );
+    return TRUE;
 }
 
 static NTSTATUS sock_transmit( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, void *apc_user,
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index fb1a4a397e9..6b8835bcba0 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -70,7 +70,8 @@ static inline struct ntdll_thread_data *ntdll_get_thread_data(void)
     return (struct ntdll_thread_data *)&NtCurrentTeb()->GdiTebBatch;
 }
 
-typedef NTSTATUS async_callback_t( void *user, ULONG_PTR *info, NTSTATUS status );
+/* returns TRUE if the async is complete; FALSE if it should be restarted */
+typedef BOOL async_callback_t( void *user, ULONG_PTR *info, NTSTATUS *status );
 
 struct async_fileio
 {
diff --git a/dlls/ntoskrnl.exe/tests/ntoskrnl.c b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
index 2484479efc3..00daccb8487 100644
--- a/dlls/ntoskrnl.exe/tests/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/tests/ntoskrnl.c
@@ -677,7 +677,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
     if (NT_ERROR(expect_status))
         ok(size == 0xdeadf00d, "got size %u\n", size);
     else if (!NT_ERROR(params->iosb_status))
-        todo_wine_if (params->iosb_status == STATUS_PENDING) ok(size == 3, "got size %u\n", size);
+        ok(size == 3, "got size %u\n", size);
     /* size is garbage if !NT_ERROR(expect_status) && NT_ERROR(iosb_status) */
     ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
 
@@ -694,11 +694,8 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
     }
     else
     {
-        todo_wine_if (params->iosb_status == STATUS_PENDING)
-        {
-            ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
-            ok(io.Information == 3, "got size %Iu\n", io.Information);
-        }
+        ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
+        ok(io.Information == 3, "got size %Iu\n", io.Information);
     }
     ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
 
@@ -731,11 +728,8 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
     }
     else
     {
-        todo_wine_if (params->iosb_status == STATUS_PENDING)
-        {
-            ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
-            ok(io.Information == 3, "got size %Iu\n", io.Information);
-        }
+        ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
+        ok(io.Information == 3, "got size %Iu\n", io.Information);
         ret = WaitForSingleObject(event, 0);
         ok(!ret, "got %d\n", ret);
     }
@@ -758,8 +752,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
         ok(key == 123, "got key %Iu\n", key);
         ok(value == 456, "got value %Iu\n", value);
         ok(io.Status == params->iosb_status, "got iosb status %#x\n", io.Status);
-        todo_wine_if (params->iosb_status == STATUS_PENDING)
-            ok(io.Information == 3, "got information %Iu\n", io.Information);
+        ok(io.Information == 3, "got information %Iu\n", io.Information);
     }
 
     /* As above, but set the event first, to show that the event is always
@@ -782,11 +775,8 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
     }
     else
     {
-        todo_wine_if (params->iosb_status == STATUS_PENDING)
-        {
-            ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
-            ok(io.Information == 3, "got size %Iu\n", io.Information);
-        }
+        ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
+        ok(io.Information == 3, "got size %Iu\n", io.Information);
         ret = WaitForSingleObject(event, 0);
         ok(!ret, "got %d\n", ret);
     }
@@ -813,11 +803,8 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
     }
     else
     {
-        todo_wine_if (params->iosb_status == STATUS_PENDING)
-        {
-            ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
-            ok(io.Information == 3, "got size %Iu\n", io.Information);
-        }
+        ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
+        ok(io.Information == 3, "got size %Iu\n", io.Information);
         ret = WaitForSingleObject(file, 0);
         ok(!ret, "got %d\n", ret);
     }
@@ -848,11 +835,8 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
         }
         else
         {
-            todo_wine_if (params->iosb_status == STATUS_PENDING)
-            {
-                ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
-                ok(io.Information == 3, "got size %Iu\n", io.Information);
-            }
+            ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
+            ok(io.Information == 3, "got size %Iu\n", io.Information);
             ret = WaitForSingleObject(event, 0);
             ok(!ret, "got %d\n", ret);
         }
@@ -883,8 +867,7 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
             ok(key == 123, "got key %Iu\n", key);
             ok(value == 456, "got value %Iu\n", value);
             ok(io.Status == params->iosb_status, "got iosb status %#x\n", io.Status);
-            todo_wine_if (params->iosb_status == STATUS_PENDING)
-                ok(io.Information == 3, "got information %Iu\n", io.Information);
+            ok(io.Information == 3, "got information %Iu\n", io.Information);
         }
     }
 
@@ -914,11 +897,8 @@ static void do_return_status(ULONG ioctl, struct return_status_params *params)
     }
     else
     {
-        todo_wine_if (params->iosb_status == STATUS_PENDING)
-        {
-            ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
-            ok(io.Information == 3, "got size %Iu\n", io.Information);
-        }
+        ok(io.Status == params->iosb_status, "got %#x\n", io.Status);
+        ok(io.Information == 3, "got size %Iu\n", io.Information);
     }
     ok(!strcmp(buffer, expect_buffer), "got buffer %s\n", buffer);
 
-- 
2.33.0




More information about the wine-devel mailing list