From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/server.c | 5 +++++ dlls/ntdll/unix/thread.c | 20 ++++++++++++++++++-- dlls/ntdll/unix/unix_private.h | 1 + dlls/ntdll/unix/virtual.c | 9 +++++---- server/inproc_sync.c | 4 ++-- server/object.h | 1 + server/protocol.def | 2 ++ server/queue.c | 2 +- server/thread.c | 22 +++++++++++++++++++++- server/thread.h | 1 + 10 files changed, 57 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 25cc9bf0cbf..220abacd4d2 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -1677,6 +1677,11 @@ size_t server_init_process(void) inproc_device_fd = wine_server_receive_fd( &handle ); assert( handle == reply->inproc_device ); } + if (reply->queue_handle) + { + data->queue_sync_fd = wine_server_receive_fd( &handle ); + assert( handle == reply->queue_handle ); + } } } SERVER_END_REQ; diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 7f61a37bf2b..9eaae846970 100644 --- a/dlls/ntdll/unix/thread.c +++ b/dlls/ntdll/unix/thread.c @@ -1104,6 +1104,7 @@ static void contexts_from_server( CONTEXT *context, struct context_data server_c */ static DECLSPEC_NORETURN void pthread_exit_wrapper( int status ) { + close( ntdll_get_thread_data()->queue_sync_fd ); close( ntdll_get_thread_data()->wait_fd[0] ); close( ntdll_get_thread_data()->wait_fd[1] ); close( ntdll_get_thread_data()->reply_fd ); @@ -1324,7 +1325,7 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT struct object_attributes *objattr; struct ntdll_thread_data *thread_data; DWORD tid = 0; - int request_pipe[2]; + int request_pipe[2], queue_sync_fd = -1; TEB *teb; unsigned int status;
@@ -1376,6 +1377,11 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT
if (!access) access = THREAD_ALL_ACCESS;
+ /* 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( new_thread ) { req->process = wine_server_obj_handle( process ); @@ -1385,6 +1391,12 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT wine_server_add_data( req, objattr, len ); if (!(status = wine_server_call( req ))) { + obj_handle_t token; + if (reply->queue_handle) + { + queue_sync_fd = wine_server_receive_fd( &token ); + assert( token == reply->queue_handle ); + } *handle = wine_server_ptr_handle( reply->handle ); tid = reply->tid; } @@ -1392,6 +1404,8 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT } SERVER_END_REQ;
+ server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); + free( objattr ); if (status) { @@ -1412,7 +1426,8 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT set_thread_id( teb, GetCurrentProcessId(), tid );
thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; - thread_data->request_fd = request_pipe[1]; + thread_data->request_fd = request_pipe[1]; + thread_data->queue_sync_fd = queue_sync_fd; thread_data->start = start; thread_data->param = param;
@@ -1434,6 +1449,7 @@ done: if (status) { NtClose( *handle ); + if (queue_sync_fd != -1) close( queue_sync_fd ); close( request_pipe[1] ); return status; } diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index bd2d6a19334..98fb4dd6c74 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -108,6 +108,7 @@ struct ntdll_thread_data int request_fd; /* fd for sending server requests */ int reply_fd; /* fd for receiving server replies */ int wait_fd[2]; /* fd for sleeping server requests */ + int queue_sync_fd; /* inproc sync fd for message queue */ BOOL allow_writes; /* ThreadAllowWrites flags */ pthread_t pthread_id; /* pthread thread id */ void *kernel_stack; /* stack for thread startup and kernel syscalls */ diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 4b4d9d6cd7f..2b21715e1eb 100644 --- a/dlls/ntdll/unix/virtual.c +++ b/dlls/ntdll/unix/virtual.c @@ -4022,10 +4022,11 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; - thread_data->request_fd = -1; - thread_data->reply_fd = -1; - thread_data->wait_fd[0] = -1; - thread_data->wait_fd[1] = -1; + thread_data->request_fd = -1; + thread_data->reply_fd = -1; + thread_data->wait_fd[0] = -1; + thread_data->wait_fd[1] = -1; + thread_data->queue_sync_fd = -1; list_add_head( &teb_list, &thread_data->entry ); return teb; } diff --git a/server/inproc_sync.c b/server/inproc_sync.c index 3cbaf227897..c96bbc4074f 100644 --- a/server/inproc_sync.c +++ b/server/inproc_sync.c @@ -127,7 +127,7 @@ static void inproc_sync_destroy( struct object *obj ) close( sync->fd ); }
-static int get_inproc_sync_fd( struct object *obj, int *type ) +int get_inproc_sync_fd( struct object *obj, int *type ) { struct object *sync; int fd = -1; @@ -167,7 +167,7 @@ void reset_inproc_sync( struct inproc_sync *sync ) { }
-static int get_inproc_sync_fd( struct object *obj, int *type ) +int get_inproc_sync_fd( struct object *obj, int *type ) { return -1; } diff --git a/server/object.h b/server/object.h index 203734a565f..46e4ac7e78d 100644 --- a/server/object.h +++ b/server/object.h @@ -247,6 +247,7 @@ extern int get_inproc_device_fd(void); extern struct inproc_sync *create_inproc_internal_sync( int manual, int signaled ); extern void signal_inproc_sync( struct inproc_sync *sync ); extern void reset_inproc_sync( struct inproc_sync *sync ); +extern int get_inproc_sync_fd( struct object *obj, int *type );
/* serial functions */
diff --git a/server/protocol.def b/server/protocol.def index 09435813dc0..2bcdf0f1c9e 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1091,6 +1091,7 @@ struct obj_locator @REPLY thread_id_t tid; /* thread id */ obj_handle_t handle; /* thread handle (in the current process) */ + obj_handle_t queue_handle; /* inproc queue fd in flight with this handle */ @END
@@ -1127,6 +1128,7 @@ struct obj_locator timeout_t server_start; /* server start time */ unsigned int session_id; /* process session id */ obj_handle_t inproc_device;/* inproc device fd in flight with this handle */ + obj_handle_t queue_handle; /* inproc queue fd in flight with this handle */ data_size_t info_size; /* total size of startup info */ VARARG(machines,ushorts); /* array of supported machines */ @END diff --git a/server/queue.c b/server/queue.c index 0e286063285..7eb10913cda 100644 --- a/server/queue.c +++ b/server/queue.c @@ -328,7 +328,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ list_init( &queue->expired_timers ); for (i = 0; i < NB_MSG_KINDS; i++) list_init( &queue->msg_list[i] );
- if (get_inproc_device_fd() >= 0 && !(queue->inproc_sync = create_inproc_internal_sync( 1, 0 ))) goto error; + if (thread->queue_sync) queue->inproc_sync = (struct inproc_sync *)grab_object( thread->queue_sync ); if (!(queue->shared = alloc_shared_object())) goto error;
SHARED_WRITE_BEGIN( queue->shared, queue_shm_t ) diff --git a/server/thread.c b/server/thread.c index 64cd1a74702..ccb253e7ce5 100644 --- a/server/thread.c +++ b/server/thread.c @@ -397,6 +397,7 @@ static inline void init_thread_structure( struct thread *thread ) int i;
thread->sync = NULL; + thread->queue_sync = NULL; thread->unix_pid = -1; /* not known yet */ thread->unix_tid = -1; /* not known yet */ thread->context = NULL; @@ -560,6 +561,10 @@ struct thread *create_thread( int fd, struct process *process, const struct secu } if (!(thread->request_fd = create_anonymous_fd( &thread_fd_ops, fd, &thread->obj, 0 ))) goto error; if (!(thread->sync = create_event_sync( 1, 0 ))) goto error; + if (get_inproc_device_fd() >= 0) + { + if (!(thread->queue_sync = create_inproc_internal_sync( 1, 0 ))) goto error; + }
if (process->desktop) { @@ -654,6 +659,7 @@ static void destroy_thread( struct object *obj ) release_object( thread->process ); if (thread->id) free_ptid( thread->id ); if (thread->token) release_object( thread->token ); + if (thread->queue_sync) release_object( thread->queue_sync ); if (thread->sync) release_object( thread->sync ); }
@@ -1621,6 +1627,7 @@ DECL_HANDLER(new_thread) const struct security_descriptor *sd; const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, NULL ); int request_fd = thread_get_inflight_fd( current, req->request_fd ); + int fd, type;
if (!(process = get_process_from_handle( req->process, 0 ))) { @@ -1665,6 +1672,14 @@ DECL_HANDLER(new_thread) if ((reply->handle = alloc_handle_no_access_check( current->process, thread, req->access, objattr->attributes ))) { + if (request_fd != -1) /* first thread fds will be sent in init_first_thread */ + { + if (thread->queue_sync && (fd = get_inproc_sync_fd( (struct object *)thread->queue_sync, &type )) >= 0) + { + reply->queue_handle = get_thread_id( thread ) | 1; + send_client_fd( thread->process, fd, reply->queue_handle ); + } + } /* thread object will be released when the thread gets killed */ goto done; } @@ -1709,7 +1724,7 @@ static int init_thread( struct thread *thread, int reply_fd, int wait_fd ) DECL_HANDLER(init_first_thread) { struct process *process = current->process; - int fd; + int fd, type;
if (!init_thread( current, req->reply_fd, req->wait_fd )) return;
@@ -1738,6 +1753,11 @@ DECL_HANDLER(init_first_thread) reply->inproc_device = get_process_id( process ) | 1; send_client_fd( process, fd, reply->inproc_device ); } + if (current->queue_sync && (fd = get_inproc_sync_fd( (struct object *)current->queue_sync, &type )) >= 0) + { + reply->queue_handle = get_thread_id( current ) | 1; + send_client_fd( process, fd, reply->queue_handle ); + } }
/* initialize a new thread */ diff --git a/server/thread.h b/server/thread.h index b33a00d9f26..535a168ee1b 100644 --- a/server/thread.h +++ b/server/thread.h @@ -51,6 +51,7 @@ struct thread { struct object obj; /* object header */ struct event_sync *sync; /* sync object for wait/signal */ + struct inproc_sync *queue_sync; /* inproc sync for message queue */ struct list entry; /* entry in system-wide thread list */ struct list proc_entry; /* entry in per-process thread list */ struct list desktop_entry; /* entry in per-desktop thread list */