[PATCH 2/4] ntdll/unix: Add a new select type "SELECT_SIGNAL_WAIT_ASYNC".

Jinoh Kang jinoh.kang.kr at gmail.com
Tue Jan 18 13:29:45 CST 2022


This select type is not used to emulate any NtWait* system call on
Windows; instead, it is intended be used in place of async_wait() to set
the async result and "wait" for the async object in one server call.

Signed-off-by: Jinoh Kang <jinoh.kang.kr at gmail.com>
---
 dlls/ntdll/unix/server.c       |  2 ++
 dlls/ntdll/unix/sync.c         | 14 ++++++++++++++
 dlls/ntdll/unix/unix_private.h |  1 +
 server/async.c                 | 13 ++++++++++---
 server/object.h                |  4 ++++
 server/protocol.def            | 11 ++++++++++-
 server/thread.c                | 10 ++++++++++
 7 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
index 9d0594d3374..100bf943292 100644
--- a/dlls/ntdll/unix/server.c
+++ b/dlls/ntdll/unix/server.c
@@ -632,6 +632,8 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT
             /* don't signal multiple times */
             if (size >= sizeof(select_op->signal_and_wait) && select_op->op == SELECT_SIGNAL_AND_WAIT)
                 size = offsetof( select_op_t, signal_and_wait.signal );
+            if (size >= sizeof(select_op->signal_wait_async) && select_op->op == SELECT_SIGNAL_WAIT_ASYNC )
+                size = offsetof( select_op_t, signal_wait_async.signal );
         }
         pthread_sigmask( SIG_SETMASK, &old_set, NULL );
         if (signaled) break;
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c
index 442243d8bcf..3b206a8f0f2 100644
--- a/dlls/ntdll/unix/sync.c
+++ b/dlls/ntdll/unix/sync.c
@@ -2510,3 +2510,17 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG
 }
 
 #endif
+
+NTSTATUS signal_wait_async( HANDLE handle, BOOL alertable, BOOL signal, NTSTATUS status, ULONG_PTR information )
+{
+    select_op_t select_op;
+    UINT flags = SELECT_INTERRUPTIBLE;
+
+    if (alertable) flags |= SELECT_ALERTABLE;
+    select_op.signal_wait_async.op = SELECT_SIGNAL_WAIT_ASYNC;
+    select_op.signal_wait_async.handle = wine_server_obj_handle( handle );
+    select_op.signal_wait_async.signal = signal;
+    select_op.signal_wait_async.status = status;
+    select_op.signal_wait_async.total = information;
+    return server_wait( &select_op, sizeof(select_op.signal_wait_async), flags, NULL );
+}
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index a79edabc37c..5455521c1a0 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 NTSTATUS signal_wait_async( HANDLE handle, BOOL alertable, BOOL signal, NTSTATUS status, ULONG_PTR information );
 
 extern void dbg_init(void) DECLSPEC_HIDDEN;
 
diff --git a/server/async.c b/server/async.c
index 7aef28355f0..339d050b086 100644
--- a/server/async.c
+++ b/server/async.c
@@ -98,6 +98,11 @@ static inline void async_reselect( struct async *async )
     if (async->queue && async->fd) fd_reselect_async( async->fd, async->queue );
 }
 
+struct async *get_async_obj( struct process *process, obj_handle_t handle, unsigned int access )
+{
+    return (struct async *)get_handle_obj( process, handle, access, &async_ops );
+}
+
 static void async_dump( struct object *obj, int verbose )
 {
     struct async *async = (struct async *)obj;
@@ -121,10 +126,7 @@ static void async_satisfied( struct object *obj, struct wait_queue_entry *entry
     assert( async->iosb );
 
     if (async->direct_result)
-    {
         async_set_result( &async->obj, async->iosb->status, async->iosb->result );
-        async->direct_result = 0;
-    }
 
     if (async->initial_status == STATUS_PENDING && async->blocking)
         set_wait_status( entry, async->iosb->status );
@@ -460,6 +462,11 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota
 
     assert( async->terminated );  /* it must have been woken up if we get a result */
 
+    /* If status == STATUS_PENDING, future results will be delivered via APC.
+     * If status != STATUS_PENDING, this prevents async_satisfied() from
+     * overriding I/O result set by SELECT_SIGNAL_WAIT_ASYNC. */
+    async->direct_result = 0;
+
     if (async->alerted && status == STATUS_PENDING)  /* restart it */
     {
         async->terminated = 0;
diff --git a/server/object.h b/server/object.h
index f156f1d2f13..8645a00f73a 100644
--- a/server/object.h
+++ b/server/object.h
@@ -288,6 +288,10 @@ extern struct object *create_symlink( struct object *root, const struct unicode_
                                       unsigned int attr, const struct unicode_str *target,
                                       const struct security_descriptor *sd );
 
+/* async I/O functions */
+
+extern struct async *get_async_obj( struct process *process, obj_handle_t handle, unsigned int access );
+
 /* global variables */
 
   /* command-line options */
diff --git a/server/protocol.def b/server/protocol.def
index db73f0418a9..ae4729a9e56 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -446,7 +446,8 @@ enum select_op
     SELECT_WAIT_ALL,
     SELECT_SIGNAL_AND_WAIT,
     SELECT_KEYED_EVENT_WAIT,
-    SELECT_KEYED_EVENT_RELEASE
+    SELECT_KEYED_EVENT_RELEASE,
+    SELECT_SIGNAL_WAIT_ASYNC,
 };
 
 typedef union
@@ -469,6 +470,14 @@ typedef union
         obj_handle_t    handle;
         client_ptr_t    key;
     } keyed_event;
+    struct
+    {
+        enum select_op  op;      /* SELECT_SIGNAL_WAIT_ASYNC */
+        obj_handle_t    handle;
+        int             signal;  /* set to 0 to ignore status and total (e.g. on retries) */
+        unsigned int    status;  /* new status of async operation */
+        apc_param_t     total;   /* bytes transferred */
+    } signal_wait_async;
 } select_op_t;
 
 enum apc_type
diff --git a/server/thread.c b/server/thread.c
index 467ccd1f0db..8eb473f2c58 100644
--- a/server/thread.c
+++ b/server/thread.c
@@ -1029,6 +1029,16 @@ static int select_on( const select_op_t *select_op, data_size_t op_size, client_
         current->wait->key = select_op->keyed_event.key;
         break;
 
+    case SELECT_SIGNAL_WAIT_ASYNC:
+        object = (struct object *)get_async_obj( current->process, select_op->signal_wait_async.handle, SYNCHRONIZE );
+        if (!object) return 1;
+        if (select_op->signal_wait_async.signal)
+            async_set_result( object, select_op->signal_wait_async.status, select_op->signal_wait_async.total );
+        ret = wait_on( select_op, 1, &object, flags, when );
+        release_object( object );
+        if (!ret) return 1;
+        break;
+
     default:
         set_error( STATUS_INVALID_PARAMETER );
         return 1;
-- 
2.31.1




More information about the wine-devel mailing list