core: Refactor initialization and how the default context is handled
Highlights for this change:
- usbi_default_context is only set if libusb_init() is called with NULL.
- All hotplug related functionality (e.g. initialization, processing) has been
moved to hotplug.c
- Backends are simplified by removing initialization mutexes. Mutual exclusion
between init()/exit() is provided by default_context_lock.
- Make hotplug types and functions part of libusbi.h with the common usbi_
prefixes (removes hotplug.h).
Addresses issue highlighted in #855
Closes #856
Signed-off-by: Chris Dickens <christopher.a.dickens@gmail.com>
Signed-off-by: Nathan Hjelm <hjelmn@google.com>
diff --git a/Xcode/libusb.xcodeproj/project.pbxproj b/Xcode/libusb.xcodeproj/project.pbxproj
index 958e256..759a102 100644
--- a/Xcode/libusb.xcodeproj/project.pbxproj
+++ b/Xcode/libusb.xcodeproj/project.pbxproj
@@ -56,7 +56,6 @@
008FC0211628BC5200BC5BE2 /* ezusb.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBFDC1628BA0E00BC5BE2 /* ezusb.c */; };
008FC0301628BC7400BC5BE2 /* listdevs.c in Sources */ = {isa = PBXBuildFile; fileRef = 008FBFE71628BA0E00BC5BE2 /* listdevs.c */; };
1438D77A17A2ED9F00166101 /* hotplug.c in Sources */ = {isa = PBXBuildFile; fileRef = 1438D77817A2ED9F00166101 /* hotplug.c */; };
- 1438D77B17A2ED9F00166101 /* hotplug.h in Headers */ = {isa = PBXBuildFile; fileRef = 1438D77917A2ED9F00166101 /* hotplug.h */; };
1438D77F17A2F0EA00166101 /* strerror.c in Sources */ = {isa = PBXBuildFile; fileRef = 1438D77E17A2F0EA00166101 /* strerror.c */; };
2018D95F24E453BA001589B2 /* events_posix.c in Sources */ = {isa = PBXBuildFile; fileRef = 2018D95E24E453BA001589B2 /* events_posix.c */; };
2018D96124E453D0001589B2 /* events_posix.h in Headers */ = {isa = PBXBuildFile; fileRef = 2018D96024E453D0001589B2 /* events_posix.h */; };
@@ -266,7 +265,6 @@
008FC0151628BC0300BC5BE2 /* fxload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = fxload; sourceTree = BUILT_PRODUCTS_DIR; };
008FC0261628BC6B00BC5BE2 /* listdevs */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = listdevs; sourceTree = BUILT_PRODUCTS_DIR; };
1438D77817A2ED9F00166101 /* hotplug.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = hotplug.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
- 1438D77917A2ED9F00166101 /* hotplug.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = hotplug.h; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
1438D77E17A2F0EA00166101 /* strerror.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = strerror.c; sourceTree = "<group>"; tabWidth = 4; usesTabs = 1; };
1443EE8416417E63007E0579 /* common.xcconfig */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xcconfig; path = common.xcconfig; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 1; };
1443EE8516417E63007E0579 /* debug.xcconfig */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = text.xcconfig; path = debug.xcconfig; sourceTree = SOURCE_ROOT; tabWidth = 4; usesTabs = 1; };
@@ -417,7 +415,6 @@
008FBF541628B7E800BC5BE2 /* core.c */,
008FBF551628B7E800BC5BE2 /* descriptor.c */,
1438D77817A2ED9F00166101 /* hotplug.c */,
- 1438D77917A2ED9F00166101 /* hotplug.h */,
008FBF561628B7E800BC5BE2 /* io.c */,
008FBF5A1628B7E800BC5BE2 /* libusb.h */,
008FBF671628B7E800BC5BE2 /* libusbi.h */,
@@ -498,7 +495,6 @@
008FBFA51628B84200BC5BE2 /* config.h in Headers */,
008FBF931628B7E800BC5BE2 /* darwin_usb.h in Headers */,
2018D96124E453D0001589B2 /* events_posix.h in Headers */,
- 1438D77B17A2ED9F00166101 /* hotplug.h in Headers */,
008FBF901628B7E800BC5BE2 /* libusbi.h in Headers */,
008FBF9B1628B7E800BC5BE2 /* threads_posix.h in Headers */,
008FBFA11628B7E800BC5BE2 /* version.h in Headers */,
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 45c3209..6568c4f 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -1,5 +1,5 @@
LIBUSB_SRC_DIR = @top_srcdir@/libusb
-EXCLUDED_FILES = hotplug.h libusbi.h version.h version_nano.h
+EXCLUDED_FILES = libusbi.h version.h version_nano.h
LIBUSB_SRC = $(wildcard $(LIBUSB_SRC_DIR)/*.c) $(wildcard $(LIBUSB_SRC_DIR)/*.h)
LIBUSB_DOC_SRC = $(filter-out $(addprefix $(LIBUSB_SRC_DIR)/,$(EXCLUDED_FILES)),$(LIBUSB_SRC))
diff --git a/doc/doxygen.cfg.in b/doc/doxygen.cfg.in
index 10f8fc4..b6e6219 100644
--- a/doc/doxygen.cfg.in
+++ b/doc/doxygen.cfg.in
@@ -899,8 +899,7 @@
# Note that relative paths are relative to the directory from which doxygen is
# run.
-EXCLUDE = @top_srcdir@/libusb/hotplug.h \
- @top_srcdir@/libusb/libusbi.h \
+EXCLUDE = @top_srcdir@/libusb/libusbi.h \
@top_srcdir@/libusb/version.h \
@top_srcdir@/libusb/version_nano.h \
@top_srcdir@/libusb/os
diff --git a/libusb/Makefile.am b/libusb/Makefile.am
index c78006e..baf7b38 100644
--- a/libusb/Makefile.am
+++ b/libusb/Makefile.am
@@ -82,7 +82,7 @@
libusb_1_0_la_LDFLAGS = $(LT_LDFLAGS)
libusb_1_0_la_SOURCES = libusbi.h version.h version_nano.h \
- core.c descriptor.c hotplug.h hotplug.c io.c strerror.c sync.c \
+ core.c descriptor.c hotplug.c io.c strerror.c sync.c \
$(PLATFORM_SRC) $(OS_SRC)
pkginclude_HEADERS = libusb.h
diff --git a/libusb/core.c b/libusb/core.c
index 7a2f6c3..8414756 100644
--- a/libusb/core.c
+++ b/libusb/core.c
@@ -21,7 +21,6 @@
*/
#include "libusbi.h"
-#include "hotplug.h"
#include "version.h"
#ifdef __ANDROID__
@@ -33,17 +32,18 @@
#include <syslog.h>
#endif
-struct libusb_context *usbi_default_context;
static const struct libusb_version libusb_version_internal =
{ LIBUSB_MAJOR, LIBUSB_MINOR, LIBUSB_MICRO, LIBUSB_NANO,
LIBUSB_RC, "http://libusb.info" };
-static int default_context_refcnt;
-static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER;
static struct timespec timestamp_origin;
#if defined(ENABLE_LOGGING) && !defined(USE_SYSTEM_LOGGING_FACILITY)
static libusb_log_cb log_handler;
#endif
+struct libusb_context *usbi_default_context;
+static int default_context_refcnt;
+static usbi_mutex_static_t default_context_lock = USBI_MUTEX_INITIALIZER;
+
usbi_mutex_static_t active_contexts_lock = USBI_MUTEX_INITIALIZER;
struct list_head active_contexts_list;
@@ -710,9 +710,8 @@
dev->session_data = session_id;
dev->speed = LIBUSB_SPEED_UNKNOWN;
- if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
- usbi_connect_device (dev);
- }
+ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
+ usbi_connect_device(dev);
return dev;
}
@@ -727,12 +726,7 @@
list_add(&dev->list, &dev->ctx->usb_devs);
usbi_mutex_unlock(&dev->ctx->usb_devs_lock);
- /* Signal that an event has occurred for this device if we support hotplug AND
- * the hotplug message list is ready. This prevents an event from getting raised
- * during initial enumeration. */
- if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) && dev->ctx->hotplug_msgs.next) {
- usbi_hotplug_notification(ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED);
- }
+ usbi_hotplug_notification(ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED);
}
void usbi_disconnect_device(struct libusb_device *dev)
@@ -745,13 +739,7 @@
list_del(&dev->list);
usbi_mutex_unlock(&ctx->usb_devs_lock);
- /* Signal that an event has occurred for this device if we support hotplug AND
- * the hotplug message list is ready. This prevents an event from getting raised
- * during initial enumeration. libusb_handle_events will take care of dereferencing
- * the device. */
- if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG) && dev->ctx->hotplug_msgs.next) {
- usbi_hotplug_notification(ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT);
- }
+ usbi_hotplug_notification(ctx, dev, LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT);
}
/* Perform some final sanity checks on a newly discovered device. If this
@@ -2247,113 +2235,105 @@
* context will be created. If there was already a default context, it will
* be reused (and nothing will be initialized/reinitialized).
*
- * \param context Optional output location for context pointer.
+ * \param ctx Optional output location for context pointer.
* Only valid on return code 0.
* \returns 0 on success, or a LIBUSB_ERROR code on failure
* \see libusb_contexts
*/
-int API_EXPORTED libusb_init(libusb_context **context)
+int API_EXPORTED libusb_init(libusb_context **ctx)
{
- struct libusb_device *dev, *next;
size_t priv_size = usbi_backend.context_priv_size;
- struct libusb_context *ctx;
- static int first_init = 1;
- int r = 0;
+ struct libusb_context *_ctx;
+ int r;
usbi_mutex_static_lock(&default_context_lock);
- if (!timestamp_origin.tv_sec)
- usbi_get_monotonic_time(×tamp_origin);
-
- if (!context && usbi_default_context) {
+ if (!ctx && usbi_default_context) {
usbi_dbg("reusing default context");
default_context_refcnt++;
usbi_mutex_static_unlock(&default_context_lock);
return 0;
}
- ctx = calloc(1, PTR_ALIGN(sizeof(*ctx)) + priv_size);
- if (!ctx) {
- r = LIBUSB_ERROR_NO_MEM;
- goto err_unlock;
+ /* check for first init */
+ if (!active_contexts_list.next) {
+ list_init(&active_contexts_list);
+ usbi_get_monotonic_time(×tamp_origin);
+ }
+
+ _ctx = calloc(1, PTR_ALIGN(sizeof(*_ctx)) + priv_size);
+ if (!_ctx) {
+ usbi_mutex_static_unlock(&default_context_lock);
+ return LIBUSB_ERROR_NO_MEM;
}
#if defined(ENABLE_LOGGING) && !defined(ENABLE_DEBUG_LOGGING)
- ctx->debug = get_env_debug_level();
- if (ctx->debug != LIBUSB_LOG_LEVEL_NONE)
- ctx->debug_fixed = 1;
+ _ctx->debug = get_env_debug_level();
+ if (_ctx->debug != LIBUSB_LOG_LEVEL_NONE)
+ _ctx->debug_fixed = 1;
#endif
/* default context should be initialized before calling usbi_dbg */
- if (!usbi_default_context) {
- usbi_default_context = ctx;
- default_context_refcnt++;
+ if (!ctx) {
+ usbi_default_context = _ctx;
+ default_context_refcnt = 1;
usbi_dbg("created default context");
}
usbi_dbg("libusb v%u.%u.%u.%u%s", libusb_version_internal.major, libusb_version_internal.minor,
libusb_version_internal.micro, libusb_version_internal.nano, libusb_version_internal.rc);
- usbi_mutex_init(&ctx->usb_devs_lock);
- usbi_mutex_init(&ctx->open_devs_lock);
- usbi_mutex_init(&ctx->hotplug_cbs_lock);
- list_init(&ctx->usb_devs);
- list_init(&ctx->open_devs);
- list_init(&ctx->hotplug_cbs);
- ctx->next_hotplug_cb_handle = 1;
+ usbi_mutex_init(&_ctx->usb_devs_lock);
+ usbi_mutex_init(&_ctx->open_devs_lock);
+ list_init(&_ctx->usb_devs);
+ list_init(&_ctx->open_devs);
+
+ r = usbi_io_init(_ctx);
+ if (r < 0) {
+ usbi_mutex_static_unlock(&default_context_lock);
+ goto err_free_ctx;
+ }
usbi_mutex_static_lock(&active_contexts_lock);
- if (first_init) {
- first_init = 0;
- list_init(&active_contexts_list);
- }
- list_add (&ctx->list, &active_contexts_list);
+ list_add(&_ctx->list, &active_contexts_list);
usbi_mutex_static_unlock(&active_contexts_lock);
if (usbi_backend.init) {
- r = usbi_backend.init(ctx);
+ r = usbi_backend.init(_ctx);
if (r)
- goto err_free_ctx;
+ goto err_io_exit;
}
- r = usbi_io_init(ctx);
- if (r < 0)
- goto err_backend_exit;
+ usbi_hotplug_init(_ctx);
usbi_mutex_static_unlock(&default_context_lock);
- if (context)
- *context = ctx;
+ if (ctx)
+ *ctx = _ctx;
return 0;
-err_backend_exit:
- if (usbi_backend.exit)
- usbi_backend.exit(ctx);
-err_free_ctx:
- if (ctx == usbi_default_context) {
- usbi_default_context = NULL;
- default_context_refcnt--;
- }
-
+err_io_exit:
usbi_mutex_static_lock(&active_contexts_lock);
- list_del(&ctx->list);
+ list_del(&_ctx->list);
usbi_mutex_static_unlock(&active_contexts_lock);
- usbi_mutex_lock(&ctx->usb_devs_lock);
- for_each_device_safe(ctx, dev, next) {
- list_del(&dev->list);
- libusb_unref_device(dev);
+ if (!ctx) {
+ usbi_default_context = NULL;
+ default_context_refcnt = 0;
}
- usbi_mutex_unlock(&ctx->usb_devs_lock);
- usbi_mutex_destroy(&ctx->open_devs_lock);
- usbi_mutex_destroy(&ctx->usb_devs_lock);
- usbi_mutex_destroy(&ctx->hotplug_cbs_lock);
-
- free(ctx);
-err_unlock:
usbi_mutex_static_unlock(&default_context_lock);
+
+ usbi_hotplug_exit(_ctx);
+ usbi_io_exit(_ctx);
+
+err_free_ctx:
+ usbi_mutex_destroy(&_ctx->open_devs_lock);
+ usbi_mutex_destroy(&_ctx->usb_devs_lock);
+
+ free(_ctx);
+
return r;
}
@@ -2364,18 +2344,14 @@
*/
void API_EXPORTED libusb_exit(libusb_context *ctx)
{
- struct libusb_device *dev, *next;
- struct timeval tv = { 0, 0 };
- int destroying_default_context = 0;
+ struct libusb_context *_ctx;
+ struct libusb_device *dev;
- usbi_dbg(" ");
-
- ctx = usbi_get_context(ctx);
+ usbi_mutex_static_lock(&default_context_lock);
/* if working with default context, only actually do the deinitialization
* if we're the last user */
- usbi_mutex_static_lock(&default_context_lock);
- if (ctx == usbi_default_context) {
+ if (!ctx) {
if (!usbi_default_context) {
usbi_dbg("no default context, not initialized?");
usbi_mutex_static_unlock(&default_context_lock);
@@ -2387,80 +2363,44 @@
usbi_mutex_static_unlock(&default_context_lock);
return;
}
- usbi_dbg("destroying default context");
- /*
- * Setting this flag without unlocking the default context, as
- * we are actually destroying the default context.
- * usbi_default_context is not set to NULL yet, as all activities
- * would only stop after usbi_backend->exit() returns.
- */
- destroying_default_context = 1;
+ usbi_dbg("destroying default context");
+ _ctx = usbi_default_context;
} else {
- /* Unlock default context, as we're not modifying it. */
- usbi_mutex_static_unlock(&default_context_lock);
+ usbi_dbg(" ");
+ _ctx = ctx;
}
usbi_mutex_static_lock(&active_contexts_lock);
- list_del(&ctx->list);
+ list_del(&_ctx->list);
usbi_mutex_static_unlock(&active_contexts_lock);
- /* Don't bother with locking after this point because unless there is
- * an application bug, nobody will be accessing these. */
-
- if (libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
- usbi_hotplug_deregister(ctx, 1);
-
- /*
- * Ensure any pending unplug events are read from the hotplug
- * pipe. The usb_device-s hold in the events are no longer part
- * of usb_devs, but the events still hold a reference!
- *
- * Note we don't do this if the application has left devices
- * open (which implies a buggy app) to avoid packet completion
- * handlers running when the app does not expect them to run.
- */
- if (list_empty(&ctx->open_devs))
- libusb_handle_events_timeout(ctx, &tv);
-
- for_each_device_safe(ctx, dev, next) {
- if (usbi_atomic_load(&dev->refcnt) > 1)
- usbi_warn(ctx, "device %d.%d still referenced",
- dev->bus_number, dev->device_address);
- list_del(&dev->list);
- libusb_unref_device(dev);
- }
- } else {
- /*
- * Backends without hotplug store enumerated devices on the
- * usb_devs list when libusb_get_device_list() is called.
- * These devices are removed from the list when the last
- * reference is dropped, typically when the device list is
- * freed. Any device still on the list has a reference held
- * by the app, which is a bug.
- */
- for_each_device(ctx, dev) {
- usbi_warn(ctx, "device %d.%d still referenced",
- dev->bus_number, dev->device_address);
- }
- }
-
- if (!list_empty(&ctx->open_devs))
- usbi_warn(ctx, "application left some devices open");
-
- usbi_io_exit(ctx);
if (usbi_backend.exit)
- usbi_backend.exit(ctx);
+ usbi_backend.exit(_ctx);
- usbi_mutex_destroy(&ctx->open_devs_lock);
- usbi_mutex_destroy(&ctx->usb_devs_lock);
- usbi_mutex_destroy(&ctx->hotplug_cbs_lock);
- free(ctx);
-
- if (destroying_default_context) {
+ if (!ctx)
usbi_default_context = NULL;
- usbi_mutex_static_unlock(&default_context_lock);
+
+ usbi_mutex_static_unlock(&default_context_lock);
+
+ /* Don't bother with locking after this point because unless there is
+ * an application bug, nobody will be accessing the context. */
+
+ usbi_hotplug_exit(_ctx);
+ usbi_io_exit(_ctx);
+
+ for_each_device(_ctx, dev) {
+ usbi_warn(_ctx, "device %d.%d still referenced",
+ dev->bus_number, dev->device_address);
}
+
+ if (!list_empty(&_ctx->open_devs))
+ usbi_warn(_ctx, "application left some devices open");
+
+ usbi_mutex_destroy(&_ctx->open_devs_lock);
+ usbi_mutex_destroy(&_ctx->usb_devs_lock);
+
+ free(_ctx);
}
/** \ingroup libusb_misc
diff --git a/libusb/hotplug.c b/libusb/hotplug.c
index e3e5e76..387b49f 100644
--- a/libusb/hotplug.c
+++ b/libusb/hotplug.c
@@ -20,7 +20,6 @@
*/
#include "libusbi.h"
-#include "hotplug.h"
/**
* @defgroup libusb_hotplug Device hotplug event notification
@@ -144,15 +143,68 @@
*/
#define VALID_HOTPLUG_EVENTS \
- (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | \
- LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
+ (LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | \
+ LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
#define VALID_HOTPLUG_FLAGS \
- (LIBUSB_HOTPLUG_ENUMERATE)
+ (LIBUSB_HOTPLUG_ENUMERATE)
-static int usbi_hotplug_match_cb(struct libusb_context *ctx,
- struct libusb_device *dev, libusb_hotplug_event event,
- struct libusb_hotplug_callback *hotplug_cb)
+void usbi_hotplug_init(struct libusb_context *ctx)
+{
+ /* check for hotplug support */
+ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
+ return;
+
+ usbi_mutex_init(&ctx->hotplug_cbs_lock);
+ list_init(&ctx->hotplug_cbs);
+ ctx->next_hotplug_cb_handle = 1;
+ usbi_atomic_store(&ctx->hotplug_ready, 1);
+}
+
+void usbi_hotplug_exit(struct libusb_context *ctx)
+{
+ struct usbi_hotplug_callback *hotplug_cb, *next_cb;
+ struct usbi_hotplug_message *msg;
+ struct libusb_device *dev, *next_dev;
+
+ /* check for hotplug support */
+ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
+ return;
+
+ /* free all registered hotplug callbacks */
+ for_each_hotplug_cb_safe(ctx, hotplug_cb, next_cb) {
+ list_del(&hotplug_cb->list);
+ free(hotplug_cb);
+ }
+
+ /* free all pending hotplug messages */
+ while (!list_empty(&ctx->hotplug_msgs)) {
+ msg = list_first_entry(&ctx->hotplug_msgs, struct usbi_hotplug_message, list);
+
+ /* if the device left, the message holds a reference
+ * and we must drop it */
+ if (msg->event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
+ libusb_unref_device(msg->device);
+
+ list_del(&msg->list);
+ free(msg);
+ }
+
+ /* free all discovered devices */
+ for_each_device_safe(ctx, dev, next_dev) {
+ /* remove the device from the usb_devs list only if there are no
+ * references held, otherwise leave it on the list so that a
+ * warning message will be shown */
+ if (usbi_atomic_load(&dev->refcnt) == 1)
+ list_del(&dev->list);
+ libusb_unref_device(dev);
+ }
+
+ usbi_mutex_destroy(&ctx->hotplug_cbs_lock);
+}
+
+static int usbi_hotplug_match_cb(struct libusb_device *dev,
+ libusb_hotplug_event event, struct usbi_hotplug_callback *hotplug_cb)
{
if (!(hotplug_cb->flags & event)) {
return 0;
@@ -173,28 +225,82 @@
return 0;
}
- return hotplug_cb->cb(ctx, dev, event, hotplug_cb->user_data);
+ return hotplug_cb->cb(DEVICE_CTX(dev), dev, event, hotplug_cb->user_data);
}
-void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
+void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
libusb_hotplug_event event)
{
- struct libusb_hotplug_callback *hotplug_cb, *next;
- int ret;
+ struct usbi_hotplug_message *msg;
+ unsigned int event_flags;
+
+ /* Only generate a notification if hotplug is ready. This prevents hotplug
+ * notifications from being generated during initial enumeration or if the
+ * backend does not support hotplug. */
+ if (!usbi_atomic_load(&ctx->hotplug_ready))
+ return;
+
+ msg = calloc(1, sizeof(*msg));
+ if (!msg) {
+ usbi_err(ctx, "error allocating hotplug message");
+ return;
+ }
+
+ msg->event = event;
+ msg->device = dev;
+
+ /* Take the event data lock and add this message to the list.
+ * Only signal an event if there are no prior pending events. */
+ usbi_mutex_lock(&ctx->event_data_lock);
+ event_flags = ctx->event_flags;
+ ctx->event_flags |= USBI_EVENT_HOTPLUG_MSG_PENDING;
+ list_add_tail(&msg->list, &ctx->hotplug_msgs);
+ if (!event_flags)
+ usbi_signal_event(&ctx->event);
+ usbi_mutex_unlock(&ctx->event_data_lock);
+}
+
+void usbi_hotplug_process(struct libusb_context *ctx, struct list_head *hotplug_msgs)
+{
+ struct usbi_hotplug_callback *hotplug_cb, *next_cb;
+ struct usbi_hotplug_message *msg;
+ int r;
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
- for_each_hotplug_cb_safe(ctx, hotplug_cb, next) {
- if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE) {
- /* process deregistration in usbi_hotplug_deregister() */
- continue;
+ /* dispatch all pending hotplug messages */
+ while (!list_empty(hotplug_msgs)) {
+ msg = list_first_entry(hotplug_msgs, struct usbi_hotplug_message, list);
+
+ for_each_hotplug_cb_safe(ctx, hotplug_cb, next_cb) {
+ /* skip callbacks that have unregistered */
+ if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE)
+ continue;
+
+ usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
+ r = usbi_hotplug_match_cb(msg->device, msg->event, hotplug_cb);
+ usbi_mutex_lock(&ctx->hotplug_cbs_lock);
+
+ if (r) {
+ list_del(&hotplug_cb->list);
+ free(hotplug_cb);
+ }
}
- usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
- ret = usbi_hotplug_match_cb(ctx, dev, event, hotplug_cb);
- usbi_mutex_lock(&ctx->hotplug_cbs_lock);
+ /* if the device left, the message holds a reference
+ * and we must drop it */
+ if (msg->event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
+ libusb_unref_device(msg->device);
- if (ret) {
+ list_del(&msg->list);
+ free(msg);
+ }
+
+ /* free any callbacks that have unregistered */
+ for_each_hotplug_cb_safe(ctx, hotplug_cb, next_cb) {
+ if (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE) {
+ usbi_dbg("freeing hotplug cb %p with handle %d",
+ hotplug_cb, hotplug_cb->handle);
list_del(&hotplug_cb->list);
free(hotplug_cb);
}
@@ -203,41 +309,16 @@
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
}
-void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
- libusb_hotplug_event event)
-{
- struct libusb_hotplug_message *message = calloc(1, sizeof(*message));
- unsigned int event_flags;
-
- if (!message) {
- usbi_err(ctx, "error allocating hotplug message");
- return;
- }
-
- message->event = event;
- message->device = dev;
-
- /* Take the event data lock and add this message to the list.
- * Only signal an event if there are no prior pending events. */
- usbi_mutex_lock(&ctx->event_data_lock);
- event_flags = ctx->event_flags;
- ctx->event_flags |= USBI_EVENT_HOTPLUG_MSG_PENDING;
- list_add_tail(&message->list, &ctx->hotplug_msgs);
- if (!event_flags)
- usbi_signal_event(&ctx->event);
- usbi_mutex_unlock(&ctx->event_data_lock);
-}
-
int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx,
int events, int flags,
int vendor_id, int product_id, int dev_class,
libusb_hotplug_callback_fn cb_fn, void *user_data,
libusb_hotplug_callback_handle *callback_handle)
{
- struct libusb_hotplug_callback *new_callback;
+ struct usbi_hotplug_callback *hotplug_cb;
/* check for sane values */
- if ((!events || (~VALID_HOTPLUG_EVENTS & events)) ||
+ if (!events || (~VALID_HOTPLUG_EVENTS & events) ||
(~VALID_HOTPLUG_FLAGS & flags) ||
(LIBUSB_HOTPLUG_MATCH_ANY != vendor_id && (~0xffff & vendor_id)) ||
(LIBUSB_HOTPLUG_MATCH_ANY != product_id && (~0xffff & product_id)) ||
@@ -247,47 +328,45 @@
}
/* check for hotplug support */
- if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
return LIBUSB_ERROR_NOT_SUPPORTED;
- }
ctx = usbi_get_context(ctx);
- new_callback = calloc(1, sizeof(*new_callback));
- if (!new_callback) {
+ hotplug_cb = calloc(1, sizeof(*hotplug_cb));
+ if (!hotplug_cb)
return LIBUSB_ERROR_NO_MEM;
- }
- new_callback->flags = (uint8_t)events;
+ hotplug_cb->flags = (uint8_t)events;
if (LIBUSB_HOTPLUG_MATCH_ANY != vendor_id) {
- new_callback->flags |= USBI_HOTPLUG_VENDOR_ID_VALID;
- new_callback->vendor_id = (uint16_t)vendor_id;
+ hotplug_cb->flags |= USBI_HOTPLUG_VENDOR_ID_VALID;
+ hotplug_cb->vendor_id = (uint16_t)vendor_id;
}
if (LIBUSB_HOTPLUG_MATCH_ANY != product_id) {
- new_callback->flags |= USBI_HOTPLUG_PRODUCT_ID_VALID;
- new_callback->product_id = (uint16_t)product_id;
+ hotplug_cb->flags |= USBI_HOTPLUG_PRODUCT_ID_VALID;
+ hotplug_cb->product_id = (uint16_t)product_id;
}
if (LIBUSB_HOTPLUG_MATCH_ANY != dev_class) {
- new_callback->flags |= USBI_HOTPLUG_DEV_CLASS_VALID;
- new_callback->dev_class = (uint8_t)dev_class;
+ hotplug_cb->flags |= USBI_HOTPLUG_DEV_CLASS_VALID;
+ hotplug_cb->dev_class = (uint8_t)dev_class;
}
- new_callback->cb = cb_fn;
- new_callback->user_data = user_data;
+ hotplug_cb->cb = cb_fn;
+ hotplug_cb->user_data = user_data;
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
/* protect the handle by the context hotplug lock */
- new_callback->handle = ctx->next_hotplug_cb_handle++;
+ hotplug_cb->handle = ctx->next_hotplug_cb_handle++;
/* handle the unlikely case of overflow */
if (ctx->next_hotplug_cb_handle < 0)
ctx->next_hotplug_cb_handle = 1;
- list_add(&new_callback->list, &ctx->hotplug_cbs);
+ list_add(&hotplug_cb->list, &ctx->hotplug_cbs);
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
- usbi_dbg("new hotplug cb %p with handle %d", new_callback, new_callback->handle);
+ usbi_dbg("new hotplug cb %p with handle %d", hotplug_cb, hotplug_cb->handle);
if ((flags & LIBUSB_HOTPLUG_ENUMERATE) && (events & LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED)) {
ssize_t i, len;
@@ -295,23 +374,21 @@
len = libusb_get_device_list(ctx, &devs);
if (len < 0) {
- libusb_hotplug_deregister_callback(ctx,
- new_callback->handle);
+ libusb_hotplug_deregister_callback(ctx, hotplug_cb->handle);
return (int)len;
}
for (i = 0; i < len; i++) {
- usbi_hotplug_match_cb(ctx, devs[i],
+ usbi_hotplug_match_cb(devs[i],
LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
- new_callback);
+ hotplug_cb);
}
libusb_free_device_list(devs, 1);
}
-
if (callback_handle)
- *callback_handle = new_callback->handle;
+ *callback_handle = hotplug_cb->handle;
return LIBUSB_SUCCESS;
}
@@ -319,13 +396,12 @@
void API_EXPORTED libusb_hotplug_deregister_callback(libusb_context *ctx,
libusb_hotplug_callback_handle callback_handle)
{
- struct libusb_hotplug_callback *hotplug_cb;
+ struct usbi_hotplug_callback *hotplug_cb;
int deregistered = 0;
/* check for hotplug support */
- if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
return;
- }
usbi_dbg("deregister hotplug cb %d", callback_handle);
@@ -334,9 +410,10 @@
usbi_mutex_lock(&ctx->hotplug_cbs_lock);
for_each_hotplug_cb(ctx, hotplug_cb) {
if (callback_handle == hotplug_cb->handle) {
- /* Mark this callback for deregistration */
+ /* mark this callback for deregistration */
hotplug_cb->flags |= USBI_HOTPLUG_NEEDS_FREE;
deregistered = 1;
+ break;
}
}
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
@@ -357,15 +434,14 @@
void * LIBUSB_CALL libusb_hotplug_get_user_data(libusb_context *ctx,
libusb_hotplug_callback_handle callback_handle)
{
- struct libusb_hotplug_callback *hotplug_cb;
+ struct usbi_hotplug_callback *hotplug_cb;
void *user_data = NULL;
/* check for hotplug support */
- if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG)) {
+ if (!libusb_has_capability(LIBUSB_CAP_HAS_HOTPLUG))
return NULL;
- }
- usbi_dbg("get hotplug user data %d", callback_handle);
+ usbi_dbg("get hotplug cb %d user data", callback_handle);
ctx = usbi_get_context(ctx);
@@ -373,25 +449,10 @@
for_each_hotplug_cb(ctx, hotplug_cb) {
if (callback_handle == hotplug_cb->handle) {
user_data = hotplug_cb->user_data;
+ break;
}
}
usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
return user_data;
}
-
-void usbi_hotplug_deregister(struct libusb_context *ctx, int forced)
-{
- struct libusb_hotplug_callback *hotplug_cb, *next;
-
- usbi_mutex_lock(&ctx->hotplug_cbs_lock);
- for_each_hotplug_cb_safe(ctx, hotplug_cb, next) {
- if (forced || (hotplug_cb->flags & USBI_HOTPLUG_NEEDS_FREE)) {
- usbi_dbg("freeing hotplug cb %p with handle %d", hotplug_cb,
- hotplug_cb->handle);
- list_del(&hotplug_cb->list);
- free(hotplug_cb);
- }
- }
- usbi_mutex_unlock(&ctx->hotplug_cbs_lock);
-}
diff --git a/libusb/hotplug.h b/libusb/hotplug.h
deleted file mode 100644
index 161f7e5..0000000
--- a/libusb/hotplug.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
-/*
- * Hotplug support for libusb
- * Copyright © 2012-2013 Nathan Hjelm <hjelmn@mac.com>
- * Copyright © 2012-2013 Peter Stuge <peter@stuge.se>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#ifndef USBI_HOTPLUG_H
-#define USBI_HOTPLUG_H
-
-#include "libusbi.h"
-
-enum usbi_hotplug_flags {
- /* This callback is interested in device arrivals */
- USBI_HOTPLUG_DEVICE_ARRIVED = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
-
- /* This callback is interested in device removals */
- USBI_HOTPLUG_DEVICE_LEFT = LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
-
- /* IMPORTANT: The values for the below entries must start *after*
- * the highest value of the above entries!!!
- */
-
- /* The vendor_id field is valid for matching */
- USBI_HOTPLUG_VENDOR_ID_VALID = (1U << 3),
-
- /* The product_id field is valid for matching */
- USBI_HOTPLUG_PRODUCT_ID_VALID = (1U << 4),
-
- /* The dev_class field is valid for matching */
- USBI_HOTPLUG_DEV_CLASS_VALID = (1U << 5),
-
- /* This callback has been unregistered and needs to be freed */
- USBI_HOTPLUG_NEEDS_FREE = (1U << 6),
-};
-
-/** \ingroup hotplug
- * The hotplug callback structure. The user populates this structure with
- * libusb_hotplug_prepare_callback() and then calls libusb_hotplug_register_callback()
- * to receive notification of hotplug events.
- */
-struct libusb_hotplug_callback {
- /** Flags that control how this callback behaves */
- uint8_t flags;
-
- /** Vendor ID to match (if flags says this is valid) */
- uint16_t vendor_id;
-
- /** Product ID to match (if flags says this is valid) */
- uint16_t product_id;
-
- /** Device class to match (if flags says this is valid) */
- uint8_t dev_class;
-
- /** Callback function to invoke for matching event/device */
- libusb_hotplug_callback_fn cb;
-
- /** Handle for this callback (used to match on deregister) */
- libusb_hotplug_callback_handle handle;
-
- /** User data that will be passed to the callback function */
- void *user_data;
-
- /** List this callback is registered in (ctx->hotplug_cbs) */
- struct list_head list;
-};
-
-struct libusb_hotplug_message {
- /** The hotplug event that occurred */
- libusb_hotplug_event event;
-
- /** The device for which this hotplug event occurred */
- struct libusb_device *device;
-
- /** List this message is contained in (ctx->hotplug_msgs) */
- struct list_head list;
-};
-
-#define for_each_hotplug_cb(ctx, c) \
- for_each_helper(c, &(ctx)->hotplug_cbs, struct libusb_hotplug_callback)
-
-#define for_each_hotplug_cb_safe(ctx, c, n) \
- for_each_safe_helper(c, n, &(ctx)->hotplug_cbs, struct libusb_hotplug_callback)
-
-void usbi_hotplug_deregister(struct libusb_context *ctx, int forced);
-void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev,
- libusb_hotplug_event event);
-void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
- libusb_hotplug_event event);
-
-#endif
diff --git a/libusb/io.c b/libusb/io.c
index 0e960dd..ecd750f 100644
--- a/libusb/io.c
+++ b/libusb/io.c
@@ -22,7 +22,6 @@
*/
#include "libusbi.h"
-#include "hotplug.h"
/**
* \page libusb_io Synchronous and asynchronous device I/O
@@ -2073,6 +2072,7 @@
static int handle_event_trigger(struct libusb_context *ctx)
{
struct list_head hotplug_msgs;
+ int hotplug_event = 0;
int r = 0;
usbi_dbg("event triggered");
@@ -2091,6 +2091,12 @@
ctx->event_flags &= ~USBI_EVENT_USER_INTERRUPT;
}
+ if (ctx->event_flags & USBI_EVENT_HOTPLUG_CB_DEREGISTERED) {
+ usbi_dbg("someone unregistered a hotplug cb");
+ ctx->event_flags &= ~USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
+ hotplug_event = 1;
+ }
+
/* check if someone is closing a device */
if (ctx->event_flags & USBI_EVENT_DEVICE_CLOSE)
usbi_dbg("someone is closing a device");
@@ -2099,6 +2105,7 @@
if (ctx->event_flags & USBI_EVENT_HOTPLUG_MSG_PENDING) {
usbi_dbg("hotplug message received");
ctx->event_flags &= ~USBI_EVENT_HOTPLUG_MSG_PENDING;
+ hotplug_event = 1;
assert(!list_empty(&ctx->hotplug_msgs));
list_cut(&hotplug_msgs, &ctx->hotplug_msgs);
}
@@ -2136,20 +2143,9 @@
usbi_mutex_unlock(&ctx->event_data_lock);
- /* process the hotplug messages, if any */
- while (!list_empty(&hotplug_msgs)) {
- struct libusb_hotplug_message *message =
- list_first_entry(&hotplug_msgs, struct libusb_hotplug_message, list);
-
- usbi_hotplug_match(ctx, message->device, message->event);
-
- /* the device left, dereference the device */
- if (message->event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
- libusb_unref_device(message->device);
-
- list_del(&message->list);
- free(message);
- }
+ /* process the hotplug events, if any */
+ if (hotplug_event)
+ usbi_hotplug_process(ctx, &hotplug_msgs);
return r;
}
diff --git a/libusb/libusbi.h b/libusb/libusbi.h
index 7656660..97c894e 100644
--- a/libusb/libusbi.h
+++ b/libusb/libusbi.h
@@ -368,6 +368,9 @@
libusb_hotplug_callback_handle next_hotplug_cb_handle;
usbi_mutex_t hotplug_cbs_lock;
+ /* A flag to indicate that the context is ready for hotplug notifications */
+ usbi_atomic_t hotplug_ready;
+
/* this is a list of in-flight transfer handles, sorted by timeout
* expiration. URBs to timeout the soonest are placed at the beginning of
* the list, URBs that will time out later are placed after, and urbs with
@@ -689,8 +692,75 @@
uint16_t align; /* Force 2-byte alignment */
};
+enum usbi_hotplug_flags {
+ /* This callback is interested in device arrivals */
+ USBI_HOTPLUG_DEVICE_ARRIVED = LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED,
+
+ /* This callback is interested in device removals */
+ USBI_HOTPLUG_DEVICE_LEFT = LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT,
+
+ /* IMPORTANT: The values for the below entries must start *after*
+ * the highest value of the above entries!!!
+ */
+
+ /* The vendor_id field is valid for matching */
+ USBI_HOTPLUG_VENDOR_ID_VALID = (1U << 3),
+
+ /* The product_id field is valid for matching */
+ USBI_HOTPLUG_PRODUCT_ID_VALID = (1U << 4),
+
+ /* The dev_class field is valid for matching */
+ USBI_HOTPLUG_DEV_CLASS_VALID = (1U << 5),
+
+ /* This callback has been unregistered and needs to be freed */
+ USBI_HOTPLUG_NEEDS_FREE = (1U << 6),
+};
+
+struct usbi_hotplug_callback {
+ /* Flags that control how this callback behaves */
+ uint8_t flags;
+
+ /* Vendor ID to match (if flags says this is valid) */
+ uint16_t vendor_id;
+
+ /* Product ID to match (if flags says this is valid) */
+ uint16_t product_id;
+
+ /* Device class to match (if flags says this is valid) */
+ uint8_t dev_class;
+
+ /* Callback function to invoke for matching event/device */
+ libusb_hotplug_callback_fn cb;
+
+ /* Handle for this callback (used to match on deregister) */
+ libusb_hotplug_callback_handle handle;
+
+ /* User data that will be passed to the callback function */
+ void *user_data;
+
+ /* List this callback is registered in (ctx->hotplug_cbs) */
+ struct list_head list;
+};
+
+struct usbi_hotplug_message {
+ /* The hotplug event that occurred */
+ libusb_hotplug_event event;
+
+ /* The device for which this hotplug event occurred */
+ struct libusb_device *device;
+
+ /* List this message is contained in (ctx->hotplug_msgs) */
+ struct list_head list;
+};
+
/* shared data and functions */
+void usbi_hotplug_init(struct libusb_context *ctx);
+void usbi_hotplug_exit(struct libusb_context *ctx);
+void usbi_hotplug_notification(struct libusb_context *ctx, struct libusb_device *dev,
+ libusb_hotplug_event event);
+void usbi_hotplug_process(struct libusb_context *ctx, struct list_head *hotplug_msgs);
+
int usbi_io_init(struct libusb_context *ctx);
void usbi_io_exit(struct libusb_context *ctx);
@@ -818,7 +888,8 @@
* data structures for later, etc.
*
* This function is called when a libusb user initializes the library
- * prior to use.
+ * prior to use. Mutual exclusion with other init and exit calls is
+ * guaranteed when this function is called.
*
* Return 0 on success, or a LIBUSB_ERROR code on failure.
*/
@@ -828,6 +899,8 @@
* that was set up by init.
*
* This function is called when the user deinitializes the library.
+ * Mutual exclusion with other init and exit calls is guaranteed when
+ * this function is called.
*/
void (*exit)(struct libusb_context *ctx);
@@ -1390,6 +1463,12 @@
#define for_each_removed_event_source_safe(ctx, e, n) \
for_each_safe_helper(e, n, &(ctx)->removed_event_sources, struct usbi_event_source)
+#define for_each_hotplug_cb(ctx, c) \
+ for_each_helper(c, &(ctx)->hotplug_cbs, struct usbi_hotplug_callback)
+
+#define for_each_hotplug_cb_safe(ctx, c, n) \
+ for_each_safe_helper(c, n, &(ctx)->hotplug_cbs, struct usbi_hotplug_callback)
+
#ifdef __cplusplus
}
#endif
diff --git a/libusb/os/darwin_usb.c b/libusb/os/darwin_usb.c
index 2e64038..acfdf97 100644
--- a/libusb/os/darwin_usb.c
+++ b/libusb/os/darwin_usb.c
@@ -52,7 +52,6 @@
#include "darwin_usb.h"
-static pthread_mutex_t libusb_darwin_init_mutex = PTHREAD_MUTEX_INITIALIZER;
static int init_count = 0;
/* async event thread */
@@ -581,8 +580,6 @@
bool first_init;
int rc;
- pthread_mutex_lock (&libusb_darwin_init_mutex);
-
first_init = (1 == ++init_count);
do {
@@ -638,16 +635,12 @@
--init_count;
}
- pthread_mutex_unlock (&libusb_darwin_init_mutex);
-
return rc;
}
static void darwin_exit (struct libusb_context *ctx) {
UNUSED(ctx);
- pthread_mutex_lock (&libusb_darwin_init_mutex);
-
if (0 == --init_count) {
/* stop the event runloop and wait for the thread to terminate. */
pthread_mutex_lock (&libusb_darwin_at_mutex);
@@ -665,8 +658,6 @@
mach_port_deallocate(mach_task_self(), clock_monotonic);
#endif
}
-
- pthread_mutex_unlock (&libusb_darwin_init_mutex);
}
static int get_configuration_index (struct libusb_device *dev, UInt8 config_value) {
diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c
index 3a1894c..5b57993 100644
--- a/libusb/os/linux_usbfs.c
+++ b/libusb/os/linux_usbfs.c
@@ -100,8 +100,6 @@
static int weak_authority = 0;
#endif
-/* Serialize hotplug start/stop */
-static usbi_mutex_static_t linux_hotplug_startstop_lock = USBI_MUTEX_INITIALIZER;
/* Serialize scan-devices, event-thread, and poll */
usbi_mutex_static_t linux_hotplug_lock = USBI_MUTEX_INITIALIZER;
@@ -407,7 +405,6 @@
}
#endif
- usbi_mutex_static_lock(&linux_hotplug_startstop_lock);
r = LIBUSB_SUCCESS;
if (init_count == 0) {
/* start up hotplug event handler */
@@ -422,7 +419,6 @@
} else {
usbi_err(ctx, "error starting hotplug event monitor");
}
- usbi_mutex_static_unlock(&linux_hotplug_startstop_lock);
return r;
}
@@ -437,13 +433,11 @@
}
#endif
- usbi_mutex_static_lock(&linux_hotplug_startstop_lock);
assert(init_count != 0);
if (!--init_count) {
/* tear down event handler */
linux_stop_event_monitor();
}
- usbi_mutex_static_unlock(&linux_hotplug_startstop_lock);
}
static int op_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap)
diff --git a/libusb/os/windows_common.c b/libusb/os/windows_common.c
index 6e69317..72499ee 100644
--- a/libusb/os/windows_common.c
+++ b/libusb/os/windows_common.c
@@ -477,26 +477,9 @@
static int windows_init(struct libusb_context *ctx)
{
struct windows_context_priv *priv = usbi_get_context_priv(ctx);
- char mutex_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
- HANDLE mutex;
bool winusb_backend_init = false;
int r;
- sprintf(mutex_name, "libusb_init%08lX", ULONG_CAST(GetCurrentProcessId() & 0xFFFFFFFFU));
- mutex = CreateMutexA(NULL, FALSE, mutex_name);
- if (mutex == NULL) {
- usbi_err(ctx, "could not create mutex: %s", windows_error_str(0));
- return LIBUSB_ERROR_NO_MEM;
- }
-
- // A successful wait gives this thread ownership of the mutex
- // => any concurrent wait stalls until the mutex is released
- if (WaitForSingleObject(mutex, INFINITE) != WAIT_OBJECT_0) {
- usbi_err(ctx, "failure to access mutex: %s", windows_error_str(0));
- CloseHandle(mutex);
- return LIBUSB_ERROR_NO_MEM;
- }
-
// NB: concurrent usage supposes that init calls are equally balanced with
// exit calls. If init is called more than exit, we will not exit properly
if (++init_count == 1) { // First init?
@@ -565,29 +548,12 @@
--init_count;
}
- ReleaseMutex(mutex);
- CloseHandle(mutex);
return r;
}
static void windows_exit(struct libusb_context *ctx)
{
struct windows_context_priv *priv = usbi_get_context_priv(ctx);
- char mutex_name[11 + 8 + 1]; // strlen("libusb_init") + (32-bit hex PID) + '\0'
- HANDLE mutex;
-
- sprintf(mutex_name, "libusb_init%08lX", ULONG_CAST(GetCurrentProcessId() & 0xFFFFFFFFU));
- mutex = CreateMutexA(NULL, FALSE, mutex_name);
- if (mutex == NULL)
- return;
-
- // A successful wait gives this thread ownership of the mutex
- // => any concurrent wait stalls until the mutex is released
- if (WaitForSingleObject(mutex, INFINITE) != WAIT_OBJECT_0) {
- usbi_err(ctx, "failed to access mutex: %s", windows_error_str(0));
- CloseHandle(mutex);
- return;
- }
// A NULL completion status will indicate to the thread that it is time to exit
if (!PostQueuedCompletionStatus(priv->completion_port, 0, (ULONG_PTR)ctx, NULL))
@@ -608,9 +574,6 @@
winusb_backend.exit(ctx);
htab_destroy();
}
-
- ReleaseMutex(mutex);
- CloseHandle(mutex);
}
static int windows_set_option(struct libusb_context *ctx, enum libusb_option option, va_list ap)
diff --git a/msvc/libusb_dll_2013.vcxproj b/msvc/libusb_dll_2013.vcxproj
index 56ffd75..03212dc 100644
--- a/msvc/libusb_dll_2013.vcxproj
+++ b/msvc/libusb_dll_2013.vcxproj
@@ -83,7 +83,6 @@
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\os\events_windows.h" />
- <ClInclude Include="..\libusb\hotplug.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\libusb\libusbi.h" />
<ClInclude Include="..\libusb\os\threads_windows.h" />
diff --git a/msvc/libusb_dll_2013.vcxproj.filters b/msvc/libusb_dll_2013.vcxproj.filters
index 8da28e3..c8643f2 100644
--- a/msvc/libusb_dll_2013.vcxproj.filters
+++ b/msvc/libusb_dll_2013.vcxproj.filters
@@ -21,9 +21,6 @@
<ClInclude Include="..\libusb\os\events_windows.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="..\libusb\hotplug.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="..\libusb\libusb.h">
<Filter>Header Files</Filter>
</ClInclude>
diff --git a/msvc/libusb_dll_2015.vcxproj b/msvc/libusb_dll_2015.vcxproj
index d2c850d..f24d94b 100644
--- a/msvc/libusb_dll_2015.vcxproj
+++ b/msvc/libusb_dll_2015.vcxproj
@@ -84,7 +84,6 @@
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\os\events_windows.h" />
- <ClInclude Include="..\libusb\hotplug.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\libusb\libusbi.h" />
<ClInclude Include="..\libusb\os\threads_windows.h" />
diff --git a/msvc/libusb_dll_2015.vcxproj.filters b/msvc/libusb_dll_2015.vcxproj.filters
index 8da28e3..c8643f2 100644
--- a/msvc/libusb_dll_2015.vcxproj.filters
+++ b/msvc/libusb_dll_2015.vcxproj.filters
@@ -21,9 +21,6 @@
<ClInclude Include="..\libusb\os\events_windows.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="..\libusb\hotplug.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="..\libusb\libusb.h">
<Filter>Header Files</Filter>
</ClInclude>
diff --git a/msvc/libusb_dll_2017.vcxproj b/msvc/libusb_dll_2017.vcxproj
index 598159d..2ff2f94 100644
--- a/msvc/libusb_dll_2017.vcxproj
+++ b/msvc/libusb_dll_2017.vcxproj
@@ -103,7 +103,6 @@
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\os\events_windows.h" />
- <ClInclude Include="..\libusb\hotplug.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\libusb\libusbi.h" />
<ClInclude Include="..\libusb\os\threads_windows.h" />
diff --git a/msvc/libusb_dll_2017.vcxproj.filters b/msvc/libusb_dll_2017.vcxproj.filters
index 8da28e3..c8643f2 100644
--- a/msvc/libusb_dll_2017.vcxproj.filters
+++ b/msvc/libusb_dll_2017.vcxproj.filters
@@ -21,9 +21,6 @@
<ClInclude Include="..\libusb\os\events_windows.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="..\libusb\hotplug.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="..\libusb\libusb.h">
<Filter>Header Files</Filter>
</ClInclude>
diff --git a/msvc/libusb_dll_2019.vcxproj b/msvc/libusb_dll_2019.vcxproj
index dbd8717..266166e 100644
--- a/msvc/libusb_dll_2019.vcxproj
+++ b/msvc/libusb_dll_2019.vcxproj
@@ -103,7 +103,6 @@
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\os\events_windows.h" />
- <ClInclude Include="..\libusb\hotplug.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\libusb\libusbi.h" />
<ClInclude Include="..\libusb\os\threads_windows.h" />
diff --git a/msvc/libusb_dll_2019.vcxproj.filters b/msvc/libusb_dll_2019.vcxproj.filters
index 8da28e3..c8643f2 100644
--- a/msvc/libusb_dll_2019.vcxproj.filters
+++ b/msvc/libusb_dll_2019.vcxproj.filters
@@ -21,9 +21,6 @@
<ClInclude Include="..\libusb\os\events_windows.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="..\libusb\hotplug.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="..\libusb\libusb.h">
<Filter>Header Files</Filter>
</ClInclude>
diff --git a/msvc/libusb_static_2013.vcxproj b/msvc/libusb_static_2013.vcxproj
index 1b287e5..94ba597 100644
--- a/msvc/libusb_static_2013.vcxproj
+++ b/msvc/libusb_static_2013.vcxproj
@@ -79,7 +79,6 @@
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\os\events_windows.h" />
- <ClInclude Include="..\libusb\hotplug.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\libusb\libusbi.h" />
<ClInclude Include="..\libusb\os\threads_windows.h" />
diff --git a/msvc/libusb_static_2013.vcxproj.filters b/msvc/libusb_static_2013.vcxproj.filters
index 2994ca1..a3294da 100644
--- a/msvc/libusb_static_2013.vcxproj.filters
+++ b/msvc/libusb_static_2013.vcxproj.filters
@@ -17,9 +17,6 @@
<ClInclude Include="..\libusb\os\events_windows.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="..\libusb\hotplug.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="..\libusb\libusb.h">
<Filter>Header Files</Filter>
</ClInclude>
diff --git a/msvc/libusb_static_2015.vcxproj b/msvc/libusb_static_2015.vcxproj
index 9fa30da..f951523 100644
--- a/msvc/libusb_static_2015.vcxproj
+++ b/msvc/libusb_static_2015.vcxproj
@@ -80,7 +80,6 @@
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\os\events_windows.h" />
- <ClInclude Include="..\libusb\hotplug.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\libusb\libusbi.h" />
<ClInclude Include="..\libusb\os\threads_windows.h" />
diff --git a/msvc/libusb_static_2015.vcxproj.filters b/msvc/libusb_static_2015.vcxproj.filters
index 2994ca1..a3294da 100644
--- a/msvc/libusb_static_2015.vcxproj.filters
+++ b/msvc/libusb_static_2015.vcxproj.filters
@@ -17,9 +17,6 @@
<ClInclude Include="..\libusb\os\events_windows.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="..\libusb\hotplug.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="..\libusb\libusb.h">
<Filter>Header Files</Filter>
</ClInclude>
diff --git a/msvc/libusb_static_2017.vcxproj b/msvc/libusb_static_2017.vcxproj
index 62076e0..857ee3f 100644
--- a/msvc/libusb_static_2017.vcxproj
+++ b/msvc/libusb_static_2017.vcxproj
@@ -99,7 +99,6 @@
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\os\events_windows.h" />
- <ClInclude Include="..\libusb\hotplug.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\libusb\libusbi.h" />
<ClInclude Include="..\libusb\os\threads_windows.h" />
diff --git a/msvc/libusb_static_2017.vcxproj.filters b/msvc/libusb_static_2017.vcxproj.filters
index 2994ca1..a3294da 100644
--- a/msvc/libusb_static_2017.vcxproj.filters
+++ b/msvc/libusb_static_2017.vcxproj.filters
@@ -17,9 +17,6 @@
<ClInclude Include="..\libusb\os\events_windows.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="..\libusb\hotplug.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="..\libusb\libusb.h">
<Filter>Header Files</Filter>
</ClInclude>
diff --git a/msvc/libusb_static_2019.vcxproj b/msvc/libusb_static_2019.vcxproj
index 60ad642..036ce95 100644
--- a/msvc/libusb_static_2019.vcxproj
+++ b/msvc/libusb_static_2019.vcxproj
@@ -99,7 +99,6 @@
<ItemGroup>
<ClInclude Include=".\config.h" />
<ClInclude Include="..\libusb\os\events_windows.h" />
- <ClInclude Include="..\libusb\hotplug.h" />
<ClInclude Include="..\libusb\libusb.h" />
<ClInclude Include="..\libusb\libusbi.h" />
<ClInclude Include="..\libusb\os\threads_windows.h" />
diff --git a/msvc/libusb_static_2019.vcxproj.filters b/msvc/libusb_static_2019.vcxproj.filters
index 2994ca1..a3294da 100644
--- a/msvc/libusb_static_2019.vcxproj.filters
+++ b/msvc/libusb_static_2019.vcxproj.filters
@@ -17,9 +17,6 @@
<ClInclude Include="..\libusb\os\events_windows.h">
<Filter>Header Files</Filter>
</ClInclude>
- <ClInclude Include="..\libusb\hotplug.h">
- <Filter>Header Files</Filter>
- </ClInclude>
<ClInclude Include="..\libusb\libusb.h">
<Filter>Header Files</Filter>
</ClInclude>