I've updated my in-process wineserver hack, cleaned it up a bit more and fixed a few problems. So, at least in Star Wars Battlefront II, the sound and HID problems are fixed (the "select" server call must be made via the pipe). I presume there are other server calls with similar properties. Also, the wineserver now exits properly and cleans up it's instance when the main process terminates. Changed the enabling enviroment variable to "WINESPEEDHACK".
So what would it take for this to be integrated into wine as an optional feature?
>From 481067ba2ad4813548e134a0f8108dfec2534aa3 Mon Sep 17 00:00:00 2001 From: Daniel Santos <[email protected]> Date: Thu, 19 Jan 2012 04:01:01 -0600 Subject: Hack for in-process wine-server (a.k.a., "Dirty speed hack") MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------1.7.3.4" This is a multi-part message in MIME format. --------------1.7.3.4 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- dlls/ntdll/server.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++-- dlls/ntdll/sync.c | 2 +- include/wine/server.h | 1 + server/Makefile.in | 32 +++++++++++- server/fd.c | 21 ++++++++ server/main.c | 17 ++++++- server/object.h | 11 ++++ server/request.c | 87 ++++++++++++++++++++++++++++++++ 8 files changed, 296 insertions(+), 8 deletions(-) --------------1.7.3.4 Content-Type: text/x-patch; name="0001-Hack-for-in-process-wine-server-a.k.a.-Dirty-speed-hac.txt" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="0001-Hack-for-in-process-wine-server-a.k.a.-Dirty-speed-hac.txt" diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index 8a01d22..3f7a957 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -74,6 +74,31 @@ WINE_DEFAULT_DEBUG_CHANNEL(server); +/************************************************************************************************** + * In-Process Server (a.k.a., "dirty speed hack") Laundry List + * + * - Build libwineserver rather or not --with-wine-tools is specified. It's currently built only + * when the server is built, but we need both 64 & 32 bit versions to run PEs of either type. The + * make targets (currently in server/Makefile.in) should probably be moved to + * libs/libwineserver/Makefile.in or other autotools code modofied so it's built independent of + * the wineserver. + * - Properly terminate wineserver when primary program exits. (Currently, auxiliary processes + * stick around and have to be manually killed after the main process/wineserver terminates. Also + * lock and socket files have to be manually cleaned up. + * - Use more portable synchronization mechanism in new server code (currently, we're just directly + * including pthread.h and using a pthread mutex). + * - Discover any other server calls (aside from init_thread and select) that should only be called + * via the pipe and change their wine_server_call function to wine_server_call_pipe. + * - Get rid of all fatal_{,p}error calls made outside of initialization. + * - Properly document new functions & data. + * + * Potential enhancements + * - Add at least one alternate server calling convention to reduce memcpy calls. + * - Tweak in-proc server call to copy less data (if possible without the above). + * - If PE is 32 bit, it must run a 32 bit wineserver and visa versa. This can create problems if + * the WINEPREFIX is a different arch (32 vs 64). The solution is probably to thunk. + *************************************************************************************************/ + /* Some versions of glibc don't define this */ #ifndef SCM_RIGHTS #define SCM_RIGHTS 1 @@ -102,6 +127,7 @@ static const enum cpu_type client_cpu = CPU_ARM; unsigned int server_cpus = 0; int is_wow64 = FALSE; +void (*call_req_handler_inproc)(void *req) = 0; timeout_t server_start_time = 0; /* time of server startup */ @@ -284,6 +310,25 @@ unsigned int wine_server_call( void *req_ptr ) sigset_t old_set; unsigned int ret; + if(call_req_handler_inproc) + { + call_req_handler_inproc(req); + return req->u.reply.reply_header.error; + } + + pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set ); + ret = send_request( req ); + if (!ret) ret = wait_reply( req ); + pthread_sigmask( SIG_SETMASK, &old_set, NULL ); + return ret; +} + +unsigned int wine_server_call_pipe( void *req_ptr ) +{ + struct __server_request_info * const req = req_ptr; + sigset_t old_set; + unsigned int ret; + pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set ); ret = send_request( req ); if (!ret) ret = wait_reply( req ); @@ -291,6 +336,13 @@ unsigned int wine_server_call( void *req_ptr ) return ret; } +unsigned int wine_server_call_inproc( void *req_ptr ) +{ + struct __server_request_info * const req = req_ptr; + + call_req_handler_inproc(req); + return req->u.reply.reply_header.error; +} /*********************************************************************** * server_enter_uninterrupted_section @@ -686,6 +738,11 @@ int server_pipe( int fd[2] ) return ret; } +/* Theory: start_server should only get called by one wine process (hopefully) + * so we don't have to screw with not loading the libwineserver.so in each + * process (therefore, screwing everythign up) + */ + /*********************************************************************** * start_server @@ -695,11 +752,14 @@ int server_pipe( int fd[2] ) static void start_server(void) { static int started; /* we only try once */ - char *argv[3]; + static char *argv[4]; static char wineserver[] = "server/wineserver"; static char debug[] = "-d"; + static char foreground[] = "-f"; - if (!started) + if (started) return; + + if(!getenv("WINESPEEDHACK")) { int status; int pid = fork(); @@ -716,8 +776,71 @@ static void start_server(void) status = WIFEXITED(status) ? WEXITSTATUS(status) : 1; if (status == 2) return; /* server lock held by someone else, will retry later */ if (status) exit(status); /* server failed */ - started = 1; } + else + { + char errmsg[1024]; + static void *ws_lib_handle; + void *(*ws_start)(void *); + pthread_t ws_thread; + struct timespec wait_time = {0, 500}; + void *wineserver_ret; +#if 0 /* do we need to try to boost wineserver's thread priority on gnu/linux? */ + pthread_attr_t attr; + struct sched_param sched_param; + int sched_pol = sched_getscheduler(getpid()); + int sched_max_pri = sched_get_priority_max(sched_pol); +#endif + + argv[0] = wineserver; + argv[1] = foreground; + argv[2] = TRACE_ON(server) ? debug : NULL; + argv[3] = NULL; + + fprintf(stderr, "Loading libwineserver...\n"); + + if(!(ws_lib_handle = wine_dlopen("libwineserver.so", RTLD_NOW, errmsg, sizeof(errmsg)))) + fatal_error("could not load wineserver lib: %s", errmsg); + + if(!(ws_start = wine_dlsym(ws_lib_handle, "wineserver_start_inproc", errmsg, sizeof(errmsg)))) + fatal_error("failed to find libwineserver entry point: %s", errmsg); + + call_req_handler_inproc = wine_dlsym(ws_lib_handle, "call_req_handler_inproc", errmsg, + sizeof(errmsg)); + if(!call_req_handler_inproc) + fatal_error("failed to find symbol call_req_handler_inproc in libwineserver: %s", + errmsg); + +#if 0 + fprintf(stderr, "sched_pol = %d, sched_max_pri = %d\n", sched_pol, sched_max_pri); + if(pthread_attr_init(&attr)) + fatal_perror("pthread_attr_init"); + + if(pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) + fatal_perror("pthread_attr_setinheritsched"); + + if(pthread_attr_setschedpolicy(&attr, sched_pol)) + fatal_perror("pthread_attr_setschedpolicy"); + + sched_param.sched_priority = sched_max_pri; + if(pthread_attr_setschedparam(&attr, &sched_param)) + fatal_perror("pthread_attr_setschedparam"); + + if(pthread_create(&ws_thread, &attr, ws_start, argv)) +#else + if(pthread_create(&ws_thread, NULL, ws_start, argv)) +#endif + fatal_perror("pthread_create failed"); + + /* FIXME: needs better mechanism to make sure wineserver started (this just waits 500 mS + * and if the thread doesn't terminate, presumes all is good). Or decide that no mechanism + * is needed. */ + if(!pthread_timedjoin_np(ws_thread, &wineserver_ret, &wait_time)) { + fatal_error("wineserver thread exited :("); + } + fprintf(stderr, "libwineserver loaded\n"); + } + started = 1; } @@ -1095,7 +1218,9 @@ size_t server_init_thread( void *entry_point ) req->wait_fd = ntdll_get_thread_data()->wait_fd[1]; req->debug_level = (TRACE_ON(server) != 0); req->cpu = client_cpu; - ret = wine_server_call( req ); + /* call_req_handler_inproc in server doesn't know how to handle this call properly, so it + * should always be called via the conventional call mechanism. */ + ret = wine_server_call_pipe( req ); NtCurrentTeb()->ClientId.UniqueProcess = ULongToHandle(reply->pid); NtCurrentTeb()->ClientId.UniqueThread = ULongToHandle(reply->tid); info_size = reply->info_size; diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index f759ce6..8cdded7 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -1113,7 +1113,7 @@ NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UIN req->timeout = abs_timeout; wine_server_add_data( req, &result, sizeof(result) ); wine_server_add_data( req, obj_handles, count * sizeof(*obj_handles) ); - ret = wine_server_call( req ); + ret = wine_server_call_pipe( req ); abs_timeout = reply->timeout; apc_handle = reply->apc_handle; call = reply->call; diff --git a/include/wine/server.h b/include/wine/server.h index d573d1f..de9a286 100644 --- a/include/wine/server.h +++ b/include/wine/server.h @@ -50,6 +50,7 @@ struct __server_request_info }; extern unsigned int wine_server_call( void *req_ptr ); +extern unsigned int wine_server_call_pipe( void *req_ptr ); extern void CDECL wine_server_send_fd( int fd ); extern int CDECL wine_server_fd_to_handle( int fd, unsigned int access, unsigned int attributes, HANDLE *handle ); extern int CDECL wine_server_handle_to_fd( HANDLE handle, unsigned int access, int *unix_fd, unsigned int *options ); diff --git a/server/Makefile.in b/server/Makefile.in index a2f1a52..03ceb79 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -1,5 +1,13 @@ DEFS = -D__WINESRC__ EXTRALIBS = @LIBPOLL@ +VERSION = 1.0 +SOVERSION = 1 +MODULE = libwineserver.$(LIBEXT) +SONAME = libwineserver.so.$(SOVERSION) +CFLAGS = @CFLAGS@ -fPIC + +SO_INSTALLDIRS = $(DESTDIR)$(libdir) + C_SRCS = \ async.c \ @@ -53,28 +61,48 @@ EXTRA_MANPAGES = wineserver.de.man wineserver.fr.man INSTALLDIRS = \ $(DESTDIR)$(bindir) \ + $(DESTDIR)$(libdir) \ $(DESTDIR)$(mandir)/man$(prog_manext) \ $(DESTDIR)$(mandir)/de.UTF-8/man$(prog_manext) \ $(DESTDIR)$(mandir)/fr.UTF-8/man$(prog_manext) -all: $(PROGRAMS) +all: $(PROGRAMS) $(MODULE) @MAKE_RULES@ wineserver: $(OBJS) $(CC) -o $@ $(OBJS) $(LIBWINE) $(LIBPORT) $(LDFLAGS) $(LIBS) $(LDRPATH_LOCAL) +libwineserver.so.$(VERSION): $(OBJS) $(VERSCRIPT) Makefile.in + $(LDSHARED) $(OBJS) $(EXTRALIBS) $(LDFLAGS) $(LIBS) -o $@ + +libwineserver.so.$(SOVERSION): libwineserver.so.$(VERSION) + $(RM) $@ && $(LN_S) libwineserver.so.$(VERSION) $@ + +libwineserver.so: libwineserver.so.$(SOVERSION) + $(RM) $@ && $(LN_S) libwineserver.so.$(SOVERSION) $@ + wineserver-installed: $(OBJS) $(CC) -o $@ $(OBJS) $(LIBWINE) $(LIBPORT) $(LDFLAGS) $(LIBS) $(LDRPATH_INSTALL) -install install-lib:: wineserver-installed $(DESTDIR)$(bindir) install-man-pages +install:: wineserver-installed $(DESTDIR)$(bindir) install-lib install-man-pages $(INSTALL_PROGRAM) wineserver-installed $(DESTDIR)$(bindir)/wineserver +install-lib:: libwineserver.so.$(VERSION) $(DESTDIR)$(libdir) + $(INSTALL_PROGRAM) libwineserver.so.$(VERSION) $(DESTDIR)$(libdir) + cd $(DESTDIR)$(libdir) \ + && $(RM) libwineserver.so libwineserver.so.$(SOVERSION) \ + && $(LN_S) libwineserver.so.$(VERSION) libwineserver.so.$(SOVERSION) \ + && $(LN_S) libwineserver.so.$(VERSION) libwineserver.so + install-man-pages:: $(EXTRA_MANPAGES) $(INSTALLDIRS) $(INSTALL_DATA) wineserver.de.man $(DESTDIR)$(mandir)/de.UTF-8/man$(prog_manext)/wineserver.$(prog_manext) $(INSTALL_DATA) wineserver.fr.man $(DESTDIR)$(mandir)/fr.UTF-8/man$(prog_manext)/wineserver.$(prog_manext) uninstall:: $(RM) $(DESTDIR)$(bindir)/wineserver + $(RM) $(DESTDIR)$(libdir)/libwineserver.so.$(VERSION) + $(RM) $(DESTDIR)$(libdir)/libwineserver.so.$(SOVERSION) + $(RM) $(DESTDIR)$(libdir)/libwineserver.so $(RM) $(DESTDIR)$(mandir)/de.UTF-8/man$(prog_manext)/wineserver.$(prog_manext) $(RM) $(DESTDIR)$(mandir)/fr.UTF-8/man$(prog_manext)/wineserver.$(prog_manext) diff --git a/server/fd.c b/server/fd.c index a8b3a5f..513197e 100644 --- a/server/fd.c +++ b/server/fd.c @@ -502,6 +502,19 @@ static inline void remove_epoll_user( struct fd *fd, int user ) } } +/* Obtain lock on wineserver_mutex, but only if we're running in-process */ +static void inline wineserver_lock() +{ + if(wineserver_is_inproc && pthread_mutex_lock(&wineserver_mutex)) + perror("wineserver: pthread_mutex_lock"); +} + +static void inline wineserver_unlock() +{ + if(wineserver_is_inproc && pthread_mutex_unlock(&wineserver_mutex)) + perror("wineserver: pthread_mutex_unlock"); +} + static inline void main_loop_epoll(void) { int i, ret, timeout; @@ -521,7 +534,9 @@ static inline void main_loop_epoll(void) if (!active_users) break; /* last user removed by a timeout */ if (epoll_fd == -1) break; /* an error occurred with epoll */ + wineserver_unlock(); ret = epoll_wait( epoll_fd, events, sizeof(events)/sizeof(events[0]), timeout ); + wineserver_lock(); set_current_time(); /* put the events into the pollfd array first, like poll does */ @@ -626,6 +641,7 @@ static inline void main_loop_epoll(void) if (!active_users) break; /* last user removed by a timeout */ if (kqueue_fd == -1) break; /* an error occurred with kqueue */ + wineserver_unlock(); if (timeout != -1) { struct timespec ts; @@ -635,6 +651,7 @@ static inline void main_loop_epoll(void) ret = kevent( kqueue_fd, NULL, 0, events, sizeof(events)/sizeof(events[0]), &ts ); } else ret = kevent( kqueue_fd, NULL, 0, events, sizeof(events)/sizeof(events[0]), NULL ); + wineserver_lock(); set_current_time(); @@ -730,6 +747,7 @@ static inline void main_loop_epoll(void) if (!active_users) break; /* last user removed by a timeout */ if (port_fd == -1) break; /* an error occurred with event completion */ + wineserver_unlock(); if (timeout != -1) { struct timespec ts; @@ -739,6 +757,7 @@ static inline void main_loop_epoll(void) ret = port_getn( port_fd, events, sizeof(events)/sizeof(events[0]), &nget, &ts ); } else ret = port_getn( port_fd, events, sizeof(events)/sizeof(events[0]), &nget, NULL ); + wineserver_lock(); if (ret == -1) break; /* an error occurred with event completion */ @@ -889,7 +908,9 @@ void main_loop(void) if (!active_users) break; /* last user removed by a timeout */ + wineserver_unlock(); ret = poll( pollfd, nb_users, timeout ); + wineserver_lock(); set_current_time(); if (ret > 0) diff --git a/server/main.c b/server/main.c index 2d841e8..72d92e0 100644 --- a/server/main.c +++ b/server/main.c @@ -41,6 +41,7 @@ /* command-line options */ int debug_level = 0; int foreground = 0; +int wineserver_is_inproc = 0; timeout_t master_socket_timeout = 3 * -TICKS_PER_SEC; /* master socket timeout, default is 3 seconds */ const char *server_argv0; @@ -125,7 +126,7 @@ static void sigterm_handler( int signum ) exit(1); /* make sure atexit functions get called */ } -int main( int argc, char *argv[] ) +static int wineserver_start( int argc, char *argv[] ) { setvbuf( stderr, NULL, _IOLBF, 0 ); parse_args( argc, argv ); @@ -148,3 +149,17 @@ int main( int argc, char *argv[] ) main_loop(); return 0; } + +int main( int argc, char *argv[] ) +{ + return wineserver_start(argc, argv); +} + +void *wineserver_start_inproc(char *argv[]) +{ + int argc = 0; + while (argv[argc]) ++argc; + wineserver_is_inproc = 1; + wineserver_start(argc, argv); + return 0; +} diff --git a/server/object.h b/server/object.h index a8cb327..51de21a 100644 --- a/server/object.h +++ b/server/object.h @@ -25,10 +25,21 @@ #include <sys/poll.h> #endif +#ifdef HAVE_PTHREAD_H +#include <pthread.h> +#else +/* FIXME */ +#endif + #include <sys/time.h> #include "wine/server_protocol.h" #include "wine/list.h" +/* FIXME: need more portable locking mechanism */ + +extern pthread_mutex_t wineserver_mutex; /* Synchronize access to wineserver data between threads */ +extern int wineserver_is_inproc; + #define DEBUG_OBJECTS /* kernel objects */ diff --git a/server/request.c b/server/request.c index 05c7464..4c511ec 100644 --- a/server/request.c +++ b/server/request.c @@ -51,6 +51,7 @@ #ifdef HAVE_POLL_H #include <poll.h> #endif +#include <pthread.h> #include "ntstatus.h" #define WIN32_NO_STATUS @@ -64,6 +65,7 @@ #include "process.h" #define WANT_REQUEST_HANDLERS #include "request.h" +#include "wine/server.h" /* Some versions of glibc don't define this */ #ifndef SCM_RIGHTS @@ -126,6 +128,8 @@ int config_dir_fd = -1; /* file descriptor for the config dir */ static struct master_socket *master_socket; /* the master socket object */ static struct timeout_user *master_timeout; +pthread_mutex_t wineserver_mutex; /* keep calls from in-process wine app serialized with out-of-process calls */ + /* complain about a protocol error and terminate the client connection */ void fatal_protocol_error( struct thread *thread, const char *err, ... ) { @@ -254,6 +258,79 @@ static void send_reply( union generic_reply *reply ) fatal_protocol_perror( current, "reply write" ); } +void call_req_handler_inproc( void * req_ptr ) { + struct __server_request_info *req = (struct __server_request_info *)req_ptr; + union generic_reply reply; + struct thread *thread; + enum request reqnum; + size_t max_reply_size = req->u.req.request_header.reply_size; + char *p; + size_t i; + + if(pthread_mutex_lock(&wineserver_mutex)) + fatal_perror("call_req_handler_inproc: pthread_mutex_lock"); + + thread = get_thread_from_id(GetCurrentThreadId()); + if(!thread) thread = get_thread_from_pid(getpid()); + if(!thread) fatal_perror("call_req_handler_inproc: failed to get thread object"); + + grab_object(thread); + + memcpy(&(thread->req), req, sizeof(thread->req)); + p = (char *)malloc(req->u.req.request_header.request_size); + if(!p) fatal_perror("malloc"); + thread->req_data = p; + for(i = 0; i < req->data_count; ++i) { + memcpy(p, req->data[i].ptr, req->data[i].size); + p += req->data[i].size; + } + + reqnum = thread->req.request_header.req; + + current = thread; + current->reply_size = 0; + clear_error(); + memset( &reply, 0, sizeof(reply) ); + + if (debug_level) trace_request(); + + if (reqnum < REQ_NB_REQUESTS) + req_handlers[reqnum]( ¤t->req, &reply ); + else + set_error( STATUS_NOT_IMPLEMENTED ); + + /* copy back the reply over the request union/struct (but not the whole __server_request_info) */ + + free (thread->req_data); + thread->req_data = NULL; + + if(current) { + memcpy(req, &reply, sizeof(reply)); + req->u.reply.reply_header.error = current->error; + req->u.reply.reply_header.reply_size = current->reply_size; + + if (debug_level) trace_reply( reqnum, &req->u.reply ); + + if(req->reply_data) { + /* FIXME: clean this up */ + if(current->reply_size > max_reply_size) { + fatal_error("reply buffer too small, supplied %u bytes, requires %u\n", + max_reply_size, current->reply_size); + } + memcpy(req->reply_data, current->reply_data, current->reply_size); + free(current->reply_data); + } + + current->reply_data = NULL; + current = NULL; + } + + release_object( thread ); + + if(pthread_mutex_unlock(&wineserver_mutex)) + fatal_perror("call_req_handler_inproc: pthread_mutex_unlock"); +} + /* call a request handler */ static void call_req_handler( struct thread *thread ) { @@ -758,6 +835,11 @@ void open_master_socket(void) assert( sizeof(union generic_request) == sizeof(struct request_max_size) ); assert( sizeof(union generic_reply) == sizeof(struct request_max_size) ); + /* init mutex for serializing in-process and out-of-process requests */ + if(pthread_mutex_init(&wineserver_mutex, NULL)) { + fatal_perror("pthread_mutex_init failed"); + } + /* make sure the stdio fds are open */ fd = open( "/dev/null", O_RDWR ); while (fd >= 0 && fd <= 2) fd = dup( fd ); @@ -840,5 +922,10 @@ void close_master_socket( timeout_t timeout ) if (master_timeout) /* cancel previous timeout */ remove_timeout_user( master_timeout ); + if(pthread_mutex_destroy(&wineserver_mutex)) { + perror("pthread_mutex_destroy"); + } + memset(&wineserver_mutex, 0, sizeof(wineserver_mutex)); + master_timeout = add_timeout_user( timeout, close_socket_timeout, NULL ); } --------------1.7.3.4--
>From 62ce729510d87909775f2d2720735d2d4c12da1a Mon Sep 17 00:00:00 2001 From: Daniel Santos <[email protected]> Date: Sun, 22 Jan 2012 04:50:38 -0600 Subject: Proper termination of wineserver and all processes when primary program terminates MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="------------1.7.3.4" This is a multi-part message in MIME format. --------------1.7.3.4 Content-Type: text/plain; charset=UTF-8; format=fixed Content-Transfer-Encoding: 8bit --- dlls/ntdll/server.c | 3 --- server/fd.c | 13 ------------- server/main.c | 13 +++++++++++++ server/object.h | 13 +++++++++++++ server/process.c | 3 ++- 5 files changed, 28 insertions(+), 17 deletions(-) --------------1.7.3.4 Content-Type: text/x-patch; name="0002-Proper-termination-of-wineserver-and-all-processes-whe.txt" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="0002-Proper-termination-of-wineserver-and-all-processes-whe.txt" diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index 3f7a957..d0ad25b 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -82,9 +82,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(server); * make targets (currently in server/Makefile.in) should probably be moved to * libs/libwineserver/Makefile.in or other autotools code modofied so it's built independent of * the wineserver. - * - Properly terminate wineserver when primary program exits. (Currently, auxiliary processes - * stick around and have to be manually killed after the main process/wineserver terminates. Also - * lock and socket files have to be manually cleaned up. * - Use more portable synchronization mechanism in new server code (currently, we're just directly * including pthread.h and using a pthread mutex). * - Discover any other server calls (aside from init_thread and select) that should only be called diff --git a/server/fd.c b/server/fd.c index 513197e..f0aa4b7 100644 --- a/server/fd.c +++ b/server/fd.c @@ -502,19 +502,6 @@ static inline void remove_epoll_user( struct fd *fd, int user ) } } -/* Obtain lock on wineserver_mutex, but only if we're running in-process */ -static void inline wineserver_lock() -{ - if(wineserver_is_inproc && pthread_mutex_lock(&wineserver_mutex)) - perror("wineserver: pthread_mutex_lock"); -} - -static void inline wineserver_unlock() -{ - if(wineserver_is_inproc && pthread_mutex_unlock(&wineserver_mutex)) - perror("wineserver: pthread_mutex_unlock"); -} - static inline void main_loop_epoll(void) { int i, ret, timeout; diff --git a/server/main.c b/server/main.c index 72d92e0..d9ce608 100644 --- a/server/main.c +++ b/server/main.c @@ -155,11 +155,24 @@ int main( int argc, char *argv[] ) return wineserver_start(argc, argv); } +void *ws_shutdown(void *smartie) { + shutdown_master_socket(); + return NULL; +} + +void wineserver_atexit (void) +{ + wineserver_lock(); + shutdown_master_socket(); + wineserver_unlock(); +} + void *wineserver_start_inproc(char *argv[]) { int argc = 0; while (argv[argc]) ++argc; wineserver_is_inproc = 1; + if(atexit(wineserver_atexit)) fatal_perror("failed to set atexit func"); wineserver_start(argc, argv); return 0; } diff --git a/server/object.h b/server/object.h index 51de21a..a6cb0a3 100644 --- a/server/object.h +++ b/server/object.h @@ -40,6 +40,19 @@ extern pthread_mutex_t wineserver_mutex; /* Synchronize access to wineserver data between threads */ extern int wineserver_is_inproc; +/* Obtain lock on wineserver_mutex, but only if we're running in-process */ +static void inline wineserver_lock() +{ + if(wineserver_is_inproc && pthread_mutex_lock(&wineserver_mutex)) + perror("wineserver: pthread_mutex_lock"); +} + +static void inline wineserver_unlock() +{ + if(wineserver_is_inproc && pthread_mutex_unlock(&wineserver_mutex)) + perror("wineserver: pthread_mutex_unlock"); +} + #define DEBUG_OBJECTS /* kernel objects */ diff --git a/server/process.c b/server/process.c index de3b594..3ef03d0 100644 --- a/server/process.c +++ b/server/process.c @@ -588,7 +588,8 @@ static void kill_all_processes(void) LIST_FOR_EACH_ENTRY( process, &process_list, struct process, entry ) { - if (process->running_threads) break; + /* when in-process, don't try to kill self */ + if (process->running_threads && process->unix_pid != getpid()) break; } if (&process->entry == &process_list) break; /* no process found */ terminate_process( process, NULL, 1 ); --------------1.7.3.4--
