[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