From: Elizabeth Figura zfigura@codeweavers.com
--- dlls/ntdll/unix/server.c | 2 +- dlls/ntdll/unix/sync.c | 55 ++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/unix_private.h | 1 + server/inproc_sync.c | 39 ++++++++++++++++++++++++ server/object.h | 6 ---- server/protocol.def | 14 +++++++++ server/queue.c | 6 ++++ server/user.h | 1 + 8 files changed, 117 insertions(+), 7 deletions(-)
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 1613c163f33..eca25743812 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -104,7 +104,7 @@ sigset_t server_block_set; /* signals to block during server calls */ static int fd_socket = -1; /* socket to exchange file descriptors with the server */ static int initial_cwd = -1; static pid_t server_pid; -static pthread_mutex_t fd_cache_mutex = PTHREAD_MUTEX_INITIALIZER; +pthread_mutex_t fd_cache_mutex = PTHREAD_MUTEX_INITIALIZER;
/* atomically exchange a 64-bit value */ static inline LONG64 interlocked_xchg64( LONG64 *dest, LONG64 val ) diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index e861bffc874..4211b796042 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -307,6 +307,45 @@ static unsigned int validate_open_object_attributes( const OBJECT_ATTRIBUTES *at }
+struct inproc_sync +{ + int fd; + unsigned int type : 2; +}; + +static void release_inproc_sync( struct inproc_sync *sync ) +{ + close( sync->fd ); +} + +static NTSTATUS get_inproc_sync( HANDLE handle, struct inproc_sync *sync ) +{ + sigset_t sigset; + NTSTATUS ret; + + /* We need to use fd_cache_mutex here to protect against races with + * other threads trying to receive fds for the fd cache, + * and we need to use an uninterrupted section to prevent reentrancy. */ + server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); + + SERVER_START_REQ( get_inproc_sync_fd ) + { + req->handle = wine_server_obj_handle( handle ); + if (!(ret = wine_server_call( req ))) + { + obj_handle_t fd_handle; + sync->fd = wine_server_receive_fd( &fd_handle ); + assert( wine_server_ptr_handle(fd_handle) == handle ); + sync->type = reply->type; + } + } + SERVER_END_REQ; + + server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); + + return ret; +} + static NTSTATUS inproc_release_semaphore( HANDLE handle, ULONG count, ULONG *prev_count ) { if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; @@ -358,7 +397,23 @@ 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 ) { + struct inproc_sync *syncs[64], stack[ARRAY_SIZE(syncs)]; + NTSTATUS ret; + if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; + + assert( count <= ARRAY_SIZE(syncs) ); + for (int i = 0; i < count; ++i) + { + if ((ret = get_inproc_sync( handles[i], stack + i ))) + { + while (i--) release_inproc_sync( syncs[i] ); + return ret; + } + syncs[i] = stack + i; + } + + while (count--) release_inproc_sync( syncs[count] ); return STATUS_NOT_IMPLEMENTED; }
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index 756f1e91a3e..188fa07ba5d 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -200,6 +200,7 @@ extern HANDLE keyed_event; extern int inproc_device_fd; extern timeout_t server_start_time; extern sigset_t server_block_set; +extern pthread_mutex_t fd_cache_mutex; extern struct _KUSER_SHARED_DATA *user_shared_data; #ifdef __i386__ extern struct ldt_copy __wine_ldt_copy; diff --git a/server/inproc_sync.c b/server/inproc_sync.c index 4016421ef36..995e8b57c4e 100644 --- a/server/inproc_sync.c +++ b/server/inproc_sync.c @@ -32,6 +32,7 @@ #include "handle.h" #include "request.h" #include "thread.h" +#include "user.h"
#ifdef HAVE_LINUX_NTSYNC_H # include <linux/ntsync.h> @@ -126,6 +127,26 @@ static void inproc_sync_destroy( struct object *obj ) close( sync->fd ); }
+static int get_inproc_sync_fd( struct object *obj, unsigned char *type ) +{ + struct object *sync; + int fd = -1; + + if (obj != (struct object *)current->queue) sync = get_obj_sync( obj ); + else sync = thread_queue_inproc_sync( current ); + if (!sync) return -1; + + 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; +} + #else /* NTSYNC_IOC_EVENT_READ */
int get_inproc_device_fd(void) @@ -146,4 +167,22 @@ void reset_inproc_sync( struct inproc_sync *sync ) { }
+static int get_inproc_sync_fd( struct object *obj, unsigned char *type ) +{ + return -1; +} + #endif /* NTSYNC_IOC_EVENT_READ */ + +DECL_HANDLER(get_inproc_sync_fd) +{ + struct object *obj; + int fd; + + if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL ))) return; + + if ((fd = get_inproc_sync_fd( obj, &reply->type )) < 0) set_error( STATUS_NOT_IMPLEMENTED ); + else send_client_fd( current->process, fd, req->handle ); + + release_object( obj ); +} diff --git a/server/object.h b/server/object.h index b609f5f7af9..f770db550c3 100644 --- a/server/object.h +++ b/server/object.h @@ -239,12 +239,6 @@ extern void abandon_mutexes( struct thread *thread );
/* in-process synchronization functions */
-enum inproc_sync_type -{ - INPROC_SYNC_UNKNOWN, - INPROC_SYNC_EVENT, -}; - struct inproc_sync; extern int get_inproc_device_fd(void); extern struct inproc_sync *create_inproc_event_sync( int manual, int signaled ); diff --git a/server/protocol.def b/server/protocol.def index 4429159a720..bfc13d0bffe 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -4117,3 +4117,17 @@ struct handle_info @REPLY int enable; /* previous state of auto-repeat enable */ @END + + +enum inproc_sync_type +{ + INPROC_SYNC_UNKNOWN = 0, + INPROC_SYNC_EVENT = 1, +}; + +/* Get the in-process synchronization fd associated with the waitable handle */ +@REQ(get_inproc_sync_fd) + obj_handle_t handle; /* handle to the object */ +@REPLY + unsigned char type; /* inproc sync type */ +@END diff --git a/server/queue.c b/server/queue.c index 792947c6813..74268420969 100644 --- a/server/queue.c +++ b/server/queue.c @@ -1490,6 +1490,12 @@ int init_thread_queue( struct thread *thread ) return (create_msg_queue( thread, NULL ) != NULL); }
+struct object *thread_queue_inproc_sync( struct thread *thread ) +{ + if (!thread->queue) return NULL; + return grab_object( thread->queue->inproc_sync ); +} + /* attach two thread input data structures */ int attach_thread_input( struct thread *thread_from, struct thread *thread_to ) { diff --git a/server/user.h b/server/user.h index ee0042b8755..ffd4b8b595c 100644 --- a/server/user.h +++ b/server/user.h @@ -120,6 +120,7 @@ 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 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 ); extern void detach_thread_input( struct thread *thread_from ); extern void set_clip_rectangle( struct desktop *desktop, const struct rectangle *rect,