From: Rémi Bernon rbernon@codeweavers.com
--- dlls/ntdll/unix/server.c | 28 +++++++++++++++++++++++++--- dlls/ntdll/unix/thread.c | 3 ++- dlls/ntdll/unix/unix_private.h | 3 ++- 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 | 21 ++++++++++++++++++++- server/thread.h | 1 + 10 files changed, 61 insertions(+), 13 deletions(-)
diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 25cc9bf0cbf..d82b8073c9d 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; @@ -1768,25 +1773,42 @@ void server_init_process_done(void) * * Send an init thread request. */ -void server_init_thread( void *entry_point, BOOL *suspend ) +void server_init_thread( struct ntdll_thread_data *data, BOOL *suspend ) { + sigset_t sigset; void *teb; int reply_pipe = init_thread_pipe();
/* always send the native TEB */ if (!(teb = NtCurrentTeb64())) teb = NtCurrentTeb();
+ /* 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( init_thread ) { req->unix_tid = get_unix_tid(); req->teb = wine_server_client_ptr( teb ); - req->entry = wine_server_client_ptr( entry_point ); + req->entry = wine_server_client_ptr( data->start ); req->reply_fd = reply_pipe; req->wait_fd = ntdll_get_thread_data()->wait_fd[1]; - wine_server_call( req ); + if (!wine_server_call( req )) + { + obj_handle_t handle; + if (reply->queue_handle) + { + data->queue_sync_fd = wine_server_receive_fd( &handle ); + assert( handle == reply->queue_handle ); + } + } *suspend = reply->suspend; } SERVER_END_REQ; + + server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); + close( reply_pipe ); }
diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c index 7f61a37bf2b..a6f09b068b5 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 ); @@ -1126,7 +1127,7 @@ static void start_thread( TEB *teb ) thread_data->syscall_trace = TRACE_ON(syscall); thread_data->pthread_id = pthread_self(); pthread_setspecific( teb_key, teb ); - server_init_thread( thread_data->start, &suspend ); + server_init_thread( thread_data, &suspend ); signal_start_thread( thread_data->start, thread_data->param, suspend, teb ); }
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index bd2d6a19334..887ff5a24f5 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 */ @@ -240,7 +241,7 @@ extern int wine_server_receive_fd( obj_handle_t *handle ); extern void process_exit_wrapper( int status ) DECLSPEC_NORETURN; extern size_t server_init_process(void); extern void server_init_process_done(void); -extern void server_init_thread( void *entry_point, BOOL *suspend ); +extern void server_init_thread( struct ntdll_thread_data *data, BOOL *suspend ); extern int server_pipe( int fd[2] );
extern void fpux_to_fpu( I386_FLOATING_SAVE_AREA *fpu, const XSAVE_FORMAT *fpux ); 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 5c7dc1ae770..a0973f42cca 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 af84f1fa6a2..2a475b84c59 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_event_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 f6f0324054d..d5b41b1eb5a 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1127,6 +1127,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 @@ -1141,6 +1142,7 @@ struct obj_locator client_ptr_t entry; /* entry point (in thread address space) */ @REPLY int suspend; /* is thread suspended? */ + obj_handle_t queue_handle; /* inproc queue fd in flight with this handle */ @END
diff --git a/server/queue.c b/server/queue.c index 7623485d676..c51a29c6a8c 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_event_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 a725800fb42..d37d1a609f1 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_event_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 ); }
@@ -1719,7 +1725,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;
@@ -1748,11 +1754,18 @@ 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 ) | 3; + send_client_fd( process, fd, reply->queue_handle ); + } }
/* initialize a new thread */ DECL_HANDLER(init_thread) { + int fd, type; + if (!init_thread( current, req->reply_fd, req->wait_fd )) return;
if (!is_valid_address(req->teb)) @@ -1772,6 +1785,12 @@ DECL_HANDLER(init_thread) set_thread_affinity( current, current->affinity );
reply->suspend = (is_thread_suspended( current ) || current->context != NULL); + + 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( current->process, fd, reply->queue_handle ); + } }
/* terminate a thread */ diff --git a/server/thread.h b/server/thread.h index 9b6e0c2a03b..0952257ed84 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 */