summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2013-08-21 14:18:09 +0200
committerHans de Goede <hdegoede@redhat.com>2013-08-21 14:18:09 +0200
commitbe76bef5b716d27b78fba120d3f9b815ed3380b9 (patch)
tree5ae750f018b696bee367c3324e7aa1ea6b28f448
parentfad4a18c8a55947a9c4f1a427427b176e053a991 (diff)
downloadlibusb-be76bef5b716d27b78fba120d3f9b815ed3380b9.tar.gz
hotplug: Don't call the user callback while holding various locks
Calling user callbacks with locks held is a bad idea and should be avoided whenever possible. Before this patch this could lead ie to the following hang: 1) User calls libusb_hotplug_register_callback with the LIBUSB_HOTPLUG_ENUMERATE flag 2) libusb_hotplug_register_callback calls the user callback while holding the hotplug_cbs_lock 3) The callback calls a synchronous libusb function 4) The synchronous libusb function calls libusb_handle_events 5) There is an hotplug event waiting in the hotplug pipe and libusb_handle_events calls usbi_hotplug_match 6) usbi_hotplug_match tries to take the lock a 2nd time 7) hang / assert / abort (depending on the platform) Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--libusb/hotplug.c24
-rw-r--r--libusb/version_nano.h2
2 files changed, 18 insertions, 8 deletions
diff --git a/libusb/hotplug.c b/libusb/hotplug.c
index ec91162..16725f2 100644
--- a/libusb/hotplug.c
+++ b/libusb/hotplug.c
@@ -241,19 +241,29 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
list_add(&new_callback->list, &ctx->hotplug_cbs);
- if (flags & LIBUSB_HOTPLUG_ENUMERATE) {
- struct libusb_device *dev;
+ usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
+
- usbi_mutex_lock(&ctx->usb_devs_lock);
+ if (flags & LIBUSB_HOTPLUG_ENUMERATE) {
+ int i, len;
+ struct libusb_device **devs;
+
+ len = libusb_get_device_list(ctx, &devs);
+ if (len < 0) {
+ libusb_hotplug_deregister_callback(ctx,
+ new_callback->handle);
+ return len;
+ }
- list_for_each_entry(dev, &ctx->usb_devs, list, struct libusb_device) {
- (void) usbi_hotplug_match_cb (ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED, new_callback);
+ for (i = 0; i < len; i++) {
+ usbi_hotplug_match_cb(ctx, devs[i],
+ LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
+ new_callback);
}
- usbi_mutex_unlock(&ctx->usb_devs_lock);
+ libusb_free_device_list(devs, 1);
}
- usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
if (handle) {
*handle = new_callback->handle;
diff --git a/libusb/version_nano.h b/libusb/version_nano.h
index acce2c9..4972515 100644
--- a/libusb/version_nano.h
+++ b/libusb/version_nano.h
@@ -1 +1 @@
-#define LIBUSB_NANO 10813
+#define LIBUSB_NANO 10814