Darwin: Fix incorrect mutex protection of libusb_darwin_acfl global
[platform/upstream/libusb.git] / libusb / os / darwin_usb.c
index 6e9d36f..f092562 100644 (file)
@@ -30,6 +30,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <unistd.h>
+#include <libkern/OSAtomic.h>
 
 #include <mach/clock.h>
 #include <mach/clock_types.h>
 static pthread_mutex_t libusb_darwin_at_mutex;
 static pthread_cond_t  libusb_darwin_at_cond;
 
+static clock_serv_t clock_realtime;
+static clock_serv_t clock_monotonic;
+
 static CFRunLoopRef libusb_darwin_acfl = NULL; /* async cf loop */
-static int initCount = 0;
+static volatile int32_t initCount = 0;
 
 /* async event thread */
 static pthread_t libusb_darwin_at;
@@ -308,6 +312,12 @@ static void *event_thread_main (void *arg0) {
   struct libusb_context *ctx = (struct libusb_context *)arg0;
   CFRunLoopRef runloop;
 
+  /* Set this thread's name, so it can be seen in the debugger
+     and crash reports. */
+#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
+  pthread_setname_np ("org.libusb.device-detach");
+#endif
+
   /* Tell the Objective-C garbage collector about this thread.
      This is required because, unlike NSThreads, pthreads are
      not automatically registered. Although we don't use
@@ -329,7 +339,7 @@ static void *event_thread_main (void *arg0) {
   /* add the notification port to the run loop */
   libusb_notification_port     = IONotificationPortCreate (kIOMasterPortDefault);
   libusb_notification_cfsource = IONotificationPortGetRunLoopSource (libusb_notification_port);
-  CFRunLoopAddSource(CFRunLoopGetCurrent (), libusb_notification_cfsource, kCFRunLoopDefaultMode);
+  CFRunLoopAddSource(runloop, libusb_notification_cfsource, kCFRunLoopDefaultMode);
 
   /* create notifications for removed devices */
   kresult = IOServiceAddMatchingNotification (libusb_notification_port, kIOTerminatedNotification,
@@ -348,11 +358,9 @@ static void *event_thread_main (void *arg0) {
 
   usbi_info (ctx, "thread ready to receive events");
 
-  /* let the main thread know about the async runloop */
-  libusb_darwin_acfl = CFRunLoopGetCurrent ();
-
   /* signal the main thread */
   pthread_mutex_lock (&libusb_darwin_at_mutex);
+  libusb_darwin_acfl = runloop;
   pthread_cond_signal (&libusb_darwin_at_cond);
   pthread_mutex_unlock (&libusb_darwin_at_mutex);
 
@@ -362,8 +370,8 @@ static void *event_thread_main (void *arg0) {
   usbi_info (ctx, "thread exiting");
 
   /* delete notification port */
-  CFRunLoopSourceInvalidate (libusb_notification_cfsource);
   IONotificationPortDestroy (libusb_notification_port);
+  IOObjectRelease (libusb_rem_device_iterator);
 
   CFRelease (runloop);
 
@@ -373,7 +381,16 @@ static void *event_thread_main (void *arg0) {
 }
 
 static int darwin_init(struct libusb_context *ctx) {
-  if (!(initCount++)) {
+  host_name_port_t host_self;
+
+  if (OSAtomicIncrement32Barrier(&initCount) == 1) {
+    /* create the clocks that will be used */
+
+    host_self = mach_host_self();
+    host_get_clock_service(host_self, CALENDAR_CLOCK, &clock_realtime);
+    host_get_clock_service(host_self, SYSTEM_CLOCK, &clock_monotonic);
+    mach_port_deallocate(mach_task_self(), host_self);
+
     pthread_mutex_init (&libusb_darwin_at_mutex, NULL);
     pthread_cond_init (&libusb_darwin_at_cond, NULL);
 
@@ -389,7 +406,9 @@ static int darwin_init(struct libusb_context *ctx) {
 }
 
 static void darwin_exit (void) {
-  if (!(--initCount)) {
+  if (OSAtomicDecrement32Barrier(&initCount) == 0) {
+    mach_port_deallocate(mach_task_self(), clock_realtime);
+    mach_port_deallocate(mach_task_self(), clock_monotonic);
 
     /* stop the async runloop */
     CFRunLoopStop (libusb_darwin_acfl);
@@ -1229,14 +1248,19 @@ static int darwin_kernel_driver_active(struct libusb_device_handle *dev_handle,
 
 /* attaching/detaching kernel drivers is not currently supported (maybe in the future?) */
 static int darwin_attach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
+  (void)dev_handle;
+  (void)interface;
   return LIBUSB_ERROR_NOT_SUPPORTED;
 }
 
 static int darwin_detach_kernel_driver (struct libusb_device_handle *dev_handle, int interface) {
+  (void)dev_handle;
+  (void)interface;
   return LIBUSB_ERROR_NOT_SUPPORTED;
 }
 
 static void darwin_destroy_device(struct libusb_device *dev) {
+  (void)dev;
 }
 
 static int submit_bulk_transfer(struct usbi_transfer *itransfer) {
@@ -1603,7 +1627,8 @@ static int op_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL
   struct usbi_transfer *itransfer;
   UInt32 io_size;
   IOReturn kresult;
-  int i = 0, ret;
+  POLL_NFDS_TYPE i = 0;
+  ssize_t ret;
   UInt32 message;
 
   usbi_mutex_lock(&ctx->open_devs_lock);
@@ -1626,7 +1651,7 @@ static int op_handle_events(struct libusb_context *ctx, struct pollfd *fds, POLL
 
     if (!(pollfd->revents & POLLERR)) {
       ret = read (hpriv->fds[0], &message, sizeof (message));
-      if (ret < sizeof (message))
+      if (ret < (ssize_t)sizeof (message))
        continue;
     } else
       /* could not poll the device-- response is to delete the device (this seems a little heavy-handed) */
@@ -1671,11 +1696,11 @@ static int darwin_clock_gettime(int clk_id, struct timespec *tp) {
   switch (clk_id) {
   case USBI_CLOCK_REALTIME:
     /* CLOCK_REALTIME represents time since the epoch */
-    host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &clock_ref);
+    clock_ref = clock_realtime;
     break;
   case USBI_CLOCK_MONOTONIC:
     /* use system boot time as reference for the monotonic clock */
-    host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &clock_ref);
+    clock_ref = clock_monotonic;
     break;
   default:
     return LIBUSB_ERROR_INVALID_PARAM;