From: Elizabeth Figura zfigura@codeweavers.com
--- configure.ac | 1 + dlls/ntdll/unix/server.c | 31 +++++++++++------ dlls/ntdll/unix/sync.c | 14 ++++++++ dlls/ntdll/unix/unix_private.h | 2 ++ server/Makefile.in | 1 + server/inproc_sync.c | 61 ++++++++++++++++++++++++++++++++++ server/object.h | 4 +++ server/protocol.def | 1 + server/thread.c | 7 ++++ 9 files changed, 111 insertions(+), 11 deletions(-) create mode 100644 server/inproc_sync.c
diff --git a/configure.ac b/configure.ac index 6d093b52526..72d30e69fe9 100644 --- a/configure.ac +++ b/configure.ac @@ -677,6 +677,7 @@ AC_CHECK_HEADERS(\ linux/input.h \ linux/ioctl.h \ linux/major.h \ + linux/ntsync.h \ linux/param.h \ linux/serial.h \ linux/types.h \ diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c index 3969c2bb898..1613c163f33 100644 --- a/dlls/ntdll/unix/server.c +++ b/dlls/ntdll/unix/server.c @@ -961,7 +961,7 @@ void wine_server_send_fd( int fd ) * * Receive a file descriptor passed from the server. */ -static int receive_fd( obj_handle_t *handle ) +int wine_server_receive_fd( obj_handle_t *handle ) { struct iovec vec; struct msghdr msghdr; @@ -1156,7 +1156,7 @@ int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, if (type) *type = reply->type; if (options) *options = reply->options; access = reply->access; - if ((fd = receive_fd( &fd_handle )) != -1) + if ((fd = wine_server_receive_fd( &fd_handle )) != -1) { assert( wine_server_ptr_handle(fd_handle) == handle ); *needs_close = (!reply->cacheable || @@ -1570,6 +1570,7 @@ size_t server_init_process(void) { const char *arch = getenv( "WINEARCH" ); const char *env_socket = getenv( "WINESERVERSOCKET" ); + struct ntdll_thread_data *data = ntdll_get_thread_data(); obj_handle_t version; unsigned int i; int ret, reply_pipe; @@ -1609,7 +1610,7 @@ size_t server_init_process(void) pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );
/* receive the first thread request fd on the main socket */ - ntdll_get_thread_data()->request_fd = receive_fd( &version ); + data->request_fd = wine_server_receive_fd( &version );
#ifdef SO_PASSCRED /* now that we hopefully received the server_pid, disable SO_PASSCRED */ @@ -1644,16 +1645,24 @@ size_t server_init_process(void) req->unix_pid = getpid(); req->unix_tid = get_unix_tid(); req->reply_fd = reply_pipe; - req->wait_fd = ntdll_get_thread_data()->wait_fd[1]; + req->wait_fd = data->wait_fd[1]; req->debug_level = (TRACE_ON(server) != 0); wine_server_set_reply( req, supported_machines, sizeof(supported_machines) ); - ret = wine_server_call( req ); - pid = reply->pid; - tid = reply->tid; - peb->SessionId = reply->session_id; - info_size = reply->info_size; - server_start_time = reply->server_start; - supported_machines_count = wine_server_reply_size( reply ) / sizeof(*supported_machines); + if (!(ret = wine_server_call( req ))) + { + obj_handle_t handle; + pid = reply->pid; + tid = reply->tid; + peb->SessionId = reply->session_id; + info_size = reply->info_size; + server_start_time = reply->server_start; + supported_machines_count = wine_server_reply_size( reply ) / sizeof(*supported_machines); + if (reply->inproc_device) + { + inproc_device_fd = wine_server_receive_fd( &handle ); + assert( handle == reply->inproc_device ); + } + } } SERVER_END_REQ; close( reply_pipe ); diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c index 425543d0d6a..e861bffc874 100644 --- a/dlls/ntdll/unix/sync.c +++ b/dlls/ntdll/unix/sync.c @@ -57,6 +57,9 @@ #ifdef HAVE_KQUEUE # include <sys/event.h> #endif +#ifdef HAVE_LINUX_NTSYNC_H +# include <linux/ntsync.h> +#endif
#include "ntstatus.h" #define WIN32_NO_STATUS @@ -70,6 +73,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(sync);
HANDLE keyed_event = 0; +int inproc_device_fd = -1;
static const char *debugstr_timeout( const LARGE_INTEGER *timeout ) { @@ -305,53 +309,63 @@ static unsigned int validate_open_object_attributes( const OBJECT_ATTRIBUTES *at
static NTSTATUS inproc_release_semaphore( HANDLE handle, ULONG count, ULONG *prev_count ) { + if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED; }
static NTSTATUS inproc_query_semaphore( HANDLE handle, SEMAPHORE_BASIC_INFORMATION *info ) { + if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED; }
static NTSTATUS inproc_set_event( HANDLE handle, LONG *prev_state ) { + if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED; }
static NTSTATUS inproc_reset_event( HANDLE handle, LONG *prev_state ) { + if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED; }
static NTSTATUS inproc_pulse_event( HANDLE handle, LONG *prev_state ) { + if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED; }
static NTSTATUS inproc_query_event( HANDLE handle, EVENT_BASIC_INFORMATION *info ) { + if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED; }
static NTSTATUS inproc_release_mutex( HANDLE handle, LONG *prev_count ) { + if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED; }
static NTSTATUS inproc_query_mutex( HANDLE handle, MUTANT_BASIC_INFORMATION *info ) { + if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED; }
static NTSTATUS inproc_wait( DWORD count, const HANDLE *handles, BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { + if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED; }
static NTSTATUS inproc_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { + if (inproc_device_fd < 0) return STATUS_NOT_IMPLEMENTED; return STATUS_NOT_IMPLEMENTED; }
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index a735e54d9ff..756f1e91a3e 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -197,6 +197,7 @@ extern unsigned int supported_machines_count; extern USHORT supported_machines[8]; extern BOOL process_exiting; extern HANDLE keyed_event; +extern int inproc_device_fd; extern timeout_t server_start_time; extern sigset_t server_block_set; extern struct _KUSER_SHARED_DATA *user_shared_data; @@ -233,6 +234,7 @@ extern unsigned int server_queue_process_apc( HANDLE process, const union apc_ca extern int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, int *needs_close, enum server_fd_type *type, unsigned int *options ); extern void wine_server_send_fd( int fd ); +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); diff --git a/server/Makefile.in b/server/Makefile.in index 6e4e68d6ebf..57250fd0332 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -16,6 +16,7 @@ SOURCES = \ file.c \ handle.c \ hook.c \ + inproc_sync.c \ mach.c \ mailslot.c \ main.c \ diff --git a/server/inproc_sync.c b/server/inproc_sync.c new file mode 100644 index 00000000000..1bef2469e96 --- /dev/null +++ b/server/inproc_sync.c @@ -0,0 +1,61 @@ +/* + * In-process synchronization primitives + * + * Copyright (C) 2021-2022 Elizabeth Figura for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "config.h" + +#include <assert.h> +#include <stdint.h> +#include <stdio.h> + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "winternl.h" + +#include "file.h" +#include "handle.h" +#include "request.h" +#include "thread.h" + +#ifdef HAVE_LINUX_NTSYNC_H +# include <linux/ntsync.h> +#endif + +#ifdef NTSYNC_IOC_EVENT_READ + +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <unistd.h> + +int get_inproc_device_fd(void) +{ + static int fd = -2; + if (fd == -2) fd = open( "/dev/ntsync", O_CLOEXEC | O_RDONLY ); + return fd; +} + +#else /* NTSYNC_IOC_EVENT_READ */ + +int get_inproc_device_fd(void) +{ + return -1; +} + +#endif /* NTSYNC_IOC_EVENT_READ */ diff --git a/server/object.h b/server/object.h index 848f6dc977e..fc0bb51f5f5 100644 --- a/server/object.h +++ b/server/object.h @@ -237,6 +237,10 @@ extern void reset_event( struct event *event );
extern void abandon_mutexes( struct thread *thread );
+/* in-process synchronization functions */ + +extern int get_inproc_device_fd(void); + /* serial functions */
int get_serial_async_timeout(struct object *obj, int type, int count); diff --git a/server/protocol.def b/server/protocol.def index 22470e33ae0..4429159a720 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1121,6 +1121,7 @@ struct obj_locator thread_id_t tid; /* thread id of the new thread */ 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 */ data_size_t info_size; /* total size of startup info */ VARARG(machines,ushorts); /* array of supported machines */ @END diff --git a/server/thread.c b/server/thread.c index 05ec6a4ec00..fb66fac8eef 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1694,6 +1694,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;
if (!init_thread( current, req->reply_fd, req->wait_fd )) return;
@@ -1716,6 +1717,12 @@ DECL_HANDLER(init_first_thread) reply->server_start = server_start_time; set_reply_data( supported_machines, min( supported_machines_count * sizeof(unsigned short), get_reply_max_size() )); + + if ((fd = get_inproc_device_fd()) >= 0) + { + reply->inproc_device = get_process_id( process ) | 1; + send_client_fd( process, fd, reply->inproc_device ); + } }
/* initialize a new thread */