summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Dickens <christopher.a.dickens@gmail.com>2020-03-26 15:50:04 -0700
committerChris Dickens <christopher.a.dickens@gmail.com>2020-03-26 15:50:04 -0700
commit1201bccf857aa2c126f6f568f5255b0aa6027ac2 (patch)
treed50d2f89312b8341ae5fe5024adffda74f76b3ea
parent8f7f8560a7ff3db832748bef576bbfd5af527fcf (diff)
downloadlibusb-1201bccf857aa2c126f6f568f5255b0aa6027ac2.tar.gz
darwin: Explicitly cleanup cached devices during the last libusb_exit()
Deferring the cached devices cleanup until the "destructor" function is called makes it appear as though libusb is leaking memory, especially if heap allocations are analyzed after calling libusb_exit(). It can also lead to devices staying on the list longer than they should, as seen by the following sequence of events: libusb_init() <-- init_count is 0, async thread is started devices_scan_devices() <-- enumerates devices libusb_exit() <-- init_count is 0, async thread is stopped [one or more devices disconnected] Because the async thread is stopped when device(s) are disconnected in the above sequence, the disconnection event(s) will not be processed and thus darwin_devices_detached() will not be called and the list will have one or more stale entries until the "destructor" function is finally called. Address both of these shortcomings by cleaning up the cached devices list after stopping the async thread. Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
-rw-r--r--libusb/os/darwin_usb.c22
-rw-r--r--libusb/version_nano.h2
2 files changed, 15 insertions, 9 deletions
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
index f8da747..4639a7e 100644
--- a/libusb/os/darwin_usb.c
+++ b/libusb/os/darwin_usb.c
@@ -67,7 +67,7 @@ static CFRunLoopRef libusb_darwin_acfl = NULL; /* event cf loop */
static CFRunLoopSourceRef libusb_darwin_acfls = NULL; /* shutdown signal for event cf loop */
static usbi_mutex_t darwin_cached_devices_lock = PTHREAD_MUTEX_INITIALIZER;
-static struct list_head darwin_cached_devices = {&darwin_cached_devices, &darwin_cached_devices};
+static struct list_head darwin_cached_devices;
static const char *darwin_device_class = kIOUSBDeviceClassName;
#define DARWIN_CACHED_DEVICE(a) (((struct darwin_device_priv *)usbi_get_device_priv((a)))->dev)
@@ -559,14 +559,14 @@ static void *darwin_event_thread_main (void *arg0) {
}
/* cleanup function to destroy cached devices */
-static void __attribute__((destructor)) _darwin_finalize(void) {
+static void darwin_cleanup_devices(void) {
struct darwin_cached_device *dev, *next;
- usbi_mutex_lock(&darwin_cached_devices_lock);
list_for_each_entry_safe(dev, next, &darwin_cached_devices, list, struct darwin_cached_device) {
darwin_deref_cached_device(dev);
}
- usbi_mutex_unlock(&darwin_cached_devices_lock);
+
+ darwin_cached_devices.prev = darwin_cached_devices.next = NULL;
}
static int darwin_init(struct libusb_context *ctx) {
@@ -578,8 +578,11 @@ static int darwin_init(struct libusb_context *ctx) {
first_init = (1 == ++init_count);
do {
-#if !defined(HAVE_CLOCK_GETTIME)
if (first_init) {
+ assert (NULL == darwin_cached_devices.next);
+ list_init (&darwin_cached_devices);
+
+#if !defined(HAVE_CLOCK_GETTIME)
/* create the clocks that will be used if clock_gettime() is not available */
host_name_port_t host_self;
@@ -587,8 +590,8 @@ static int darwin_init(struct libusb_context *ctx) {
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);
- }
#endif
+ }
rc = darwin_scan_devices (ctx);
if (LIBUSB_SUCCESS != rc)
@@ -617,12 +620,13 @@ static int darwin_init(struct libusb_context *ctx) {
} while (0);
if (LIBUSB_SUCCESS != rc) {
-#if !defined(HAVE_CLOCK_GETTIME)
if (first_init) {
+ darwin_cleanup_devices ();
+#if !defined(HAVE_CLOCK_GETTIME)
mach_port_deallocate(mach_task_self(), clock_realtime);
mach_port_deallocate(mach_task_self(), clock_monotonic);
- }
#endif
+ }
--init_count;
}
@@ -646,6 +650,8 @@ static void darwin_exit (struct libusb_context *ctx) {
pthread_mutex_unlock (&libusb_darwin_at_mutex);
pthread_join (libusb_darwin_at, NULL);
+ darwin_cleanup_devices ();
+
#if !defined(HAVE_CLOCK_GETTIME)
mach_port_deallocate(mach_task_self(), clock_realtime);
mach_port_deallocate(mach_task_self(), clock_monotonic);
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index 2c5b766..037f308 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 11473
+#define LIBUSB_NANO 11474