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>
This commit is contained in:
Chris Dickens 2021-01-20 11:18:35 -08:00 committed by Nathan Hjelm
parent a2b81aeff1
commit 32a2206942
28 changed files with 339 additions and 457 deletions

View file

@ -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 */,

View file

@ -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))

View file

@ -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

View file

@ -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

View file

@ -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 @@ 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(&timestamp_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(&timestamp_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

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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) {

View file

@ -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)

View file

@ -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)

View file

@ -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" />

View file

@ -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>

View file

@ -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" />

View file

@ -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>

View file

@ -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" />

View file

@ -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>

View file

@ -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" />

View file

@ -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>

View file

@ -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" />

View file

@ -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>

View file

@ -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" />

View file

@ -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>

View file

@ -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" />

View file

@ -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>

View file

@ -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" />

View file

@ -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>