From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/ntdll/unix/sync.c | 48 ++++++++++++++++++++++++++++++++++++++---- server/inproc_sync.c | 21 ++++++++++++------ server/protocol.def | 7 ++++++ server/queue.c | 10 +++++++++ server/user.h | 2 ++ 5 files changed, 77 insertions(+), 11 deletions(-)
diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index f7efd78b4c4..2ea8061e506 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -359,6 +359,13 @@ static NTSTATUS get_inproc_sync( HANDLE handle, ACCESS_MASK desired_access, stru return STATUS_SUCCESS; }
+static NTSTATUS get_inproc_queue_sync( struct inproc_sync *sync ) +{ + sync->refcount = 2; /* prevent closing */ + sync->fd = ntdll_get_thread_data()->queue_sync_fd; + return STATUS_SUCCESS; +} + extern unsigned int check_signal_access( struct inproc_sync *sync ) { switch (sync->type) @@ -371,6 +378,26 @@ extern unsigned int check_signal_access( struct inproc_sync *sync ) return STATUS_OBJECT_TYPE_MISMATCH; }
+static void select_queue(void) +{ + SERVER_START_REQ( select_inproc_queue ) + { + req->select = 1; + wine_server_call( req ); + } + SERVER_END_REQ; +} + +static void unselect_queue( BOOL signaled ) +{ + SERVER_START_REQ( select_inproc_queue ) + { + req->signaled = signaled; + wine_server_call( req ); + } + SERVER_END_REQ; +} + static NTSTATUS inproc_release_semaphore( HANDLE handle, ULONG count, ULONG *prev_count ) { if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; @@ -422,7 +449,9 @@ static NTSTATUS inproc_query_mutex( HANDLE handle, MUTANT_BASIC_INFORMATION *inf static NTSTATUS inproc_wait( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { + HANDLE server_queue = UlongToHandle( NtUserGetThreadInfo()->server_queue ); struct inproc_sync *syncs[64], stack[ARRAY_SIZE(syncs)]; + UINT queue = -1; NTSTATUS ret;
if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; @@ -430,7 +459,8 @@ static NTSTATUS inproc_wait( DWORD count, const HANDLE *handles, BOOLEAN wait_an assert( count <= ARRAY_SIZE(syncs) ); for (int i = 0; i < count; ++i) { - if ((ret = get_inproc_sync( handles[i], SYNCHRONIZE, stack + i ))) + if (server_queue && handles[i] == server_queue && !get_inproc_queue_sync( stack + i )) queue = i; + else if ((ret = get_inproc_sync( handles[i], SYNCHRONIZE, stack + i ))) { while (i--) release_inproc_sync( syncs[i] ); return ret; @@ -438,13 +468,18 @@ static NTSTATUS inproc_wait( DWORD count, const HANDLE *handles, BOOLEAN wait_an syncs[i] = stack + i; }
+ if (queue != -1) select_queue(); + ret = STATUS_NOT_IMPLEMENTED; + if (queue != -1) unselect_queue( ret == queue ); + while (count--) release_inproc_sync( syncs[count] ); - return STATUS_NOT_IMPLEMENTED; + return ret; }
static NTSTATUS inproc_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { + HANDLE server_queue = UlongToHandle( NtUserGetThreadInfo()->server_queue ); struct inproc_sync stack_signal, stack_wait, *signal_sync = &stack_signal, *wait_sync = &stack_wait; NTSTATUS ret;
@@ -457,15 +492,20 @@ static NTSTATUS inproc_signal_and_wait( HANDLE signal, HANDLE wait, return ret; }
- if ((ret = get_inproc_sync( wait, SYNCHRONIZE, wait_sync ))) + if (server_queue && wait == server_queue) get_inproc_queue_sync( wait_sync ); + else if ((ret = get_inproc_sync( wait, SYNCHRONIZE, wait_sync ))) { release_inproc_sync( signal_sync ); return ret; }
+ if (server_queue && wait == server_queue) select_queue(); + ret = STATUS_NOT_IMPLEMENTED; + if (server_queue && wait == server_queue) unselect_queue( !ret ); + release_inproc_sync( signal_sync ); release_inproc_sync( wait_sync ); - return STATUS_NOT_IMPLEMENTED; + return ret; }
diff --git a/server/inproc_sync.c b/server/inproc_sync.c index 66469bca407..6a601eff178 100644 --- a/server/inproc_sync.c +++ b/server/inproc_sync.c @@ -130,18 +130,18 @@ static void inproc_sync_destroy( struct object *obj )
int get_inproc_sync_fd( struct object *obj, int *type ) { - struct inproc_sync *inproc; struct object *sync; int fd = -1;
if (!(sync = get_obj_sync( obj ))) return -1; - assert( sync->ops == &inproc_sync_ops ); - - inproc = (struct inproc_sync *)sync; - *type = inproc->type; - fd = inproc->fd; - + if (sync->ops == &inproc_sync_ops) + { + struct inproc_sync *inproc = (struct inproc_sync *)sync; + *type = inproc->type; + fd = inproc->fd; + } release_object( sync ); + return fd; }
@@ -186,3 +186,10 @@ DECL_HANDLER(get_inproc_sync_fd)
release_object( obj ); } + +DECL_HANDLER(select_inproc_queue) +{ + if (!thread_queue_select( current, req->select )) return; + if (req->select) check_thread_queue_idle( current ); + if (req->signaled) thread_queue_satisfied( current ); +} diff --git a/server/protocol.def b/server/protocol.def index 2bcdf0f1c9e..2a7e3c3cdd2 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -4139,3 +4139,10 @@ enum inproc_sync_type int type; /* inproc sync type */ unsigned int access; /* handle access rights */ @END + + +/* Begin/end a client-side wait on a message queue */ +@REQ(select_inproc_queue) + int select; /* 1: begin waiting, 0: end waiting */ + int signaled; /* was the queue signaled? */ +@END diff --git a/server/queue.c b/server/queue.c index 7eb10913cda..b0cd37e4684 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1359,6 +1359,16 @@ static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *en reset_queue_sync( queue ); }
+int thread_queue_select( struct thread *thread, int select ) +{ + return msg_queue_select( thread->queue, select ); +} + +void thread_queue_satisfied( struct thread *thread ) +{ + msg_queue_satisfied( &thread->queue->obj, NULL ); +} + static void msg_queue_destroy( struct object *obj ) { struct msg_queue *queue = (struct msg_queue *)obj; diff --git a/server/user.h b/server/user.h index 0ec6ef3145e..7a97ef3aef5 100644 --- a/server/user.h +++ b/server/user.h @@ -119,6 +119,8 @@ extern void add_queue_hook_count( struct thread *thread, unsigned int index, int extern void inc_queue_paint_count( struct thread *thread, int incr ); extern void queue_cleanup_window( struct thread *thread, user_handle_t win ); extern int init_thread_queue( struct thread *thread ); +extern int thread_queue_select( struct thread *thread, int select ); +extern void thread_queue_satisfied( struct thread *thread ); extern void check_thread_queue_idle( struct thread *thread ); extern struct object *thread_queue_inproc_sync( struct thread *thread ); extern int attach_thread_input( struct thread *thread_from, struct thread *thread_to );