From 32a22069428cda9d63aa666e92fb8882a83d4515 Mon Sep 17 00:00:00 2001 From: Chris Dickens Date: Wed, 20 Jan 2021 11:18:35 -0800 Subject: [PATCH] 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 Signed-off-by: Nathan Hjelm --- Xcode/libusb.xcodeproj/project.pbxproj | 4 - doc/Makefile.in | 2 +- doc/doxygen.cfg.in | 3 +- libusb/Makefile.am | 2 +- libusb/core.c | 242 +++++++++-------------- libusb/hotplug.c | 247 +++++++++++++++--------- libusb/hotplug.h | 105 ---------- libusb/io.c | 26 ++- libusb/libusbi.h | 81 +++++++- libusb/os/darwin_usb.c | 9 - libusb/os/linux_usbfs.c | 6 - libusb/os/windows_common.c | 37 ---- msvc/libusb_dll_2013.vcxproj | 1 - msvc/libusb_dll_2013.vcxproj.filters | 3 - msvc/libusb_dll_2015.vcxproj | 1 - msvc/libusb_dll_2015.vcxproj.filters | 3 - msvc/libusb_dll_2017.vcxproj | 1 - msvc/libusb_dll_2017.vcxproj.filters | 3 - msvc/libusb_dll_2019.vcxproj | 1 - msvc/libusb_dll_2019.vcxproj.filters | 3 - msvc/libusb_static_2013.vcxproj | 1 - msvc/libusb_static_2013.vcxproj.filters | 3 - msvc/libusb_static_2015.vcxproj | 1 - msvc/libusb_static_2015.vcxproj.filters | 3 - msvc/libusb_static_2017.vcxproj | 1 - msvc/libusb_static_2017.vcxproj.filters | 3 - msvc/libusb_static_2019.vcxproj | 1 - msvc/libusb_static_2019.vcxproj.filters | 3 - 28 files changed, 339 insertions(+), 457 deletions(-) delete mode 100644 libusb/hotplug.h diff --git a/Xcode/libusb.xcodeproj/project.pbxproj b/Xcode/libusb.xcodeproj/project.pbxproj index 958e2566..759a1025 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 = ""; tabWidth = 4; usesTabs = 1; }; - 1438D77917A2ED9F00166101 /* hotplug.h */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = hotplug.h; sourceTree = ""; tabWidth = 4; usesTabs = 1; }; 1438D77E17A2F0EA00166101 /* strerror.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = strerror.c; sourceTree = ""; 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 45c3209e..6568c4ff 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 10f8fc44..b6e6219c 100644 --- a/doc/doxygen.cfg.in +++ b/doc/doxygen.cfg.in @@ -899,8 +899,7 @@ RECURSIVE = NO # 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 c78006e5..baf7b38f 100644 --- a/libusb/Makefile.am +++ b/libusb/Makefile.am @@ -82,7 +82,7 @@ endif 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 7a2f6c37..84147565 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 #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 @@ struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, 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 @@ void usbi_connect_device(struct libusb_device *dev) 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 @@ void usbi_disconnect_device(struct libusb_device *dev) 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 @@ static enum libusb_log_level get_env_debug_level(void) * 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 @@ err_unlock: */ 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 @@ void API_EXPORTED libusb_exit(libusb_context *ctx) 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 e3e5e76e..387b49f4 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 @@ int main (void) { */ #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 @@ static int usbi_hotplug_match_cb(struct libusb_context *ctx, 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 @@ void usbi_hotplug_match(struct libusb_context *ctx, struct libusb_device *dev, 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 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, } /* 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 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, 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 @@ int API_EXPORTED libusb_hotplug_register_callback(libusb_context *ctx, 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 @@ void API_EXPORTED libusb_hotplug_deregister_callback(libusb_context *ctx, 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 @@ DEFAULT_VISIBILITY 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 @@ void * LIBUSB_CALL libusb_hotplug_get_user_data(libusb_context *ctx, 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 161f7e5f..00000000 --- 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 - * Copyright © 2012-2013 Peter Stuge - * - * 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 0e960ddf..ecd750fb 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 void handle_timeouts(struct libusb_context *ctx) 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 @@ static int handle_event_trigger(struct libusb_context *ctx) 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 @@ static int handle_event_trigger(struct libusb_context *ctx) 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 @@ static int handle_event_trigger(struct libusb_context *ctx) 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 76566609..97c894e2 100644 --- a/libusb/libusbi.h +++ b/libusb/libusbi.h @@ -368,6 +368,9 @@ struct libusb_context { 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 @@ union usbi_bos_desc_buf { 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 @@ struct usbi_os_backend { * 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 @@ struct usbi_os_backend { * 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 @@ extern const struct usbi_os_backend usbi_backend; #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 2e64038c..acfdf97d 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 @@ static int darwin_init(struct libusb_context *ctx) { bool first_init; int rc; - pthread_mutex_lock (&libusb_darwin_init_mutex); - first_init = (1 == ++init_count); do { @@ -638,16 +635,12 @@ static int darwin_init(struct libusb_context *ctx) { --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 @@ static void darwin_exit (struct libusb_context *ctx) { 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 3a1894cf..5b579939 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -100,8 +100,6 @@ static int init_count = 0; 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 @@ static int op_init(struct libusb_context *ctx) } #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 @@ static int op_init(struct libusb_context *ctx) } else { usbi_err(ctx, "error starting hotplug event monitor"); } - usbi_mutex_static_unlock(&linux_hotplug_startstop_lock); return r; } @@ -437,13 +433,11 @@ static void op_exit(struct libusb_context *ctx) } #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 6e69317a..72499eec 100644 --- a/libusb/os/windows_common.c +++ b/libusb/os/windows_common.c @@ -477,26 +477,9 @@ static unsigned __stdcall windows_iocp_thread(void *arg) 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_exit: // Holds semaphore here --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 @@ static void windows_exit(struct libusb_context *ctx) 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 56ffd75e..03212dc2 100644 --- a/msvc/libusb_dll_2013.vcxproj +++ b/msvc/libusb_dll_2013.vcxproj @@ -83,7 +83,6 @@ - diff --git a/msvc/libusb_dll_2013.vcxproj.filters b/msvc/libusb_dll_2013.vcxproj.filters index 8da28e35..c8643f2b 100644 --- a/msvc/libusb_dll_2013.vcxproj.filters +++ b/msvc/libusb_dll_2013.vcxproj.filters @@ -21,9 +21,6 @@ Header Files - - Header Files - Header Files diff --git a/msvc/libusb_dll_2015.vcxproj b/msvc/libusb_dll_2015.vcxproj index d2c850d0..f24d94b0 100644 --- a/msvc/libusb_dll_2015.vcxproj +++ b/msvc/libusb_dll_2015.vcxproj @@ -84,7 +84,6 @@ - diff --git a/msvc/libusb_dll_2015.vcxproj.filters b/msvc/libusb_dll_2015.vcxproj.filters index 8da28e35..c8643f2b 100644 --- a/msvc/libusb_dll_2015.vcxproj.filters +++ b/msvc/libusb_dll_2015.vcxproj.filters @@ -21,9 +21,6 @@ Header Files - - Header Files - Header Files diff --git a/msvc/libusb_dll_2017.vcxproj b/msvc/libusb_dll_2017.vcxproj index 598159d0..2ff2f948 100644 --- a/msvc/libusb_dll_2017.vcxproj +++ b/msvc/libusb_dll_2017.vcxproj @@ -103,7 +103,6 @@ - diff --git a/msvc/libusb_dll_2017.vcxproj.filters b/msvc/libusb_dll_2017.vcxproj.filters index 8da28e35..c8643f2b 100644 --- a/msvc/libusb_dll_2017.vcxproj.filters +++ b/msvc/libusb_dll_2017.vcxproj.filters @@ -21,9 +21,6 @@ Header Files - - Header Files - Header Files diff --git a/msvc/libusb_dll_2019.vcxproj b/msvc/libusb_dll_2019.vcxproj index dbd87176..266166e7 100644 --- a/msvc/libusb_dll_2019.vcxproj +++ b/msvc/libusb_dll_2019.vcxproj @@ -103,7 +103,6 @@ - diff --git a/msvc/libusb_dll_2019.vcxproj.filters b/msvc/libusb_dll_2019.vcxproj.filters index 8da28e35..c8643f2b 100644 --- a/msvc/libusb_dll_2019.vcxproj.filters +++ b/msvc/libusb_dll_2019.vcxproj.filters @@ -21,9 +21,6 @@ Header Files - - Header Files - Header Files diff --git a/msvc/libusb_static_2013.vcxproj b/msvc/libusb_static_2013.vcxproj index 1b287e59..94ba5975 100644 --- a/msvc/libusb_static_2013.vcxproj +++ b/msvc/libusb_static_2013.vcxproj @@ -79,7 +79,6 @@ - diff --git a/msvc/libusb_static_2013.vcxproj.filters b/msvc/libusb_static_2013.vcxproj.filters index 2994ca10..a3294dad 100644 --- a/msvc/libusb_static_2013.vcxproj.filters +++ b/msvc/libusb_static_2013.vcxproj.filters @@ -17,9 +17,6 @@ Header Files - - Header Files - Header Files diff --git a/msvc/libusb_static_2015.vcxproj b/msvc/libusb_static_2015.vcxproj index 9fa30dab..f9515232 100644 --- a/msvc/libusb_static_2015.vcxproj +++ b/msvc/libusb_static_2015.vcxproj @@ -80,7 +80,6 @@ - diff --git a/msvc/libusb_static_2015.vcxproj.filters b/msvc/libusb_static_2015.vcxproj.filters index 2994ca10..a3294dad 100644 --- a/msvc/libusb_static_2015.vcxproj.filters +++ b/msvc/libusb_static_2015.vcxproj.filters @@ -17,9 +17,6 @@ Header Files - - Header Files - Header Files diff --git a/msvc/libusb_static_2017.vcxproj b/msvc/libusb_static_2017.vcxproj index 62076e0a..857ee3f4 100644 --- a/msvc/libusb_static_2017.vcxproj +++ b/msvc/libusb_static_2017.vcxproj @@ -99,7 +99,6 @@ - diff --git a/msvc/libusb_static_2017.vcxproj.filters b/msvc/libusb_static_2017.vcxproj.filters index 2994ca10..a3294dad 100644 --- a/msvc/libusb_static_2017.vcxproj.filters +++ b/msvc/libusb_static_2017.vcxproj.filters @@ -17,9 +17,6 @@ Header Files - - Header Files - Header Files diff --git a/msvc/libusb_static_2019.vcxproj b/msvc/libusb_static_2019.vcxproj index 60ad642c..036ce956 100644 --- a/msvc/libusb_static_2019.vcxproj +++ b/msvc/libusb_static_2019.vcxproj @@ -99,7 +99,6 @@ - diff --git a/msvc/libusb_static_2019.vcxproj.filters b/msvc/libusb_static_2019.vcxproj.filters index 2994ca10..a3294dad 100644 --- a/msvc/libusb_static_2019.vcxproj.filters +++ b/msvc/libusb_static_2019.vcxproj.filters @@ -17,9 +17,6 @@ Header Files - - Header Files - Header Files