--- BasiliskII/src/MacOSX/sys_darwin.cpp 2008/02/04 01:02:58 1.14 +++ BasiliskII/src/MacOSX/sys_darwin.cpp 2012/04/21 16:04:51 1.17 @@ -1,5 +1,5 @@ /* - * $Id: sys_darwin.cpp,v 1.14 2008/02/04 01:02:58 nigel Exp $ + * $Id: sys_darwin.cpp,v 1.17 2012/04/21 16:04:51 asvitkine Exp $ * * sys_darwin.cpp - Extra Darwin system dependant routines. Called by: * @@ -48,7 +48,7 @@ // Global variables -static CFRunLoopRef media_poll_loop = NULL; +static volatile CFRunLoopRef media_poll_loop = NULL; static bool media_thread_active = false; static pthread_t media_thread; @@ -66,8 +66,10 @@ extern void SysMediaRemoved(const char * void DarwinSysInit(void) { - media_thread_active = (pthread_create(&media_thread, NULL, media_poll_func, NULL) == 0); - D(bug("Media poll thread installed (%ld)\n", media_thread)); + if (PrefsFindBool("nocdrom")) { + media_thread_active = (pthread_create(&media_thread, NULL, media_poll_func, NULL) == 0); + D(bug("Media poll thread installed (%ld)\n", media_thread)); + } } @@ -78,10 +80,14 @@ void DarwinSysInit(void) void DarwinSysExit(void) { // Stop media poll thread - if (media_poll_loop) + if (media_thread_active) { + while (media_poll_loop == NULL || !CFRunLoopIsWaiting(media_poll_loop)) + usleep(0); CFRunLoopStop(media_poll_loop); - if (media_thread_active) pthread_join(media_thread, NULL); + media_poll_loop = NULL; + media_thread_active = false; + } } @@ -154,52 +160,65 @@ static void media_removed(int type, io_i /* * Media poll function + * + * NOTE: to facilitate orderly thread termination, media_poll_func MUST end up waiting in CFRunLoopRun. + * Early returns must be avoided, even if there is nothing useful to be done here. See DarwinSysExit. */ +static void dummy(void *) { }; // stub for dummy runloop source + static void *media_poll_func(void *) { media_poll_loop = CFRunLoopGetCurrent(); mach_port_t masterPort; - kern_return_t kernResult = IOMasterPort(bootstrap_port, &masterPort); - if (kernResult != KERN_SUCCESS) { - fprintf(stderr, "IOMasterPort() returned %d\n", kernResult); - return NULL; - } + kern_return_t kernResult; + CFMutableDictionaryRef matchingDictionary; + CFRunLoopSourceRef loopSource = NULL; + CFRunLoopSourceRef dummySource = NULL; - CFMutableDictionaryRef matchingDictionary = IOServiceMatching(kIOCDMediaClass); - if (matchingDictionary == NULL) { + if ((kernResult = IOMasterPort(bootstrap_port, &masterPort)) != KERN_SUCCESS) + fprintf(stderr, "IOMasterPort() returned %d\n", kernResult); + else if ((matchingDictionary = IOServiceMatching(kIOCDMediaClass)) == NULL) fprintf(stderr, "IOServiceMatching() returned a NULL dictionary\n"); - return NULL; + else { + matchingDictionary = (CFMutableDictionaryRef)CFRetain(matchingDictionary); + IONotificationPortRef notificationPort = IONotificationPortCreate(kIOMasterPortDefault); + loopSource = IONotificationPortGetRunLoopSource(notificationPort); + CFRunLoopAddSource(media_poll_loop, loopSource, kCFRunLoopDefaultMode); + + io_iterator_t mediaArrivedIterator; + kernResult = IOServiceAddMatchingNotification(notificationPort, + kIOMatchedNotification, + matchingDictionary, + (IOServiceMatchingCallback)media_arrived, + (void *)MEDIA_CD, &mediaArrivedIterator); + if (kernResult != KERN_SUCCESS) + fprintf(stderr, "IOServiceAddMatchingNotification() returned %d\n", kernResult); + media_arrived(MEDIA_CD, mediaArrivedIterator); + + io_iterator_t mediaRemovedIterator; + kernResult = IOServiceAddMatchingNotification(notificationPort, + kIOTerminatedNotification, + matchingDictionary, + (IOServiceMatchingCallback)media_removed, + (void *)MEDIA_CD, &mediaRemovedIterator); + if (kernResult != KERN_SUCCESS) + fprintf(stderr, "IOServiceAddMatchingNotification() returned %d\n", kernResult); + media_removed(MEDIA_CD, mediaRemovedIterator); } - matchingDictionary = (CFMutableDictionaryRef)CFRetain(matchingDictionary); - IONotificationPortRef notificationPort = IONotificationPortCreate(kIOMasterPortDefault); - CFRunLoopAddSource(media_poll_loop, - IONotificationPortGetRunLoopSource(notificationPort), - kCFRunLoopDefaultMode); - - io_iterator_t mediaArrivedIterator; - kernResult = IOServiceAddMatchingNotification(notificationPort, - kIOMatchedNotification, - matchingDictionary, - (IOServiceMatchingCallback)media_arrived, - (void *)MEDIA_CD, &mediaArrivedIterator); - if (kernResult != KERN_SUCCESS) - fprintf(stderr, "IOServiceAddMatchingNotification() returned %d\n", kernResult); - media_arrived(MEDIA_CD, mediaArrivedIterator); - - io_iterator_t mediaRemovedIterator; - kernResult = IOServiceAddMatchingNotification(notificationPort, - kIOTerminatedNotification, - matchingDictionary, - (IOServiceMatchingCallback)media_removed, - (void *)MEDIA_CD, &mediaRemovedIterator); - if (kernResult != KERN_SUCCESS) - fprintf(stderr, "IOServiceAddMatchingNotification() returned %d\n", kernResult); - media_removed(MEDIA_CD, mediaRemovedIterator); + if (loopSource == NULL) { + // add a dummy runloop source to prevent premature return from CFRunLoopRun + CFRunLoopSourceContext context = { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, dummy }; + dummySource = CFRunLoopSourceCreate(NULL, 0, &context); + CFRunLoopAddSource(media_poll_loop, dummySource, kCFRunLoopDefaultMode); + } CFRunLoopRun(); + + if (dummySource != NULL) + CFRelease(dummySource); return NULL; }