diff --git a/dix/main.c b/dix/main.c index db4347341..e265e6566 100644 --- a/dix/main.c +++ b/dix/main.c @@ -237,12 +237,11 @@ static int indexForScanlinePad[ 65 ] = { #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif -#ifdef __APPLE__ -void DarwinHandleGUI(int argc, char **argv, char **envp); +#ifdef XQUARTZ +int dix_main(int argc, char *argv[], char *envp[]) +#else +int main(int argc, char *argv[], char *envp[]) #endif - -int -main(int argc, char *argv[], char *envp[]) { int i, j, k, error; char *xauthfile; @@ -256,13 +255,6 @@ main(int argc, char *argv[], char *envp[]) PrinterInitGlobals(); #endif -#ifdef XQUARTZ - /* Quartz support on Mac OS X requires that the Cocoa event loop be in - * the main thread. This allows the X server main to be called again - * from another thread. */ - DarwinHandleGUI(argc, argv, envp); -#endif - CheckUserParameters(argc, argv, envp); CheckUserAuthorization(); diff --git a/hw/xquartz/X11Application.h b/hw/xquartz/X11Application.h index 47c605c67..3869df92f 100644 --- a/hw/xquartz/X11Application.h +++ b/hw/xquartz/X11Application.h @@ -71,7 +71,7 @@ void X11ApplicationSetCanQuit (int state); void X11ApplicationServerReady (void); void X11ApplicationShowHideMenubar (int state); -void X11ApplicationMain(int argc, const char **argv, void (*server_thread) (void *), void *server_arg); +void X11ApplicationMain(int argc, const char **argv); extern int X11EnableKeyEquivalents; extern int quartzHasRoot, quartzEnableRootless; diff --git a/hw/xquartz/X11Application.m b/hw/xquartz/X11Application.m index eefa45fbf..76804373e 100644 --- a/hw/xquartz/X11Application.m +++ b/hw/xquartz/X11Application.m @@ -35,6 +35,7 @@ #include "quartzForeground.h" #include "quartzCommon.h" + #import "X11Application.h" # include "darwin.h" @@ -45,7 +46,9 @@ # include "micmap.h" #include #include + #include +extern pthread_cond_t server_can_start_cond; #define DEFAULTS_FILE "/usr/X11/lib/X11/xserver/Xquartz.plist" @@ -732,19 +735,6 @@ void X11ApplicationShowHideMenubar (int state) { [n release]; } -static pthread_t create_thread (void *func, void *arg) { - pthread_attr_t attr; - pthread_t tid; - - pthread_attr_init (&attr); - pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); - pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); - pthread_create (&tid, &attr, func, arg); - pthread_attr_destroy (&attr); - - return tid; -} - static void check_xinitrc (void) { char *tem, buf[1024]; NSString *msg; @@ -786,7 +776,7 @@ environment?", @"Startup xinitrc dialog"); [X11App prefs_synchronize]; } -void X11ApplicationMain (int argc, const char **argv, void (*server_thread) (void *), void *server_arg) { +void X11ApplicationMain (int argc, const char **argv) { NSAutoreleasePool *pool; #ifdef DEBUG @@ -812,16 +802,9 @@ void X11ApplicationMain (int argc, const char **argv, void (*server_thread) (voi /* Calculate the height of the menubar so we can avoid it. */ aquaMenuBarHeight = NSHeight([[NSScreen mainScreen] frame]) - NSMaxY([[NSScreen mainScreen] visibleFrame]); - - APPKIT_THREAD = pthread_self(); - SERVER_THREAD = create_thread (server_thread, server_arg); - if (!SERVER_THREAD) { - ErrorF("can't create secondary thread\n"); - exit (1); - } - - QuartzMoveToForeground(); + /* Tell the server thread that it can proceed */ + pthread_cond_broadcast(&server_can_start_cond); [NSApp run]; /* not reached */ diff --git a/hw/xquartz/X11Controller.h b/hw/xquartz/X11Controller.h index c5994bd1f..d33752ead 100644 --- a/hw/xquartz/X11Controller.h +++ b/hw/xquartz/X11Controller.h @@ -100,6 +100,6 @@ #endif /* __OBJC__ */ -void X11ControllerMain(int argc, const char **argv, void (*server_thread) (void *), void *server_arg); +void X11ControllerMain(int argc, const char **argv); #endif /* X11CONTROLLER_H */ diff --git a/hw/xquartz/X11Controller.m b/hw/xquartz/X11Controller.m index 8dfe4b342..01470e55f 100644 --- a/hw/xquartz/X11Controller.m +++ b/hw/xquartz/X11Controller.m @@ -756,6 +756,6 @@ objectValueForTableColumn:(NSTableColumn *)tableColumn row:(int)row @end -void X11ControllerMain(int argc, const char **argv, void (*server_thread) (void *), void *server_arg) { - X11ApplicationMain (argc, argv, server_thread, server_arg); +void X11ControllerMain(int argc, const char **argv) { + X11ApplicationMain (argc, argv); } diff --git a/hw/xquartz/darwinEvents.c b/hw/xquartz/darwinEvents.c index 0643e5343..86e7704fc 100644 --- a/hw/xquartz/darwinEvents.c +++ b/hw/xquartz/darwinEvents.c @@ -78,7 +78,8 @@ static int old_flags = 0; // last known modifier state xEvent *darwinEvents = NULL; -pthread_mutex_t mieqEnqueue_mutex; +pthread_mutex_t mieqEnqueue_mutex = PTHREAD_MUTEX_INITIALIZER; + static inline void mieqEnqueue_lock(void) { int err; if((err = pthread_mutex_lock(&mieqEnqueue_mutex))) { @@ -303,17 +304,11 @@ static void DarwinEventHandler(int screenNum, xEventPtr xe, DeviceIntPtr dev, in } Bool DarwinEQInit(DevicePtr pKbd, DevicePtr pPtr) { - int err; - if (!darwinEvents) darwinEvents = (xEvent *)xcalloc(sizeof(xEvent), GetMaximumEventsNum()); if (!darwinEvents) FatalError("Couldn't allocate event buffer\n"); - if((err = pthread_mutex_init(&mieqEnqueue_mutex, NULL))) { - FatalError("Couldn't allocate mieqEnqueue mutex: %d.\n", err); - } - mieqInit(); mieqSetHandler(kXquartzReloadKeymap, DarwinKeyboardReloadHandler); mieqSetHandler(kXquartzActivate, DarwinEventHandler); diff --git a/hw/xquartz/quartz.c b/hw/xquartz/quartz.c index 2cba5df2c..0635b48b5 100644 --- a/hw/xquartz/quartz.c +++ b/hw/xquartz/quartz.c @@ -39,7 +39,6 @@ #include "quartz.h" #include "darwin.h" #include "darwinEvents.h" -#include "quartzAudio.h" #include "pseudoramiX.h" #define _APPLEWM_SERVER_ #include "applewmExt.h" @@ -156,10 +155,6 @@ void QuartzInitOutput( int argc, char **argv ) { - if (serverGeneration == 1) { - QuartzAudioInit(); - } - if (!RegisterBlockAndWakeupHandlers(QuartzBlockHandler, QuartzWakeupHandler, NULL)) diff --git a/hw/xquartz/quartzStartup.c b/hw/xquartz/quartzStartup.c index 18d0bfac3..d5413305f 100644 --- a/hw/xquartz/quartzStartup.c +++ b/hw/xquartz/quartzStartup.c @@ -37,8 +37,11 @@ #include #include #include "quartzCommon.h" +#include "quartzForeground.h" #include "X11Controller.h" #include "darwin.h" +#include "darwinEvents.h" +#include "quartzAudio.h" #include "quartz.h" #include "opaque.h" #include "micmap.h" @@ -51,46 +54,60 @@ #include #endif -char **envpGlobal; // argcGlobal and argvGlobal - // are from dix/globals.c +#include -int main(int argc, char **argv, char **envp); -void _InitHLTB(void); -void DarwinHandleGUI(int argc, char **argv, char **envp); +int dix_main(int argc, char **argv, char **envp); + +struct arg { + int argc; + char **argv; + char **envp; +}; + +pthread_cond_t server_can_start_cond = PTHREAD_COND_INITIALIZER; static void server_thread (void *arg) { - exit (main (argcGlobal, argvGlobal, envpGlobal)); + struct arg *args = (struct arg *)arg; + + /* Wait to be told we can continue */ + pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + pthread_mutex_lock(&mutex); + pthread_cond_wait(&server_can_start_cond, &mutex); + pthread_mutex_unlock(&mutex); + pthread_mutex_destroy(&mutex); + + exit (dix_main(args->argc, args->argv, args->envp)); } -/* - * DarwinHandleGUI - * This function is called first from main(). The first time - * it is called we start the Mac OS X front end. The front end - * will call main() again from another thread to run the X - * server. On the second call this function loads the user - * preferences set by the Mac OS X front end. - */ -void DarwinHandleGUI(int argc, char **argv, char **envp) { - static Bool been_here = FALSE; +static pthread_t create_thread (void *func, void *arg) { + pthread_attr_t attr; + pthread_t tid; + + pthread_attr_init (&attr); + pthread_attr_setscope (&attr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED); + pthread_create (&tid, &attr, func, arg); + pthread_attr_destroy (&attr); + + return tid; +} + +int main(int argc, char **argv, char **envp) { int i; int fd[2]; - if (been_here) { - return; - } - been_here = TRUE; - + /* Store the args to pass to dix_main() */ + struct arg args; + args.argc = argc; + args.argv = argv; + args.envp = envp; + // Make a pipe to pass events assert( pipe(fd) == 0 ); darwinEventReadFD = fd[0]; darwinEventWriteFD = fd[1]; fcntl(darwinEventReadFD, F_SETFL, O_NONBLOCK); - // Store command line arguments to pass back to main() - argcGlobal = argc; - argvGlobal = argv; - envpGlobal = envp; - for (i = 1; i < argc; i++) { // Display version info without starting Mac OS X UI if requested if (!strcmp( argv[i], "-showconfig" ) || !strcmp( argv[i], "-version" )) { @@ -99,16 +116,20 @@ void DarwinHandleGUI(int argc, char **argv, char **envp) { } } - /* Initially I ran the X server on the main thread, and received - events on the second thread. But now we may be using Carbon, - that needs to run on the main thread. (Otherwise, when it's - prebound, it will initialize itself on the wrong thread) - - grr.. but doing that means that if the X thread gets scheduled - before the main thread when we're _not_ prebound, things fail, - so initialize by hand. */ + /* Create the audio mutex */ + QuartzAudioInit(); + + pthread_cond_init(&server_can_start_cond, NULL); + + APPKIT_THREAD_ID = pthread_self(); + SERVER_THREAD_ID = create_thread(server_thread, &args); - _InitHLTB(); - X11ControllerMain(argc, (const char **)argv, server_thread, NULL); + if (!SERVER_THREAD_ID) { + ErrorF("can't create secondary thread\n"); + exit (1); + } + + QuartzMoveToForeground(); + X11ControllerMain(argc, (const char **)argv); exit(0); } diff --git a/hw/xquartz/threadSafety.c b/hw/xquartz/threadSafety.c index 7835de68d..b5a4ecf95 100644 --- a/hw/xquartz/threadSafety.c +++ b/hw/xquartz/threadSafety.c @@ -33,8 +33,8 @@ #include -pthread_t SERVER_THREAD; -pthread_t APPKIT_THREAD; +pthread_t APPKIT_THREAD_ID; +pthread_t SERVER_THREAD_ID; void spewCallStack(void) { void* callstack[128]; @@ -48,7 +48,7 @@ void spewCallStack(void) { free(strs); } -void _threadAssert(pthread_t tid, const char *file, const char *fun, int line) { +void _threadSafetyAssert(pthread_t tid, const char *file, const char *fun, int line) { if(pthread_equal(pthread_self(), tid)) return; @@ -58,3 +58,13 @@ void _threadAssert(pthread_t tid, const char *file, const char *fun, int line) { file, fun, line); spewCallStack(); } + +const char *threadSafetyID(pthread_t tid) { + if(pthread_equal(tid, APPKIT_THREAD_ID)) { + return "Appkit Thread"; + } else if(pthread_equal(tid, SERVER_THREAD_ID)) { + return "Xserver Thread"; + } else { + return "Unknown Thread"; + } +} diff --git a/hw/xquartz/threadSafety.h b/hw/xquartz/threadSafety.h index ed2ad9ff5..7b009103a 100644 --- a/hw/xquartz/threadSafety.h +++ b/hw/xquartz/threadSafety.h @@ -31,22 +31,23 @@ #include -extern pthread_t SERVER_THREAD; -extern pthread_t APPKIT_THREAD; - -#define threadSafetyID(tid) (pthread_equal((tid), SERVER_THREAD) ? "X Server Thread" : "Appkit Thread") +extern pthread_t APPKIT_THREAD_ID; +extern pthread_t SERVER_THREAD_ID; /* Dump the call stack */ void spewCallStack(void); /* Print message to ErrorF if we're in the wrong thread */ -void _threadAssert(pthread_t tid, const char *file, const char *fun, int line); +void _threadSafetyAssert(pthread_t tid, const char *file, const char *fun, int line); -#define threadAssert(tid) _threadAssert(tid, __FILE__, __FUNCTION__, __LINE__) +/* Get a string that identifies our thread nicely */ +const char *threadSafetyID(pthread_t tid); + +#define threadSafetyAssert(tid) _threadSafetyAssert(tid, __FILE__, __FUNCTION__, __LINE__) #ifdef DEBUG_THREADS -#define TA_SERVER() threadAssert(SERVER_THREAD) -#define TA_APPKIT() threadAssert(APPKIT_THREAD) +#define TA_APPKIT() threadSafetyAssert(APPKIT_THREAD_ID) +#define TA_SERVER() threadSafetyAssert(SERVER_THREAD_ID) #else #define TA_SERVER() #define TA_APPKIT()