darwin: fix occasional dead-lock on libusb_exit
authorparafin <parafin@paraf.in>
Thu, 15 Oct 2015 17:12:42 +0000 (20:12 +0300)
committerNathan Hjelm <hjelmn@me.com>
Sat, 5 Mar 2016 16:11:41 +0000 (09:11 -0700)
CFRunLoopStop() isn't thread-safe, see for example this bugreport:
https://github.com/joyent/libuv/issues/799
Use CFRunLoopSource instead

Closes #112

Signed-off-by: Nathan Hjelm <hjelmn@me.com>
libusb/os/darwin_usb.c
libusb/version_nano.h

index 0f346f5..4e4ab04 100644 (file)
@@ -54,6 +54,7 @@ static clock_serv_t clock_realtime;
 static clock_serv_t clock_monotonic;
 
 static CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */
+static CFRunLoopSourceRef libusb_darwin_acfls = NULL; /* shutdown signal for event cf loop */
 static volatile int32_t initCount = 0;
 
 static usbi_mutex_t darwin_cached_devices_lock = PTHREAD_MUTEX_INITIALIZER;
@@ -383,6 +384,7 @@ static void *darwin_event_thread_main (void *arg0) {
 #endif
 
   /* hotplug (device arrival/removal) sources */
+  CFRunLoopSourceContext libusb_shutdown_cfsourcectx;
   CFRunLoopSourceRef     libusb_notification_cfsource;
   io_notification_port_t libusb_notification_port;
   io_iterator_t          libusb_rem_device_iterator;
@@ -393,6 +395,13 @@ static void *darwin_event_thread_main (void *arg0) {
   runloop = CFRunLoopGetCurrent ();
   CFRetain (runloop);
 
+  /* add the shutdown cfsource to the run loop */
+  memset(&libusb_shutdown_cfsourcectx, 0, sizeof(libusb_shutdown_cfsourcectx));
+  libusb_shutdown_cfsourcectx.info = runloop;
+  libusb_shutdown_cfsourcectx.perform = (void (*)(void *))CFRunLoopStop;
+  libusb_darwin_acfls = CFRunLoopSourceCreate(NULL, 0, &libusb_shutdown_cfsourcectx);
+  CFRunLoopAddSource(runloop, libusb_darwin_acfls, kCFRunLoopDefaultMode);
+
   /* add the notification port to the run loop */
   libusb_notification_port     = IONotificationPortCreate (kIOMasterPortDefault);
   libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port);
@@ -442,6 +451,9 @@ static void *darwin_event_thread_main (void *arg0) {
   /* remove the notification cfsource */
   CFRunLoopRemoveSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode);
 
+  /* remove the shutdown cfsource */
+  CFRunLoopRemoveSource(runloop, libusb_darwin_acfls, kCFRunLoopDefaultMode);
+
   /* delete notification port */
   IONotificationPortDestroy (libusb_notification_port);
 
@@ -449,8 +461,10 @@ static void *darwin_event_thread_main (void *arg0) {
   IOObjectRelease (libusb_rem_device_iterator);
   IOObjectRelease (libusb_add_device_iterator);
 
+  CFRelease (libusb_darwin_acfls);
   CFRelease (runloop);
 
+  libusb_darwin_acfls = NULL;
   libusb_darwin_acfl = NULL;
 
   pthread_exit (NULL);
@@ -522,7 +536,8 @@ static void darwin_exit (void) {
     mach_port_deallocate(mach_task_self(), clock_monotonic);
 
     /* stop the event runloop and wait for the thread to terminate. */
-    CFRunLoopStop (libusb_darwin_acfl);
+    CFRunLoopSourceSignal(libusb_darwin_acfls);
+    CFRunLoopWakeUp (libusb_darwin_acfl);
     pthread_join (libusb_darwin_at, NULL);
   }
 }
index 5709b65..039b1d1 100644 (file)
@@ -1 +1 @@
-#define LIBUSB_NANO 11091
+#define LIBUSB_NANO 11093