From 1df713d622ab4f0b03aad72d903ac7beb8fb3b90 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Tue, 24 Jun 2008 23:01:51 -0500 Subject: Introduce contexts to the API Suggested by David Zeuthen. This allows multiple libraries in the same process to independently use libusb without interfering. --- libusb/core.c | 179 ++++++++++++++++++-------- libusb/descriptor.c | 50 ++++---- libusb/io.c | 324 +++++++++++++++++++++++++----------------------- libusb/libusb.h | 61 ++++++--- libusb/libusbi.h | 88 ++++++++++--- libusb/os/linux_usbfs.c | 256 ++++++++++++++++++++++---------------- libusb/sync.c | 14 ++- 7 files changed, 591 insertions(+), 381 deletions(-) (limited to 'libusb') diff --git a/libusb/core.c b/libusb/core.c index 20aed50..a6c70d4 100644 --- a/libusb/core.c +++ b/libusb/core.c @@ -31,21 +31,14 @@ #include "libusb.h" #include "libusbi.h" -static int usbi_debug = 0; -static int debug_fixed = 0; - #ifdef OS_LINUX const struct usbi_os_backend * const usbi_backend = &linux_usbfs_backend; #else #error "Unsupported OS" #endif -static struct list_head usb_devs; -static pthread_mutex_t usb_devs_lock = PTHREAD_MUTEX_INITIALIZER; - -/* A list of open handles. Backends are free to traverse this if required. */ -struct list_head usbi_open_devs; -pthread_mutex_t usbi_open_devs_lock = PTHREAD_MUTEX_INITIALIZER; +struct libusb_context *usbi_default_context = NULL; +static pthread_mutex_t default_context_lock = PTHREAD_MUTEX_INITIALIZER; /** * \mainpage libusb-1.0 API Reference @@ -233,6 +226,37 @@ if (cfg != desired) * or driver is able to select another configuration. */ +/** + * \page contexts Contexts + * + * It is possible that libusb may be used simultaneously from two independent + * libraries linked into the same executable. For example, if your application + * has a plugin-like system which allows the user to dynamically load a range + * of modules into your program, it is feasible that two independently + * developed modules may both use libusb. + * + * libusb is written to allow for these multiple user scenarios. The two + * "instances" of libusb will not interfere: libusb_set_debug() calls + * from one user will not affect the same settings for other users, other + * users can continue using libusb after one of them calls libusb_exit(), etc. + * + * This is made possible through libusb's context concept. When you + * call libusb_init(), you are (optionally) given a context. You can then pass + * this context pointer back into future libusb functions. + * + * In order to keep things simple for more simplistic applications, it is + * legal to pass NULL to all functions requiring a context pointer (as long as + * you're sure no other code will attempt to use libusb from the same process). + * When you pass NULL, the default context will be used. The default context + * is created the first time a process calls libusb_init() when no other + * context is alive. Contexts are destroyed during libusb_exit(). + * + * You may be wondering why only a subset of libusb functions require a + * context pointer in their function definition. Internally, libusb stores + * context pointers in other objects (e.g. libusb_device instances) and hence + * can infer the context from those objects. + */ + /** * @defgroup lib Library initialization/deinitialization * This page details how to initialize and deinitialize libusb. Initialization @@ -258,7 +282,7 @@ if (cfg != desired) // discover devices libusb_device **list; libusb_device *found = NULL; -size_t cnt = libusb_get_device_list(&list); +size_t cnt = libusb_get_device_list(NULL, &list); size_t i = 0; int err = 0; if (cnt < 0) @@ -413,7 +437,8 @@ static void discovered_devs_free(struct discovered_devs *discdevs) /* Allocate a new device with a specific session ID. The returned device has * a reference count of 1. */ -struct libusb_device *usbi_alloc_device(unsigned long session_id) +struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, + unsigned long session_id) { size_t priv_size = usbi_backend->device_priv_size; struct libusb_device *dev = malloc(sizeof(*dev) + priv_size); @@ -426,13 +451,14 @@ struct libusb_device *usbi_alloc_device(unsigned long session_id) if (r) return NULL; + dev->ctx = ctx; dev->refcnt = 1; dev->session_data = session_id; memset(&dev->os_priv, 0, priv_size); - pthread_mutex_lock(&usb_devs_lock); - list_add(&dev->list, &usb_devs); - pthread_mutex_unlock(&usb_devs_lock); + pthread_mutex_lock(&ctx->usb_devs_lock); + list_add(&dev->list, &ctx->usb_devs); + pthread_mutex_unlock(&ctx->usb_devs_lock); return dev; } @@ -452,7 +478,7 @@ int usbi_sanitize_device(struct libusb_device *dev) num_configurations = raw_desc[DEVICE_DESC_LENGTH - 1]; if (num_configurations > USB_MAXCONFIG) { - usbi_err("too many configurations"); + usbi_err(DEVICE_CTX(dev), "too many configurations"); return LIBUSB_ERROR_IO; } else if (num_configurations < 1) { usbi_dbg("no configurations?"); @@ -466,18 +492,19 @@ int usbi_sanitize_device(struct libusb_device *dev) /* Examine libusb's internal list of known devices, looking for one with * a specific session ID. Returns the matching device if it was found, and * NULL otherwise. */ -struct libusb_device *usbi_get_device_by_session_id(unsigned long session_id) +struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx, + unsigned long session_id) { struct libusb_device *dev; struct libusb_device *ret = NULL; - pthread_mutex_lock(&usb_devs_lock); - list_for_each_entry(dev, &usb_devs, list) + pthread_mutex_lock(&ctx->usb_devs_lock); + list_for_each_entry(dev, &ctx->usb_devs, list) if (dev->session_data == session_id) { ret = dev; break; } - pthread_mutex_unlock(&usb_devs_lock); + pthread_mutex_unlock(&ctx->usb_devs_lock); return ret; } @@ -496,24 +523,27 @@ struct libusb_device *usbi_get_device_by_session_id(unsigned long session_id) * the resultant list. The list is actually one element larger, as it is * NULL-terminated. * + * \param ctx the context to operate on, or NULL for the default context * \param list output location for a list of devices. Must be later freed with * libusb_free_device_list(). * \returns the number of devices in the outputted list, or LIBUSB_ERROR_NO_MEM * on memory allocation failure. */ -API_EXPORTED ssize_t libusb_get_device_list(libusb_device ***list) +API_EXPORTED ssize_t libusb_get_device_list(libusb_context *ctx, + libusb_device ***list) { struct discovered_devs *discdevs = discovered_devs_alloc(); struct libusb_device **ret; int r = 0; size_t i; ssize_t len; + USBI_GET_CONTEXT(ctx); usbi_dbg(""); if (!discdevs) return LIBUSB_ERROR_NO_MEM; - r = usbi_backend->get_device_list(&discdevs); + r = usbi_backend->get_device_list(ctx, &discdevs); if (r < 0) { len = r; goto out; @@ -602,7 +632,8 @@ API_EXPORTED int libusb_get_max_packet_size(libusb_device *dev, r = libusb_get_active_config_descriptor(dev, &config); if (r < 0) { - usbi_err("could not retrieve active config descriptor"); + usbi_err(DEVICE_CTX(dev), + "could not retrieve active config descriptor"); return LIBUSB_ERROR_OTHER; } @@ -668,9 +699,9 @@ API_EXPORTED void libusb_unref_device(libusb_device *dev) if (usbi_backend->destroy_device) usbi_backend->destroy_device(dev); - pthread_mutex_lock(&usb_devs_lock); + pthread_mutex_lock(&dev->ctx->usb_devs_lock); list_del(&dev->list); - pthread_mutex_unlock(&usb_devs_lock); + pthread_mutex_unlock(&dev->ctx->usb_devs_lock); free(dev); } @@ -721,9 +752,9 @@ API_EXPORTED int libusb_open(libusb_device *dev, libusb_device_handle **handle) return r; } - pthread_mutex_lock(&usbi_open_devs_lock); - list_add(&_handle->list, &usbi_open_devs); - pthread_mutex_unlock(&usbi_open_devs_lock); + pthread_mutex_lock(&dev->ctx->open_devs_lock); + list_add(&_handle->list, &dev->ctx->open_devs); + pthread_mutex_unlock(&dev->ctx->open_devs_lock); *handle = _handle; return 0; } @@ -739,12 +770,13 @@ API_EXPORTED int libusb_open(libusb_device *dev, libusb_device_handle **handle) * applications: if multiple devices have the same IDs it will only * give you the first one, etc. * + * \param ctx the context to operate on, or NULL for the default context * \param vendor_id the idVendor value to search for * \param product_id the idProduct value to search for * \returns a handle for the first found device, or NULL on error or if the * device could not be found. */ API_EXPORTED libusb_device_handle *libusb_open_device_with_vid_pid( - uint16_t vendor_id, uint16_t product_id) + libusb_context *ctx, uint16_t vendor_id, uint16_t product_id) { struct libusb_device **devs; struct libusb_device *found = NULL; @@ -753,7 +785,7 @@ API_EXPORTED libusb_device_handle *libusb_open_device_with_vid_pid( size_t i = 0; int r; - if (libusb_get_device_list(&devs) < 0) + if (libusb_get_device_list(ctx, &devs) < 0) return NULL; while ((dev = devs[i++]) != NULL) { @@ -801,9 +833,9 @@ API_EXPORTED void libusb_close(libusb_device_handle *dev_handle) return; usbi_dbg(""); - pthread_mutex_lock(&usbi_open_devs_lock); + pthread_mutex_lock(&HANDLE_CTX(dev_handle)->open_devs_lock); list_del(&dev_handle->list); - pthread_mutex_unlock(&usbi_open_devs_lock); + pthread_mutex_unlock(&HANDLE_CTX(dev_handle)->open_devs_lock); do_close(dev_handle); free(dev_handle); @@ -856,7 +888,7 @@ API_EXPORTED int libusb_get_configuration(libusb_device_handle *dev, r = libusb_control_transfer(dev, LIBUSB_ENDPOINT_IN, LIBUSB_REQUEST_GET_CONFIGURATION, 0, 0, &tmp, 1, 1000); if (r == 0) { - usbi_err("zero bytes returned in ctrl transfer?"); + usbi_err(HANDLE_CTX(dev), "zero bytes returned in ctrl transfer?"); r = LIBUSB_ERROR_IO; } else if (r == 1) { r = 0; @@ -1026,7 +1058,8 @@ out: API_EXPORTED int libusb_set_interface_alt_setting(libusb_device_handle *dev, int interface_number, int alternate_setting) { - usbi_dbg("interface %d altsetting %d", interface_number, alternate_setting); + usbi_dbg("interface %d altsetting %d", + interface_number, alternate_setting); if (interface_number >= sizeof(dev->claimed_interfaces) * 8) return LIBUSB_ERROR_INVALID_PARAM; @@ -1161,80 +1194,116 @@ API_EXPORTED int libusb_detach_kernel_driver(libusb_device_handle *dev, * If libusb was compiled with verbose debug message logging, this function * does nothing: you'll always get messages from all levels. * + * \param ctx the context to operate on, or NULL for the default context * \param level debug level to set */ -API_EXPORTED void libusb_set_debug(int level) +API_EXPORTED void libusb_set_debug(libusb_context *ctx, int level) { - if (!debug_fixed) - usbi_debug = level; + USBI_GET_CONTEXT(ctx); + if (!ctx->debug_fixed) + ctx->debug = level; } /** \ingroup lib * Initialize libusb. This function must be called before calling any other * libusb function. + * \param context Optional output location for context pointer. + * Only valid on return code 0. * \returns 0 on success, or a LIBUSB_ERROR code on failure */ -API_EXPORTED int libusb_init(void) +API_EXPORTED int libusb_init(libusb_context **context) { char *dbg = getenv("LIBUSB_DEBUG"); + struct libusb_context *ctx = malloc(sizeof(*ctx)); + + if (!ctx) + return LIBUSB_ERROR_NO_MEM; + memset(ctx, 0, sizeof(*ctx)); + if (dbg) { - usbi_debug = atoi(dbg); - if (usbi_debug) - debug_fixed = 1; + ctx->debug = atoi(dbg); + if (ctx->debug) + ctx->debug_fixed = 1; } usbi_dbg(""); if (usbi_backend->init) { - int r = usbi_backend->init(); - if (r) + int r = usbi_backend->init(ctx); + if (r) { + free(ctx); return r; + } + } + + pthread_mutex_init(&ctx->usb_devs_lock, NULL); + pthread_mutex_init(&ctx->open_devs_lock, NULL); + list_init(&ctx->usb_devs); + list_init(&ctx->open_devs); + usbi_io_init(ctx); + + pthread_mutex_lock(&default_context_lock); + if (!usbi_default_context) { + usbi_dbg("created default context"); + usbi_default_context = ctx; } + pthread_mutex_unlock(&default_context_lock); - list_init(&usb_devs); - list_init(&usbi_open_devs); - usbi_io_init(); + if (context) + *context = ctx; return 0; } /** \ingroup lib * Deinitialize libusb. Should be called after closing all open devices and * before your application terminates. + * \param ctx the context to deinitialize, or NULL for the default context */ -API_EXPORTED void libusb_exit(void) +API_EXPORTED void libusb_exit(struct libusb_context *ctx) { + USBI_GET_CONTEXT(ctx); usbi_dbg(""); - pthread_mutex_lock(&usbi_open_devs_lock); - if (!list_empty(&usbi_open_devs)) { + pthread_mutex_lock(&ctx->open_devs_lock); + if (!list_empty(&ctx->open_devs)) { struct libusb_device_handle *devh; struct libusb_device_handle *tmp; usbi_dbg("naughty app left some devices open!"); - list_for_each_entry_safe(devh, tmp, &usbi_open_devs, list) { + list_for_each_entry_safe(devh, tmp, &ctx->open_devs, list) { list_del(&devh->list); do_close(devh); free(devh); } } - pthread_mutex_unlock(&usbi_open_devs_lock); + pthread_mutex_unlock(&ctx->open_devs_lock); if (usbi_backend->exit) usbi_backend->exit(); + + pthread_mutex_lock(&default_context_lock); + if (ctx == usbi_default_context) { + usbi_dbg("freeing default context"); + usbi_default_context = NULL; + } + pthread_mutex_unlock(&default_context_lock); + + free(ctx); } -void usbi_log(enum usbi_log_level level, const char *function, - const char *format, ...) +void usbi_log(struct libusb_context *ctx, enum usbi_log_level level, + const char *function, const char *format, ...) { va_list args; FILE *stream = stdout; const char *prefix; #ifndef ENABLE_DEBUG_LOGGING - if (!usbi_debug) + USBI_GET_CONTEXT(ctx); + if (!ctx->debug) return; - if (level == LOG_LEVEL_WARNING && usbi_debug < 2) + if (level == LOG_LEVEL_WARNING && ctx->debug < 2) return; - if (level == LOG_LEVEL_INFO && usbi_debug < 3) + if (level == LOG_LEVEL_INFO && ctx->debug < 3) return; #endif diff --git a/libusb/descriptor.c b/libusb/descriptor.c index 37dcc64..2fed1e9 100644 --- a/libusb/descriptor.c +++ b/libusb/descriptor.c @@ -74,8 +74,9 @@ static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint) free((unsigned char *) endpoint->extra); } -static int parse_endpoint(struct libusb_endpoint_descriptor *endpoint, - unsigned char *buffer, int size, int host_endian) +static int parse_endpoint(struct libusb_context *ctx, + struct libusb_endpoint_descriptor *endpoint, unsigned char *buffer, + int size, int host_endian) { struct usb_descriptor_header header; unsigned char *extra; @@ -88,12 +89,12 @@ static int parse_endpoint(struct libusb_endpoint_descriptor *endpoint, /* Everything should be fine being passed into here, but we sanity */ /* check JIC */ if (header.bLength > size) { - usbi_err("ran out of descriptors parsing"); + usbi_err(ctx, "ran out of descriptors parsing"); return -1; } if (header.bDescriptorType != LIBUSB_DT_ENDPOINT) { - usbi_err("unexpected descriptor %x (expected %x)", + usbi_err(ctx, "unexpected descriptor %x (expected %x)", header.bDescriptorType, LIBUSB_DT_ENDPOINT); return parsed; } @@ -114,7 +115,7 @@ static int parse_endpoint(struct libusb_endpoint_descriptor *endpoint, usbi_parse_descriptor(buffer, "bb", &header, 0); if (header.bLength < 2) { - usbi_err("invalid descriptor length %d", header.bLength); + usbi_err(ctx, "invalid descriptor length %d", header.bLength); return -1; } @@ -177,8 +178,9 @@ static void clear_interface(struct libusb_interface *interface) } -static int parse_interface(struct libusb_interface *interface, - unsigned char *buffer, int size, int host_endian) +static int parse_interface(libusb_context *ctx, + struct libusb_interface *interface, unsigned char *buffer, int size, + int host_endian) { int i; int len; @@ -221,7 +223,8 @@ static int parse_interface(struct libusb_interface *interface, while (size >= DESC_HEADER_LENGTH) { usbi_parse_descriptor(buffer, "bb", &header, 0); if (header.bLength < 2) { - usbi_err("invalid descriptor of length %d", header.bLength); + usbi_err(ctx, "invalid descriptor of length %d", + header.bLength); r = LIBUSB_ERROR_IO; goto err; } @@ -259,7 +262,7 @@ static int parse_interface(struct libusb_interface *interface, return parsed; if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { - usbi_err("too many endpoints (%d)", ifp->bNumEndpoints); + usbi_err(ctx, "too many endpoints (%d)", ifp->bNumEndpoints); r = LIBUSB_ERROR_IO; goto err; } @@ -279,12 +282,13 @@ static int parse_interface(struct libusb_interface *interface, usbi_parse_descriptor(buffer, "bb", &header, 0); if (header.bLength > size) { - usbi_err("ran out of descriptors parsing"); + usbi_err(ctx, "ran out of descriptors parsing"); r = LIBUSB_ERROR_IO; goto err; } - r = parse_endpoint(endpoint + i, buffer, size, host_endian); + r = parse_endpoint(ctx, endpoint + i, buffer, size, + host_endian); if (r < 0) goto err; @@ -321,8 +325,9 @@ static void clear_configuration(struct libusb_config_descriptor *config) free((void *) config->extra); } -static int parse_configuration(struct libusb_config_descriptor *config, - unsigned char *buffer, int host_endian) +static int parse_configuration(struct libusb_context *ctx, + struct libusb_config_descriptor *config, unsigned char *buffer, + int host_endian) { int i; int r; @@ -335,7 +340,7 @@ static int parse_configuration(struct libusb_config_descriptor *config, size = config->wTotalLength; if (config->bNumInterfaces > USB_MAXINTERFACES) { - usbi_err("too many interfaces (%d)", config->bNumInterfaces); + usbi_err(ctx, "too many interfaces (%d)", config->bNumInterfaces); return LIBUSB_ERROR_IO; } @@ -364,7 +369,8 @@ static int parse_configuration(struct libusb_config_descriptor *config, if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) { - usbi_err("invalid descriptor length of %d", header.bLength); + usbi_err(ctx, "invalid descriptor length of %d", + header.bLength); r = LIBUSB_ERROR_IO; goto err; } @@ -398,7 +404,7 @@ static int parse_configuration(struct libusb_config_descriptor *config, } } - r = parse_interface(interface + i, buffer, size, host_endian); + r = parse_interface(ctx, interface + i, buffer, size, host_endian); if (r < 0) goto err; @@ -488,12 +494,12 @@ API_EXPORTED int libusb_get_active_config_descriptor(libusb_device *dev, if (r < 0) goto err; - r = parse_configuration(_config, buf, host_endian); + r = parse_configuration(dev->ctx, _config, buf, host_endian); if (r < 0) { - usbi_err("parse_configuration failed with error %d", r); + usbi_err(dev->ctx, "parse_configuration failed with error %d", r); goto err; } else if (r > 0) { - usbi_warn("descriptor data still left"); + usbi_warn(dev->ctx, "descriptor data still left"); } *config = _config; @@ -556,12 +562,12 @@ API_EXPORTED int libusb_get_config_descriptor(libusb_device *dev, if (r < 0) goto err; - r = parse_configuration(_config, buf, host_endian); + r = parse_configuration(dev->ctx, _config, buf, host_endian); if (r < 0) { - usbi_err("parse_configuration failed with error %d", r); + usbi_err(dev->ctx, "parse_configuration failed with error %d", r); goto err; } else if (r > 0) { - usbi_warn("descriptor data still left"); + usbi_warn(dev->ctx, "descriptor data still left"); } *config = _config; diff --git a/libusb/io.c b/libusb/io.c index 5f3d617..f2de833 100644 --- a/libusb/io.c +++ b/libusb/io.c @@ -32,32 +32,6 @@ #include "libusbi.h" -/* 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 infinite timeout - * are always placed at the very end. */ -static struct list_head flying_transfers; -static pthread_mutex_t flying_transfers_lock = PTHREAD_MUTEX_INITIALIZER; - -/* list of poll fd's */ -static struct list_head pollfds; -static pthread_mutex_t pollfds_lock = PTHREAD_MUTEX_INITIALIZER; - -/* user callbacks for pollfd changes */ -static libusb_pollfd_added_cb fd_added_cb = NULL; -static libusb_pollfd_removed_cb fd_removed_cb = NULL; - -/* this lock ensures that only one thread is handling events at any one time */ -static pthread_mutex_t events_lock = PTHREAD_MUTEX_INITIALIZER; - -/* used to see if there is an active thread doing event handling */ -static int event_handler_active = 0; - -/* used to wait for event completion in threads other than the one that is - * event handling */ -static pthread_mutex_t event_waiters_lock = PTHREAD_MUTEX_INITIALIZER; -static pthread_cond_t event_waiters_cond = PTHREAD_COND_INITIALIZER; - /** * \page io Synchronous and asynchronous device I/O * @@ -575,7 +549,7 @@ if (r == 0 && actual_length == sizeof(data)) { // maybe fire off some initial async I/O while (user_has_not_requested_exit) - libusb_handle_events(); + libusb_handle_events(ctx); // clean up and exit \endcode @@ -606,15 +580,15 @@ while (user_has_not_requested_exit) \code // initialise libusb -libusb_get_pollfds() +libusb_get_pollfds(ctx) while (user has not requested application exit) { - libusb_get_next_timeout(); + libusb_get_next_timeout(ctx); select(on libusb file descriptors plus any other event sources of interest, using a timeout no larger than the value libusb just suggested) if (select() indicated activity on libusb file descriptors) - libusb_handle_events_timeout(0); + libusb_handle_events_timeout(ctx, 0); if (time has elapsed to or beyond the libusb timeout) - libusb_handle_events_timeout(0); + libusb_handle_events_timeout(ctx, 0); } // clean up and exit @@ -684,7 +658,7 @@ void myfunc() { while (!completed) { poll(libusb file descriptors, 120*1000); if (poll indicates activity) - libusb_handle_events_timeout(0); + libusb_handle_events_timeout(ctx, 0); } printf("completed!"); // other code here @@ -738,13 +712,13 @@ void myfunc() { * Although the events lock is a critical part of the solution, it is not * enough on it's own. You might wonder if the following is sufficient... \code - libusb_lock_events(); + libusb_lock_events(ctx); while (!completed) { poll(libusb file descriptors, 120*1000); if (poll indicates activity) - libusb_handle_events_timeout(0); + libusb_handle_events_timeout(ctx, 0); } - libusb_lock_events(); + libusb_lock_events(ctx); \endcode * ...and the answer is that it is not. This is because the transfer in the * code shown above may take a long time (say 30 seconds) to complete, and @@ -775,33 +749,33 @@ void myfunc() { * This looks like the following, as pseudo-code: \code retry: -if (libusb_try_lock_events() == 0) { +if (libusb_try_lock_events(ctx) == 0) { // we obtained the event lock: do our own event handling - libusb_lock_events(); + libusb_lock_events(ctx); while (!completed) { poll(libusb file descriptors, 120*1000); if (poll indicates activity) - libusb_handle_events_locked(0); + libusb_handle_events_locked(ctx, 0); } - libusb_unlock_events(); + libusb_unlock_events(ctx); } else { // another thread is doing event handling. wait for it to signal us that // an event has completed - libusb_lock_event_waiters(); + libusb_lock_event_waiters(ctx); while (!completed) { // now that we have the event waiters lock, double check that another // thread is still handling events for us. (it may have ceased handling // events in the time it took us to reach this point) - if (!libusb_event_handler_active()) { + if (!libusb_event_handler_active(ctx)) { // whoever was handling events is no longer doing so, try again - libusb_unlock_event_waiters(); + libusb_unlock_event_waiters(ctx); goto retry; } - libusb_wait_for_event(); + libusb_wait_for_event(ctx); } - libusb_unlock_event_waiters(); + libusb_unlock_event_waiters(ctx); } printf("completed!\n"); \endcode @@ -858,12 +832,15 @@ printf("completed!\n"); * fall back to the "event waiters" mechanism detailed above. */ -void usbi_io_init() +void usbi_io_init(struct libusb_context *ctx) { - list_init(&flying_transfers); - list_init(&pollfds); - fd_added_cb = NULL; - fd_removed_cb = NULL; + pthread_mutex_init(&ctx->flying_transfers_lock, NULL); + pthread_mutex_init(&ctx->pollfds_lock, NULL); + pthread_mutex_init(&ctx->events_lock, NULL); + pthread_mutex_init(&ctx->event_waiters_lock, NULL); + pthread_cond_init(&ctx->event_waiters_cond, NULL); + list_init(&ctx->flying_transfers); + list_init(&ctx->pollfds); } static int calculate_timeout(struct usbi_transfer *transfer) @@ -878,7 +855,8 @@ static int calculate_timeout(struct usbi_transfer *transfer) r = clock_gettime(CLOCK_MONOTONIC, ¤t_time); if (r < 0) { - usbi_err("failed to read monotonic clock, errno=%d", errno); + usbi_err(ITRANSFER_CTX(transfer), + "failed to read monotonic clock, errno=%d", errno); return r; } @@ -898,23 +876,24 @@ static void add_to_flying_list(struct usbi_transfer *transfer) { struct usbi_transfer *cur; struct timeval *timeout = &transfer->timeout; + struct libusb_context *ctx = ITRANSFER_CTX(transfer); - pthread_mutex_lock(&flying_transfers_lock); + pthread_mutex_lock(&ctx->flying_transfers_lock); /* if we have no other flying transfers, start the list with this one */ - if (list_empty(&flying_transfers)) { - list_add(&transfer->list, &flying_transfers); + if (list_empty(&ctx->flying_transfers)) { + list_add(&transfer->list, &ctx->flying_transfers); goto out; } /* if we have infinite timeout, append to end of list */ if (!timerisset(timeout)) { - list_add_tail(&transfer->list, &flying_transfers); + list_add_tail(&transfer->list, &ctx->flying_transfers); goto out; } /* otherwise, find appropriate place in list */ - list_for_each_entry(cur, &flying_transfers, list) { + list_for_each_entry(cur, &ctx->flying_transfers, list) { /* find first timeout that occurs after the transfer in question */ struct timeval *cur_tv = &cur->timeout; @@ -927,9 +906,9 @@ static void add_to_flying_list(struct usbi_transfer *transfer) } /* otherwise we need to be inserted at the end */ - list_add_tail(&transfer->list, &flying_transfers); + list_add_tail(&transfer->list, &ctx->flying_transfers); out: - pthread_mutex_unlock(&flying_transfers_lock); + pthread_mutex_unlock(&ctx->flying_transfers_lock); } /** \ingroup asyncio @@ -1025,9 +1004,9 @@ API_EXPORTED int libusb_submit_transfer(struct libusb_transfer *transfer) add_to_flying_list(itransfer); r = usbi_backend->submit_transfer(itransfer); if (r) { - pthread_mutex_lock(&flying_transfers_lock); + pthread_mutex_lock(&TRANSFER_CTX(transfer)->flying_transfers_lock); list_del(&itransfer->list); - pthread_mutex_unlock(&flying_transfers_lock); + pthread_mutex_unlock(&TRANSFER_CTX(transfer)->flying_transfers_lock); } return r; @@ -1056,7 +1035,8 @@ API_EXPORTED int libusb_cancel_transfer(struct libusb_transfer *transfer) usbi_dbg(""); r = usbi_backend->cancel_transfer(itransfer); if (r < 0) - usbi_err("cancel transfer failed error %d", r); + usbi_err(TRANSFER_CTX(transfer), + "cancel transfer failed error %d", r); return r; } @@ -1070,11 +1050,12 @@ void usbi_handle_transfer_completion(struct usbi_transfer *itransfer, { struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer); + struct libusb_context *ctx = TRANSFER_CTX(transfer); uint8_t flags; - pthread_mutex_lock(&flying_transfers_lock); + pthread_mutex_lock(&ctx->flying_transfers_lock); list_del(&itransfer->list); - pthread_mutex_unlock(&flying_transfers_lock); + pthread_mutex_unlock(&ctx->flying_transfers_lock); if (status == LIBUSB_TRANSFER_COMPLETED && transfer->flags & LIBUSB_TRANSFER_SHORT_NOT_OK) { @@ -1096,9 +1077,9 @@ void usbi_handle_transfer_completion(struct usbi_transfer *itransfer, * this point. */ if (flags & LIBUSB_TRANSFER_FREE_TRANSFER) libusb_free_transfer(transfer); - pthread_mutex_lock(&event_waiters_lock); - pthread_cond_broadcast(&event_waiters_cond); - pthread_mutex_unlock(&event_waiters_lock); + pthread_mutex_lock(&ctx->event_waiters_lock); + pthread_cond_broadcast(&ctx->event_waiters_cond); + pthread_mutex_unlock(&ctx->event_waiters_lock); } /* Similar to usbi_handle_transfer_completion() but exclusively for transfers @@ -1132,17 +1113,21 @@ void usbi_handle_transfer_cancellation(struct usbi_transfer *transfer) * If you are no longer handling events, you must call libusb_unlock_events() * as soon as possible. * + * \param ctx the context to operate on, or NULL for the default context * \returns 0 if the lock was obtained successfully * \returns 1 if the lock was not obtained (i.e. another thread holds the lock) * \see \ref mtasync */ -API_EXPORTED int libusb_try_lock_events(void) +API_EXPORTED int libusb_try_lock_events(libusb_context *ctx) { - int r = pthread_mutex_trylock(&events_lock); + int r; + USBI_GET_CONTEXT(ctx); + + r = pthread_mutex_trylock(&ctx->events_lock); if (r) return 1; - event_handler_active = 1; + ctx->event_handler_active = 1; return 0; } @@ -1161,12 +1146,14 @@ API_EXPORTED int libusb_try_lock_events(void) * If you are no longer handling events, you must call libusb_unlock_events() * as soon as possible. * + * \param ctx the context to operate on, or NULL for the default context * \see \ref mtasync */ -API_EXPORTED void libusb_lock_events(void) +API_EXPORTED void libusb_lock_events(libusb_context *ctx) { - pthread_mutex_lock(&events_lock); - event_handler_active = 1; + USBI_GET_CONTEXT(ctx); + pthread_mutex_lock(&ctx->events_lock); + ctx->event_handler_active = 1; } /** \ingroup poll @@ -1174,29 +1161,33 @@ API_EXPORTED void libusb_lock_events(void) * libusb_lock_events(). Releasing this lock will wake up any threads blocked * on libusb_wait_for_event(). * + * \param ctx the context to operate on, or NULL for the default context * \see \ref mtasync */ -API_EXPORTED void libusb_unlock_events(void) +API_EXPORTED void libusb_unlock_events(libusb_context *ctx) { - event_handler_active = 0; - pthread_mutex_unlock(&events_lock); + USBI_GET_CONTEXT(ctx); + ctx->event_handler_active = 0; + pthread_mutex_unlock(&ctx->events_lock); - pthread_mutex_lock(&event_waiters_lock); - pthread_cond_broadcast(&event_waiters_cond); - pthread_mutex_unlock(&event_waiters_lock); + pthread_mutex_lock(&ctx->event_waiters_lock); + pthread_cond_broadcast(&ctx->event_waiters_cond); + pthread_mutex_unlock(&ctx->event_waiters_lock); } /** \ingroup poll * Determine if an active thread is handling events (i.e. if anyone is holding * the event handling lock). * + * \param ctx the context to operate on, or NULL for the default context * \returns 1 if a thread is handling events * \returns 0 if there are no threads currently handling events * \see \ref mtasync */ -API_EXPORTED int libusb_event_handler_active(void) +API_EXPORTED int libusb_event_handler_active(libusb_context *ctx) { - return event_handler_active; + USBI_GET_CONTEXT(ctx); + return ctx->event_handler_active; } /** \ingroup poll @@ -1215,20 +1206,24 @@ API_EXPORTED int libusb_event_handler_active(void) * libusb_handle_events()) then you do not need to be concerned with this * locking. * + * \param ctx the context to operate on, or NULL for the default context * \see \ref mtasync */ -API_EXPORTED void libusb_lock_event_waiters(void) +API_EXPORTED void libusb_lock_event_waiters(libusb_context *ctx) { - pthread_mutex_lock(&event_waiters_lock); + USBI_GET_CONTEXT(ctx); + pthread_mutex_lock(&ctx->event_waiters_lock); } /** \ingroup poll * Release the event waiters lock. + * \param ctx the context to operate on, or NULL for the default context * \see \ref mtasync */ -API_EXPORTED void libusb_unlock_event_waiters(void) +API_EXPORTED void libusb_unlock_event_waiters(libusb_context *ctx) { - pthread_mutex_unlock(&event_waiters_lock); + USBI_GET_CONTEXT(ctx); + pthread_mutex_unlock(&ctx->event_waiters_lock); } /** \ingroup poll @@ -1249,25 +1244,27 @@ API_EXPORTED void libusb_unlock_event_waiters(void) * This function releases the event waiters lock before putting your thread * to sleep, and reacquires the lock as it is being woken up. * + * \param ctx the context to operate on, or NULL for the default context * \param tv maximum timeout for this blocking function. A NULL value * indicates unlimited timeout. * \returns 0 after a transfer completes or another thread stops event handling * \returns 1 if the timeout expired * \see \ref mtasync */ -API_EXPORTED int libusb_wait_for_event(struct timeval *tv) +API_EXPORTED int libusb_wait_for_event(libusb_context *ctx, struct timeval *tv) { struct timespec timeout; int r; + USBI_GET_CONTEXT(ctx); if (tv == NULL) { - pthread_cond_wait(&event_waiters_cond, &event_waiters_lock); + pthread_cond_wait(&ctx->event_waiters_cond, &ctx->event_waiters_lock); return 0; } r = clock_gettime(CLOCK_REALTIME, &timeout); if (r < 0) { - usbi_err("failed to read realtime clock, error %d", errno); + usbi_err(ctx, "failed to read realtime clock, error %d", errno); return LIBUSB_ERROR_OTHER; } @@ -1278,8 +1275,8 @@ API_EXPORTED int libusb_wait_for_event(struct timeval *tv) timeout.tv_sec++; } - r = pthread_cond_timedwait(&event_waiters_cond, &event_waiters_lock, - &timeout); + r = pthread_cond_timedwait(&ctx->event_waiters_cond, + &ctx->event_waiters_lock, &timeout); return (r == ETIMEDOUT); } @@ -1292,18 +1289,20 @@ static void handle_timeout(struct usbi_transfer *itransfer) itransfer->flags |= USBI_TRANSFER_TIMED_OUT; r = libusb_cancel_transfer(transfer); if (r < 0) - usbi_warn("async cancel failed %d errno=%d", r, errno); + usbi_warn(TRANSFER_CTX(transfer), + "async cancel failed %d errno=%d", r, errno); } -static int handle_timeouts(void) +static int handle_timeouts(struct libusb_context *ctx) { struct timespec systime_ts; struct timeval systime; struct usbi_transfer *transfer; int r = 0; - pthread_mutex_lock(&flying_transfers_lock); - if (list_empty(&flying_transfers)) + USBI_GET_CONTEXT(ctx); + pthread_mutex_lock(&ctx->flying_transfers_lock); + if (list_empty(&ctx->flying_transfers)) goto out; /* get current time */ @@ -1315,7 +1314,7 @@ static int handle_timeouts(void) /* iterate through flying transfers list, finding all transfers that * have expired timeouts */ - list_for_each_entry(transfer, &flying_transfers, list) { + list_for_each_entry(transfer, &ctx->flying_transfers, list) { struct timeval *cur_tv = &transfer->timeout; /* if we've reached transfers of infinite timeout, we're all done */ @@ -1337,13 +1336,13 @@ static int handle_timeouts(void) } out: - pthread_mutex_unlock(&flying_transfers_lock); + pthread_mutex_unlock(&ctx->flying_transfers_lock); return r; } /* do the actual event handling. assumes that no other thread is concurrently * doing the same thing. */ -static int handle_events(struct timeval *tv) +static int handle_events(struct libusb_context *ctx, struct timeval *tv) { int r; struct usbi_pollfd *ipollfd; @@ -1352,8 +1351,8 @@ static int handle_events(struct timeval *tv) int i = -1; int timeout_ms; - pthread_mutex_lock(&pollfds_lock); - list_for_each_entry(ipollfd, &pollfds, list) + pthread_mutex_lock(&ctx->pollfds_lock); + list_for_each_entry(ipollfd, &ctx->pollfds, list) nfds++; /* TODO: malloc when number of fd's changes, not on every poll */ @@ -1361,7 +1360,7 @@ static int handle_events(struct timeval *tv) if (!fds) return LIBUSB_ERROR_NO_MEM; - list_for_each_entry(ipollfd, &pollfds, list) { + list_for_each_entry(ipollfd, &ctx->pollfds, list) { struct libusb_pollfd *pollfd = &ipollfd->pollfd; int fd = pollfd->fd; i++; @@ -1369,7 +1368,7 @@ static int handle_events(struct timeval *tv) fds[i].events = pollfd->events; fds[i].revents = 0; } - pthread_mutex_unlock(&pollfds_lock); + pthread_mutex_unlock(&ctx->pollfds_lock); timeout_ms = (tv->tv_sec * 1000) + (tv->tv_usec / 1000); @@ -1382,19 +1381,19 @@ static int handle_events(struct timeval *tv) usbi_dbg("poll() returned %d", r); if (r == 0) { free(fds); - return handle_timeouts(); + return handle_timeouts(ctx); } else if (r == -1 && errno == EINTR) { free(fds); return LIBUSB_ERROR_INTERRUPTED; } else if (r < 0) { free(fds); - usbi_err("poll failed %d err=%d\n", r, errno); + usbi_err(ctx, "poll failed %d err=%d\n", r, errno); return LIBUSB_ERROR_IO; } - r = usbi_backend->handle_events(fds, nfds, r); + r = usbi_backend->handle_events(ctx, fds, nfds, r); if (r) - usbi_err("backend handle_events failed with error %d", r); + usbi_err(ctx, "backend handle_events failed with error %d", r); free(fds); return r; @@ -1406,10 +1405,11 @@ static int handle_events(struct timeval *tv) * returns 1 if there is an already-expired timeout, otherwise returns 0 * and populates out */ -static int get_next_timeout(struct timeval *tv, struct timeval *out) +static int get_next_timeout(libusb_context *ctx, struct timeval *tv, + struct timeval *out) { struct timeval timeout; - int r = libusb_get_next_timeout(&timeout); + int r = libusb_get_next_timeout(ctx, &timeout); if (r) { /* timeout already expired? */ if (!timerisset(&timeout)) @@ -1440,49 +1440,52 @@ static int get_next_timeout(struct timeval *tv, struct timeval *out) * timeout. If an event arrives or a signal is raised, this function will * return early. * + * \param ctx the context to operate on, or NULL for the default context * \param tv the maximum time to block waiting for events, or zero for * non-blocking mode * \returns 0 on success, or a LIBUSB_ERROR code on failure */ -API_EXPORTED int libusb_handle_events_timeout(struct timeval *tv) +API_EXPORTED int libusb_handle_events_timeout(libusb_context *ctx, + struct timeval *tv) { int r; struct timeval poll_timeout; - r = get_next_timeout(tv, &poll_timeout); + USBI_GET_CONTEXT(ctx); + r = get_next_timeout(ctx, tv, &poll_timeout); if (r) { /* timeout already expired */ - return handle_timeouts(); + return handle_timeouts(ctx); } retry: - if (libusb_try_lock_events() == 0) { + if (libusb_try_lock_events(ctx) == 0) { /* we obtained the event lock: do our own event handling */ - r = handle_events(&poll_timeout); - libusb_unlock_events(); + r = handle_events(ctx, &poll_timeout); + libusb_unlock_events(ctx); return r; } /* another thread is doing event handling. wait for pthread events that * notify event completion. */ - libusb_lock_event_waiters(); + libusb_lock_event_waiters(ctx); - if (!libusb_event_handler_active()) { + if (!libusb_event_handler_active(ctx)) { /* we hit a race: whoever was event handling earlier finished in the * time it took us to reach this point. try the cycle again. */ - libusb_unlock_event_waiters(); + libusb_unlock_event_waiters(ctx); usbi_dbg("event handler was active but went away, retrying"); goto retry; } usbi_dbg("another thread is doing event handling"); - r = libusb_wait_for_event(&poll_timeout); - libusb_unlock_event_waiters(); + r = libusb_wait_for_event(ctx, &poll_timeout); + libusb_unlock_event_waiters(ctx); if (r < 0) return r; else if (r == 1) - return handle_timeouts(); + return handle_timeouts(ctx); else return 0; } @@ -1494,14 +1497,15 @@ retry: * function is blocking or non-blocking, or the maximum timeout, use * libusb_handle_events_timeout() instead. * + * \param ctx the context to operate on, or NULL for the default context * \returns 0 on success, or a LIBUSB_ERROR code on failure */ -API_EXPORTED int libusb_handle_events(void) +API_EXPORTED int libusb_handle_events(libusb_context *ctx) { struct timeval tv; tv.tv_sec = 2; tv.tv_usec = 0; - return libusb_handle_events_timeout(&tv); + return libusb_handle_events_timeout(ctx, &tv); } /** \ingroup poll @@ -1515,23 +1519,26 @@ API_EXPORTED int libusb_handle_events(void) * You detect events on libusb's descriptors, so you then call this function * with a zero timeout value (while still holding the event lock). * + * \param ctx the context to operate on, or NULL for the default context * \param tv the maximum time to block waiting for events, or zero for * non-blocking mode * \returns 0 on success, or a LIBUSB_ERROR code on failure * \see \ref mtasync */ -API_EXPORTED int libusb_handle_events_locked(struct timeval *tv) +API_EXPORTED int libusb_handle_events_locked(libusb_context *ctx, + struct timeval *tv) { int r; struct timeval poll_timeout; - r = get_next_timeout(tv, &poll_timeout); + USBI_GET_CONTEXT(ctx); + r = get_next_timeout(ctx, tv, &poll_timeout); if (r) { /* timeout already expired */ - return handle_timeouts(); + return handle_timeouts(ctx); } - return handle_events(&poll_timeout); + return handle_events(ctx, &poll_timeout); } /** \ingroup poll @@ -1553,12 +1560,14 @@ API_EXPORTED int libusb_handle_events_locked(struct timeval *tv) * so you should call libusb_handle_events_timeout() or similar immediately. * A return code of 0 indicates that there are no pending timeouts. * + * \param ctx the context to operate on, or NULL for the default context * \param tv output location for a relative time against the current * clock in which libusb must be called into in order to process timeout events * \returns 0 if there are no pending timeouts, 1 if a timeout was returned, * or LIBUSB_ERROR_OTHER on failure */ -API_EXPORTED int libusb_get_next_timeout(struct timeval *tv) +API_EXPORTED int libusb_get_next_timeout(libusb_context *ctx, + struct timeval *tv) { struct usbi_transfer *transfer; struct timespec cur_ts; @@ -1567,21 +1576,22 @@ API_EXPORTED int libusb_get_next_timeout(struct timeval *tv) int r; int found = 0; - pthread_mutex_lock(&flying_transfers_lock); - if (list_empty(&flying_transfers)) { - pthread_mutex_unlock(&flying_transfers_lock); + USBI_GET_CONTEXT(ctx); + pthread_mutex_lock(&ctx->flying_transfers_lock); + if (list_empty(&ctx->flying_transfers)) { + pthread_mutex_unlock(&ctx->flying_transfers_lock); usbi_dbg("no URBs, no timeout!"); return 0; } /* find next transfer which hasn't already been processed as timed out */ - list_for_each_entry(transfer, &flying_transfers, list) { + list_for_each_entry(transfer, &ctx->flying_transfers, list) { if (!(transfer->flags & USBI_TRANSFER_TIMED_OUT)) { found = 1; break; } } - pthread_mutex_unlock(&flying_transfers_lock); + pthread_mutex_unlock(&ctx->flying_transfers_lock); if (!found) { usbi_dbg("all URBs have already been processed for timeouts"); @@ -1598,7 +1608,7 @@ API_EXPORTED int libusb_get_next_timeout(struct timeval *tv) r = clock_gettime(CLOCK_MONOTONIC, &cur_ts); if (r < 0) { - usbi_err("failed to read monotonic clock, errno=%d", errno); + usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno); return LIBUSB_ERROR_OTHER; } TIMESPEC_TO_TIMEVAL(&cur_tv, &cur_ts); @@ -1621,20 +1631,22 @@ API_EXPORTED int libusb_get_next_timeout(struct timeval *tv) * * To remove notifiers, pass NULL values for the function pointers. * + * \param ctx the context to operate on, or NULL for the default context * \param added_cb pointer to function for addition notifications * \param removed_cb pointer to function for removal notifications */ -API_EXPORTED void libusb_set_pollfd_notifiers(libusb_pollfd_added_cb added_cb, - libusb_pollfd_removed_cb removed_cb) +API_EXPORTED void libusb_set_pollfd_notifiers(libusb_context *ctx, + libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb) { - fd_added_cb = added_cb; - fd_removed_cb = removed_cb; + USBI_GET_CONTEXT(ctx); + ctx->fd_added_cb = added_cb; + ctx->fd_removed_cb = removed_cb; } /* Add a file descriptor to the list of file descriptors to be monitored. * events should be specified as a bitmask of events passed to poll(), e.g. * POLLIN and/or POLLOUT. */ -int usbi_add_pollfd(int fd, short events) +int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events) { struct usbi_pollfd *ipollfd = malloc(sizeof(*ipollfd)); if (!ipollfd) @@ -1643,24 +1655,24 @@ int usbi_add_pollfd(int fd, short events) usbi_dbg("add fd %d events %d", fd, events); ipollfd->pollfd.fd = fd; ipollfd->pollfd.events = events; - pthread_mutex_lock(&pollfds_lock); - list_add(&ipollfd->list, &pollfds); - pthread_mutex_unlock(&pollfds_lock); + pthread_mutex_lock(&ctx->pollfds_lock); + list_add(&ipollfd->list, &ctx->pollfds); + pthread_mutex_unlock(&ctx->pollfds_lock); - if (fd_added_cb) - fd_added_cb(fd, events); + if (ctx->fd_added_cb) + ctx->fd_added_cb(fd, events); return 0; } /* Remove a file descriptor from the list of file descriptors to be polled. */ -void usbi_remove_pollfd(int fd) +void usbi_remove_pollfd(struct libusb_context *ctx, int fd) { struct usbi_pollfd *ipollfd; int found = 0; usbi_dbg("remove fd %d", fd); - pthread_mutex_lock(&pollfds_lock); - list_for_each_entry(ipollfd, &pollfds, list) + pthread_mutex_lock(&ctx->pollfds_lock); + list_for_each_entry(ipollfd, &ctx->pollfds, list) if (ipollfd->pollfd.fd == fd) { found = 1; break; @@ -1668,15 +1680,15 @@ void usbi_remove_pollfd(int fd) if (!found) { usbi_dbg("couldn't find fd %d to remove", fd); - pthread_mutex_unlock(&pollfds_lock); + pthread_mutex_unlock(&ctx->pollfds_lock); return; } list_del(&ipollfd->list); - pthread_mutex_unlock(&pollfds_lock); + pthread_mutex_unlock(&ctx->pollfds_lock); free(ipollfd); - if (fd_removed_cb) - fd_removed_cb(fd); + if (ctx->fd_removed_cb) + ctx->fd_removed_cb(fd); } /** \ingroup poll @@ -1686,30 +1698,32 @@ void usbi_remove_pollfd(int fd) * The returned list is NULL-terminated and should be freed with free() when * done. The actual list contents must not be touched. * + * \param ctx the context to operate on, or NULL for the default context * \returns a NULL-terminated list of libusb_pollfd structures, or NULL on * error */ -API_EXPORTED const struct libusb_pollfd **libusb_get_pollfds(void) +API_EXPORTED const struct libusb_pollfd **libusb_get_pollfds( + libusb_context *ctx) { struct libusb_pollfd **ret = NULL; struct usbi_pollfd *ipollfd; size_t i = 0; size_t cnt = 0; - pthread_mutex_lock(&pollfds_lock); - list_for_each_entry(ipollfd, &pollfds, list) + pthread_mutex_lock(&ctx->pollfds_lock); + list_for_each_entry(ipollfd, &ctx->pollfds, list) cnt++; ret = calloc(cnt + 1, sizeof(struct libusb_pollfd *)); if (!ret) goto out; - list_for_each_entry(ipollfd, &pollfds, list) + list_for_each_entry(ipollfd, &ctx->pollfds, list) ret[i++] = (struct libusb_pollfd *) ipollfd; ret[cnt] = NULL; out: - pthread_mutex_unlock(&pollfds_lock); + pthread_mutex_unlock(&ctx->pollfds_lock); return (const struct libusb_pollfd **) ret; } @@ -1738,14 +1752,14 @@ void usbi_handle_disconnect(struct libusb_device_handle *handle) */ while (1) { - pthread_mutex_lock(&flying_transfers_lock); + pthread_mutex_lock(&HANDLE_CTX(handle)->flying_transfers_lock); to_cancel = NULL; - list_for_each_entry(cur, &flying_transfers, list) + list_for_each_entry(cur, &HANDLE_CTX(handle)->flying_transfers, list) if (__USBI_TRANSFER_TO_LIBUSB_TRANSFER(cur)->dev_handle == handle) { to_cancel = cur; break; } - pthread_mutex_unlock(&flying_transfers_lock); + pthread_mutex_unlock(&HANDLE_CTX(handle)->flying_transfers_lock); if (!to_cancel) break; diff --git a/libusb/libusb.h b/libusb/libusb.h index 40d1a87..20d1988 100644 --- a/libusb/libusb.h +++ b/libusb/libusb.h @@ -533,9 +533,29 @@ struct libusb_control_setup { /* libusb */ +struct libusb_context; struct libusb_device; struct libusb_device_handle; +/** \ingroup lib + * Structure representing a libusb session. The concept of individual libusb + * sessions allows for your program to use two libraries (or dynamically + * load two modules) which both independently use libusb. This will prevent + * interference between the individual libusb users - for example + * libusb_set_debug() will not affect the other user of the library, and + * libusb_exit() will not destroy resources that the other user is still + * using. + * + * Sessions are created by libusb_init() and destroyed through libusb_exit(). + * If your application is guaranteed to only ever include a single libusb + * user (i.e. you), you do not have to worry about contexts: pass NULL in + * every function call where a context is required. The default context + * will be used. + * + * For more information, see \ref contexts. + */ +typedef struct libusb_context libusb_context; + /** \ingroup dev * Structure representing a USB device detected on the system. This is an * opaque type for which you are only ever provided with a pointer, usually @@ -727,11 +747,12 @@ struct libusb_transfer { struct libusb_iso_packet_descriptor iso_packet_desc[0]; }; -int libusb_init(void); -void libusb_exit(void); -void libusb_set_debug(int level); +int libusb_init(libusb_context **ctx); +void libusb_exit(libusb_context *ctx); +void libusb_set_debug(libusb_context *ctx, int level); -ssize_t libusb_get_device_list(libusb_device ***list); +ssize_t libusb_get_device_list(libusb_context *ctx, + libusb_device ***list); void libusb_free_device_list(libusb_device **list, int unref_devices); libusb_device *libusb_ref_device(libusb_device *dev); void libusb_unref_device(libusb_device *dev); @@ -757,8 +778,8 @@ int libusb_set_configuration(libusb_device_handle *dev, int configuration); int libusb_claim_interface(libusb_device_handle *dev, int iface); int libusb_release_interface(libusb_device_handle *dev, int iface); -libusb_device_handle *libusb_open_device_with_vid_pid(uint16_t vendor_id, - uint16_t product_id); +libusb_device_handle *libusb_open_device_with_vid_pid(libusb_context *ctx, + uint16_t vendor_id, uint16_t product_id); int libusb_set_interface_alt_setting(libusb_device_handle *dev, int interface_number, int alternate_setting); @@ -1112,18 +1133,18 @@ int libusb_get_string_descriptor_ascii(libusb_device_handle *dev, /* polling and timeouts */ -int libusb_try_lock_events(void); -void libusb_lock_events(void); -void libusb_unlock_events(void); -int libusb_event_handler_active(void); -void libusb_lock_event_waiters(void); -void libusb_unlock_event_waiters(void); -int libusb_wait_for_event(struct timeval *tv); +int libusb_try_lock_events(libusb_context *ctx); +void libusb_lock_events(libusb_context *ctx); +void libusb_unlock_events(libusb_context *ctx); +int libusb_event_handler_active(libusb_context *ctx); +void libusb_lock_event_waiters(libusb_context *ctx); +void libusb_unlock_event_waiters(libusb_context *ctx); +int libusb_wait_for_event(libusb_context *ctx, struct timeval *tv); -int libusb_handle_events_timeout(struct timeval *tv); -int libusb_handle_events(void); -int libusb_handle_events_locked(struct timeval *tv); -int libusb_get_next_timeout(struct timeval *tv); +int libusb_handle_events_timeout(libusb_context *ctx, struct timeval *tv); +int libusb_handle_events(libusb_context *ctx); +int libusb_handle_events_locked(libusb_context *ctx, struct timeval *tv); +int libusb_get_next_timeout(libusb_context *ctx, struct timeval *tv); /** \ingroup poll * File descriptor for polling @@ -1158,9 +1179,9 @@ typedef void (*libusb_pollfd_added_cb)(int fd, short events); */ typedef void (*libusb_pollfd_removed_cb)(int fd); -const struct libusb_pollfd **libusb_get_pollfds(void); -void libusb_set_pollfd_notifiers(libusb_pollfd_added_cb added_cb, - libusb_pollfd_removed_cb removed_cb); +const struct libusb_pollfd **libusb_get_pollfds(libusb_context *ctx); +void libusb_set_pollfd_notifiers(libusb_context *ctx, + libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb); #ifdef __cplusplus } diff --git a/libusb/libusbi.h b/libusb/libusbi.h index 5c00a63..8eb4c5c 100644 --- a/libusb/libusbi.h +++ b/libusb/libusbi.h @@ -112,23 +112,72 @@ enum usbi_log_level { LOG_LEVEL_ERROR, }; -void usbi_log(enum usbi_log_level, const char *function, const char *format, ...); +void usbi_log(struct libusb_context *ctx, enum usbi_log_level, + const char *function, const char *format, ...); #ifdef ENABLE_LOGGING -#define _usbi_log(level, fmt...) usbi_log(level, __FUNCTION__, fmt) +#define _usbi_log(ctx, level, fmt...) usbi_log(ctx, level, __FUNCTION__, fmt) #else -#define _usbi_log(level, fmt...) +#define _usbi_log(ctx, level, fmt...) #endif #ifdef ENABLE_DEBUG_LOGGING -#define usbi_dbg(fmt...) _usbi_log(LOG_LEVEL_DEBUG, fmt) +#define usbi_dbg(fmt...) _usbi_log(NULL, LOG_LEVEL_DEBUG, fmt) #else #define usbi_dbg(fmt...) #endif -#define usbi_info(fmt...) _usbi_log(LOG_LEVEL_INFO, fmt) -#define usbi_warn(fmt...) _usbi_log(LOG_LEVEL_WARNING, fmt) -#define usbi_err(fmt...) _usbi_log(LOG_LEVEL_ERROR, fmt) +#define usbi_info(ctx, fmt...) _usbi_log(ctx, LOG_LEVEL_INFO, fmt) +#define usbi_warn(ctx, fmt...) _usbi_log(ctx, LOG_LEVEL_WARNING, fmt) +#define usbi_err(ctx, fmt...) _usbi_log(ctx, LOG_LEVEL_ERROR, fmt) + +#define USBI_GET_CONTEXT(ctx) if (!(ctx)) (ctx) = usbi_default_context +#define DEVICE_CTX(dev) ((dev)->ctx) +#define HANDLE_CTX(handle) (DEVICE_CTX((handle)->dev)) +#define TRANSFER_CTX(transfer) (HANDLE_CTX((transfer)->dev_handle)) +#define ITRANSFER_CTX(transfer) \ + (TRANSFER_CTX(__USBI_TRANSFER_TO_LIBUSB_TRANSFER(transfer))) + +extern struct libusb_context *usbi_default_context; + +struct libusb_context { + int debug; + int debug_fixed; + + struct list_head usb_devs; + pthread_mutex_t usb_devs_lock; + + /* A list of open handles. Backends are free to traverse this if required. + */ + struct list_head open_devs; + pthread_mutex_t open_devs_lock; + + /* 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 + * infinite timeout are always placed at the very end. */ + struct list_head flying_transfers; + pthread_mutex_t flying_transfers_lock; + + /* list of poll fd's */ + struct list_head pollfds; + pthread_mutex_t pollfds_lock; + + /* user callbacks for pollfd changes */ + libusb_pollfd_added_cb fd_added_cb; + libusb_pollfd_removed_cb fd_removed_cb; + + /* ensures that only one thread is handling events at any one time */ + pthread_mutex_t events_lock; + + /* used to see if there is an active thread doing event handling */ + int event_handler_active; + + /* used to wait for event completion in threads other than the one that is + * event handling */ + pthread_mutex_t event_waiters_lock; + pthread_cond_t event_waiters_cond; +}; struct libusb_device { /* lock protects refcnt, everything else is finalized at initialization @@ -136,6 +185,8 @@ struct libusb_device { pthread_mutex_t lock; int refcnt; + struct libusb_context *ctx; + uint8_t bus_number; uint8_t device_address; uint8_t num_configurations; @@ -203,13 +254,12 @@ struct usb_descriptor_header { /* shared data and functions */ -extern struct list_head usbi_open_devs; -extern pthread_mutex_t usbi_open_devs_lock; - -void usbi_io_init(void); +void usbi_io_init(struct libusb_context *ctx); -struct libusb_device *usbi_alloc_device(unsigned long session_id); -struct libusb_device *usbi_get_device_by_session_id(unsigned long session_id); +struct libusb_device *usbi_alloc_device(struct libusb_context *ctx, + unsigned long session_id); +struct libusb_device *usbi_get_device_by_session_id(struct libusb_context *ctx, + unsigned long session_id); int usbi_sanitize_device(struct libusb_device *dev); void usbi_handle_disconnect(struct libusb_device_handle *handle); @@ -231,8 +281,8 @@ struct usbi_pollfd { struct list_head list; }; -int usbi_add_pollfd(int fd, short events); -void usbi_remove_pollfd(int fd); +int usbi_add_pollfd(struct libusb_context *ctx, int fd, short events); +void usbi_remove_pollfd(struct libusb_context *ctx, int fd); /* device discovery */ @@ -267,7 +317,7 @@ struct usbi_os_backend { * * Return 0 on success, or a LIBUSB_ERROR code on failure. */ - int (*init)(void); + int (*init)(struct libusb_context *ctx); /* Deinitialization. Optional. This function should destroy anything * that was set up by init. @@ -325,7 +375,8 @@ struct usbi_os_backend { * * Return 0 on success, or a LIBUSB_ERROR code on failure. */ - int (*get_device_list)(struct discovered_devs **discdevs); + int (*get_device_list)(struct libusb_context *ctx, + struct discovered_devs **discdevs); /* Open a device for I/O and other USB operations. The device handle * is preallocated for you, you can retrieve the device in question @@ -651,7 +702,8 @@ struct usbi_os_backend { * * Return 0 on success, or a LIBUSB_ERROR code on failure. */ - int (*handle_events)(struct pollfd *fds, nfds_t nfds, int num_ready); + int (*handle_events)(struct libusb_context *ctx, + struct pollfd *fds, nfds_t nfds, int num_ready); /* Number of bytes to reserve for per-device private backend data. * This private data area is accessible through the "os_priv" field of diff --git a/libusb/os/linux_usbfs.c b/libusb/os/linux_usbfs.c index fb50d34..5ca8640 100644 --- a/libusb/os/linux_usbfs.c +++ b/libusb/os/linux_usbfs.c @@ -162,14 +162,14 @@ static const char *find_usbfs_path(void) return ret; } -static int op_init(void) +static int op_init(struct libusb_context *ctx) { struct stat statbuf; int r; usbfs_path = find_usbfs_path(); if (!usbfs_path) { - usbi_err("could not find usbfs"); + usbi_err(ctx, "could not find usbfs"); return LIBUSB_ERROR_OTHER; } @@ -205,7 +205,8 @@ static int __open_sysfs_attr(struct libusb_device *dev, const char *attr) SYSFS_DEVICE_PATH, priv->sysfs_dir, attr); fd = open(filename, O_RDONLY); if (fd < 0) { - usbi_err("open %s failed ret=%d errno=%d", filename, fd, errno); + usbi_err(DEVICE_CTX(dev), + "open %s failed ret=%d errno=%d", filename, fd, errno); return LIBUSB_ERROR_IO; } @@ -228,10 +229,10 @@ static int sysfs_get_device_descriptor(struct libusb_device *dev, r = read(fd, buffer, DEVICE_DESC_LENGTH);; close(fd); if (r < 0) { - usbi_err("read failed, ret=%d errno=%d", fd, errno); + usbi_err(DEVICE_CTX(dev), "read failed, ret=%d errno=%d", fd, errno); return LIBUSB_ERROR_IO; } else if (r < DEVICE_DESC_LENGTH) { - usbi_err("short read %d/%d", r, DEVICE_DESC_LENGTH); + usbi_err(DEVICE_CTX(dev), "short read %d/%d", r, DEVICE_DESC_LENGTH); return LIBUSB_ERROR_IO; } @@ -277,7 +278,7 @@ static int sysfs_get_active_config_descriptor(struct libusb_device *dev, off = lseek(fd, DEVICE_DESC_LENGTH, SEEK_SET); if (off < 0) { - usbi_err("seek failed, ret=%d errno=%d", off, errno); + usbi_err(DEVICE_CTX(dev), "seek failed, ret=%d errno=%d", off, errno); close(fd); return LIBUSB_ERROR_IO; } @@ -285,13 +286,13 @@ static int sysfs_get_active_config_descriptor(struct libusb_device *dev, r = read(fd, buffer, len); close(fd); if (r < 0) { - usbi_err("read failed, ret=%d errno=%d", fd, errno); + usbi_err(DEVICE_CTX(dev), "read failed, ret=%d errno=%d", fd, errno); return LIBUSB_ERROR_IO; } else if (r == 0) { usbi_dbg("device is unconfigured"); return LIBUSB_ERROR_NOT_FOUND; } else if (r < len) { - usbi_err("short read %d/%d", r, len); + usbi_err(DEVICE_CTX(dev), "short read %d/%d", r, len); return LIBUSB_ERROR_IO; } @@ -313,8 +314,8 @@ static int op_get_active_config_descriptor(struct libusb_device *dev, /* takes a usbfs fd, attempts to find the requested config and copy a certain * amount of it into an output buffer. a bConfigurationValue of -1 indicates * that the first config should be retreived. */ -static int get_config_descriptor(int fd, uint8_t config_index, - unsigned char *buffer, size_t len) +static int get_config_descriptor(struct libusb_context *ctx, int fd, + uint8_t config_index, unsigned char *buffer, size_t len) { unsigned char tmp[8]; off_t off; @@ -322,7 +323,7 @@ static int get_config_descriptor(int fd, uint8_t config_index, off = lseek(fd, DEVICE_DESC_LENGTH, SEEK_SET); if (off < 0) { - usbi_err("seek failed ret=%d errno=%d", off, errno); + usbi_err(ctx, "seek failed ret=%d errno=%d", off, errno); return LIBUSB_ERROR_IO; } @@ -334,10 +335,10 @@ static int get_config_descriptor(int fd, uint8_t config_index, /* read first 8 bytes of descriptor */ r = read(fd, tmp, sizeof(tmp)); if (r < 0) { - usbi_err("read failed ret=%d errno=%d", r, errno); + usbi_err(ctx, "read failed ret=%d errno=%d", r, errno); return LIBUSB_ERROR_IO; } else if (r < sizeof(tmp)) { - usbi_err("short descriptor read %d/%d", r, sizeof(tmp)); + usbi_err(ctx, "short descriptor read %d/%d", r, sizeof(tmp)); return LIBUSB_ERROR_IO; } @@ -346,7 +347,7 @@ static int get_config_descriptor(int fd, uint8_t config_index, /* seek forward to end of config */ off = lseek(fd, config.wTotalLength - sizeof(tmp), SEEK_CUR); if (off < 0) { - usbi_err("seek failed ret=%d errno=%d", off, errno); + usbi_err(ctx, "seek failed ret=%d errno=%d", off, errno); return LIBUSB_ERROR_IO; } @@ -356,10 +357,10 @@ static int get_config_descriptor(int fd, uint8_t config_index, /* read the rest of the descriptor */ r = read(fd, buffer, len); if (r < 0) { - usbi_err("read failed ret=%d errno=%d", r, errno); + usbi_err(ctx, "read failed ret=%d errno=%d", r, errno); return LIBUSB_ERROR_IO; } else if (r < len) { - usbi_err("short output read %d/%d", r, len); + usbi_err(ctx, "short output read %d/%d", r, len); return LIBUSB_ERROR_IO; } @@ -379,11 +380,12 @@ static int op_get_config_descriptor(struct libusb_device *dev, __get_usbfs_path(dev, filename); fd = open(filename, O_RDONLY); if (fd < 0) { - usbi_err("open '%s' failed, ret=%d errno=%d", filename, fd, errno); + usbi_err(DEVICE_CTX(dev), + "open '%s' failed, ret=%d errno=%d", filename, fd, errno); return LIBUSB_ERROR_IO; } - r = get_config_descriptor(fd, config_index, buffer, len); + r = get_config_descriptor(DEVICE_CTX(dev), fd, config_index, buffer, len); close(fd); *host_endian = 1; return r; @@ -412,9 +414,9 @@ static int cache_active_config(struct libusb_device *dev, int fd, return LIBUSB_ERROR_NOT_FOUND; } - r = get_config_descriptor(fd, idx, tmp, sizeof(tmp)); + r = get_config_descriptor(DEVICE_CTX(dev), fd, idx, tmp, sizeof(tmp)); if (r < 0) { - usbi_err("first read error %d", r); + usbi_err(DEVICE_CTX(dev), "first read error %d", r); return r; } @@ -423,7 +425,8 @@ static int cache_active_config(struct libusb_device *dev, int fd, if (!buf) return LIBUSB_ERROR_NO_MEM; - r = get_config_descriptor(fd, idx, buf, config.wTotalLength); + r = get_config_descriptor(DEVICE_CTX(dev), fd, idx, buf, + config.wTotalLength); if (r < 0) { free(buf); return r; @@ -451,26 +454,26 @@ static int sysfs_get_active_config(struct libusb_device *dev, int *config) r = read(fd, tmp, sizeof(tmp)); close(fd); if (r < 0) { - usbi_err("read bConfigurationValue failed ret=%d errno=%d", - r, errno); + usbi_err(DEVICE_CTX(dev), + "read bConfigurationValue failed ret=%d errno=%d", r, errno); return LIBUSB_ERROR_IO; } else if (r == 0) { - usbi_err("device unconfigured"); + usbi_err(DEVICE_CTX(dev), "device unconfigured"); *config = -1; return 0; } if (tmp[sizeof(tmp) - 1] != 0) { - usbi_err("not null-terminated?"); + usbi_err(DEVICE_CTX(dev), "not null-terminated?"); return LIBUSB_ERROR_IO; } else if (tmp[0] == 0) { - usbi_err("no configuration value?"); + usbi_err(DEVICE_CTX(dev), "no configuration value?"); return LIBUSB_ERROR_IO; } num = strtol(tmp, &endptr, 10); if (endptr == tmp) { - usbi_err("error converting '%s' to integer", tmp); + usbi_err(DEVICE_CTX(dev), "error converting '%s' to integer", tmp); return LIBUSB_ERROR_IO; } @@ -499,7 +502,8 @@ static int usbfs_get_active_config(struct libusb_device *dev, int fd) if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; - usbi_err("get_configuration failed ret=%d errno=%d", r, errno); + usbi_err(DEVICE_CTX(dev), + "get_configuration failed ret=%d errno=%d", r, errno); return LIBUSB_ERROR_IO; } @@ -551,7 +555,7 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, } if (fd < 0) { - usbi_err("open failed, ret=%d errno=%d", fd, errno); + usbi_err(DEVICE_CTX(dev), "open failed, ret=%d errno=%d", fd, errno); return LIBUSB_ERROR_IO; } @@ -560,8 +564,8 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, /* if we only have read-only access to the device, we cannot * send a control message to determine the active config. just * assume the first one is active. */ - usbi_warn("access to %s is read-only; cannot determine " - "active configuration descriptor", path); + usbi_warn(DEVICE_CTX(dev), "access to %s is read-only; cannot " + "determine active configuration descriptor", path); } else { active_config = usbfs_get_active_config(dev, fd); if (active_config < 0) { @@ -587,12 +591,13 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, r = read(fd, dev_buf, DEVICE_DESC_LENGTH); if (r < 0) { - usbi_err("read descriptor failed ret=%d errno=%d", fd, errno); + usbi_err(DEVICE_CTX(dev), + "read descriptor failed ret=%d errno=%d", fd, errno); free(dev_buf); close(fd); return LIBUSB_ERROR_IO; } else if (r < DEVICE_DESC_LENGTH) { - usbi_err("short descriptor read (%d)", r); + usbi_err(DEVICE_CTX(dev), "short descriptor read (%d)", r); free(dev_buf); close(fd); return LIBUSB_ERROR_IO; @@ -616,8 +621,9 @@ static int initialize_device(struct libusb_device *dev, uint8_t busnum, return 0; } -static int enumerate_device(struct discovered_devs **_discdevs, - uint8_t busnum, uint8_t devaddr, const char *sysfs_dir) +static int enumerate_device(struct libusb_context *ctx, + struct discovered_devs **_discdevs, uint8_t busnum, uint8_t devaddr, + const char *sysfs_dir) { struct discovered_devs *discdevs; unsigned long session_id; @@ -632,14 +638,14 @@ static int enumerate_device(struct discovered_devs **_discdevs, usbi_dbg("busnum %d devaddr %d session_id %ld", busnum, devaddr, session_id); - dev = usbi_get_device_by_session_id(session_id); + dev = usbi_get_device_by_session_id(ctx, session_id); if (dev) { usbi_dbg("using existing device for %d/%d (session %ld)", busnum, devaddr, session_id); } else { usbi_dbg("allocating new device for %d/%d (session %ld)", busnum, devaddr, session_id); - dev = usbi_alloc_device(session_id); + dev = usbi_alloc_device(ctx, session_id); if (!dev) return LIBUSB_ERROR_NO_MEM; need_unref = 1; @@ -667,7 +673,8 @@ out: * failure (non-zero return) the pre-existing discdevs should be destroyed * (and devices freed). on success, the new discdevs pointer should be used * as it may have been moved. */ -static int usbfs_scan_busdir(struct discovered_devs **_discdevs, uint8_t busnum) +static int usbfs_scan_busdir(struct libusb_context *ctx, + struct discovered_devs **_discdevs, uint8_t busnum) { DIR *dir; char dirpath[PATH_MAX + 1]; @@ -679,7 +686,7 @@ static int usbfs_scan_busdir(struct discovered_devs **_discdevs, uint8_t busnum) usbi_dbg("%s", dirpath); dir = opendir(dirpath); if (!dir) { - usbi_err("opendir '%s' failed, errno=%d", dirpath, errno); + usbi_err(ctx, "opendir '%s' failed, errno=%d", dirpath, errno); /* FIXME: should handle valid race conditions like hub unplugged * during directory iteration - this is not an error */ return LIBUSB_ERROR_IO; @@ -697,7 +704,7 @@ static int usbfs_scan_busdir(struct discovered_devs **_discdevs, uint8_t busnum) continue; } - r = enumerate_device(&discdevs, busnum, (uint8_t) devaddr, NULL); + r = enumerate_device(ctx, &discdevs, busnum, (uint8_t) devaddr, NULL); if (r < 0) goto out; } @@ -708,7 +715,8 @@ out: return r; } -static int usbfs_get_device_list(struct discovered_devs **_discdevs) +static int usbfs_get_device_list(struct libusb_context *ctx, + struct discovered_devs **_discdevs) { struct dirent *entry; DIR *buses = opendir(usbfs_path); @@ -716,7 +724,7 @@ static int usbfs_get_device_list(struct discovered_devs **_discdevs) int r = 0; if (!buses) { - usbi_err("opendir buses failed errno=%d", errno); + usbi_err(ctx, "opendir buses failed errno=%d", errno); return LIBUSB_ERROR_IO; } @@ -733,7 +741,7 @@ static int usbfs_get_device_list(struct discovered_devs **_discdevs) continue; } - r = usbfs_scan_busdir(&discdevs_new, busnum); + r = usbfs_scan_busdir(ctx, &discdevs_new, busnum); if (r < 0) goto out; discdevs = discdevs_new; @@ -746,8 +754,9 @@ out: } -static int sysfs_scan_device(struct discovered_devs **_discdevs, - const char *devname, int *usbfs_fallback) +static int sysfs_scan_device(struct libusb_context *ctx, + struct discovered_devs **_discdevs, const char *devname, + int *usbfs_fallback) { int r; FILE *fd; @@ -784,7 +793,7 @@ static int sysfs_scan_device(struct discovered_devs **_discdevs, *usbfs_fallback = 1; return LIBUSB_ERROR_OTHER; } - usbi_err("open busnum failed, errno=%d", errno); + usbi_err(ctx, "open busnum failed, errno=%d", errno); return LIBUSB_ERROR_IO; } @@ -793,21 +802,21 @@ static int sysfs_scan_device(struct discovered_devs **_discdevs, r = fscanf(fd, "%d", &busnum); fclose(fd); if (r != 1) { - usbi_err("fscanf busnum returned %d, errno=%d", r, errno); + usbi_err(ctx, "fscanf busnum returned %d, errno=%d", r, errno); return LIBUSB_ERROR_IO; } snprintf(filename, PATH_MAX, "%s/%s/devnum", SYSFS_DEVICE_PATH, devname); fd = fopen(filename, "r"); if (!fd) { - usbi_err("open devnum failed, errno=%d", errno); + usbi_err(ctx, "open devnum failed, errno=%d", errno); return LIBUSB_ERROR_IO; } r = fscanf(fd, "%d", &devaddr); fclose(fd); if (r != 1) { - usbi_err("fscanf devnum returned %d, errno=%d", r, errno); + usbi_err(ctx, "fscanf devnum returned %d, errno=%d", r, errno); return LIBUSB_ERROR_IO; } @@ -815,11 +824,12 @@ static int sysfs_scan_device(struct discovered_devs **_discdevs, if (busnum > 255 || devaddr > 255) return LIBUSB_ERROR_INVALID_PARAM; - return enumerate_device(_discdevs, busnum & 0xff, devaddr & 0xff, devname); + return enumerate_device(ctx, _discdevs, busnum & 0xff, devaddr & 0xff, + devname); } -static int sysfs_get_device_list(struct discovered_devs **_discdevs, - int *usbfs_fallback) +static int sysfs_get_device_list(struct libusb_context *ctx, + struct discovered_devs **_discdevs, int *usbfs_fallback) { struct discovered_devs *discdevs = *_discdevs; DIR *devices = opendir(SYSFS_DEVICE_PATH); @@ -827,7 +837,7 @@ static int sysfs_get_device_list(struct discovered_devs **_discdevs, int r = 0; if (!devices) { - usbi_err("opendir devices failed errno=%d", errno); + usbi_err(ctx, "opendir devices failed errno=%d", errno); return LIBUSB_ERROR_IO; } @@ -838,7 +848,8 @@ static int sysfs_get_device_list(struct discovered_devs **_discdevs, || strchr(entry->d_name, ':')) continue; - r = sysfs_scan_device(&discdevs_new, entry->d_name, usbfs_fallback); + r = sysfs_scan_device(ctx, &discdevs_new, entry->d_name, + usbfs_fallback); if (r < 0) goto out; discdevs = discdevs_new; @@ -850,7 +861,8 @@ out: return r; } -static int op_get_device_list(struct discovered_devs **_discdevs) +static int op_get_device_list(struct libusb_context *ctx, + struct discovered_devs **_discdevs) { /* we can retrieve device list and descriptors from sysfs or usbfs. * sysfs is preferable, because if we use usbfs we end up resuming @@ -864,12 +876,12 @@ static int op_get_device_list(struct discovered_devs **_discdevs) */ if (sysfs_can_relate_devices != 0) { int usbfs_fallback = 0; - int r = sysfs_get_device_list(_discdevs, &usbfs_fallback); + int r = sysfs_get_device_list(ctx, _discdevs, &usbfs_fallback); if (!usbfs_fallback) return r; } - return usbfs_get_device_list(_discdevs); + return usbfs_get_device_list(ctx, _discdevs); } static int op_open(struct libusb_device_handle *handle) @@ -889,18 +901,19 @@ static int op_open(struct libusb_device_handle *handle) } else if (errno == ENOENT) { return LIBUSB_ERROR_NO_DEVICE; } else { - usbi_err("open failed, code %d errno %d", hpriv->fd, errno); + usbi_err(HANDLE_CTX(handle), + "open failed, code %d errno %d", hpriv->fd, errno); return LIBUSB_ERROR_IO; } } - return usbi_add_pollfd(hpriv->fd, POLLOUT); + return usbi_add_pollfd(HANDLE_CTX(handle), hpriv->fd, POLLOUT); } static void op_close(struct libusb_device_handle *dev_handle) { int fd = __device_handle_priv(dev_handle)->fd; - usbi_remove_pollfd(fd); + usbi_remove_pollfd(HANDLE_CTX(dev_handle), fd); close(fd); } @@ -931,7 +944,7 @@ static int op_set_configuration(struct libusb_device_handle *handle, int config) else if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; - usbi_err("failed, error %d errno %d", r, errno); + usbi_err(HANDLE_CTX(handle), "failed, error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } @@ -945,8 +958,8 @@ static int op_set_configuration(struct libusb_device_handle *handle, int config) } else { r = cache_active_config(handle->dev, fd, config); if (r < 0) - usbi_warn("failed to update cached config descriptor, " - "error %d", r); + usbi_warn(HANDLE_CTX(handle), + "failed to update cached config descriptor, error %d", r); } } @@ -965,7 +978,8 @@ static int op_claim_interface(struct libusb_device_handle *handle, int iface) else if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; - usbi_err("claim interface failed, error %d errno %d", r, errno); + usbi_err(HANDLE_CTX(handle), + "claim interface failed, error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } return 0; @@ -979,7 +993,8 @@ static int op_release_interface(struct libusb_device_handle *handle, int iface) if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; - usbi_err("release interface failed, error %d errno %d", r, errno); + usbi_err(HANDLE_CTX(handle), + "release interface failed, error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } return 0; @@ -1001,7 +1016,8 @@ static int op_set_interface(struct libusb_device_handle *handle, int iface, else if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; - usbi_err("setintf failed error %d errno %d", r, errno); + usbi_err(HANDLE_CTX(handle), + "setintf failed error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } @@ -1020,7 +1036,8 @@ static int op_clear_halt(struct libusb_device_handle *handle, else if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; - usbi_err("clear_halt failed error %d errno %d", r, errno); + usbi_err(HANDLE_CTX(handle), + "clear_halt failed error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } @@ -1035,7 +1052,8 @@ static int op_reset_device(struct libusb_device_handle *handle) if (errno == ENODEV) return LIBUSB_ERROR_NOT_FOUND; - usbi_err("reset failed error %d errno %d", r, errno); + usbi_err(HANDLE_CTX(handle), + "reset failed error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } @@ -1057,7 +1075,8 @@ static int op_kernel_driver_active(struct libusb_device_handle *handle, else if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; - usbi_err("get driver failed error %d errno %d", r, errno); + usbi_err(HANDLE_CTX(handle), + "get driver failed error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } @@ -1084,7 +1103,8 @@ static int op_detach_kernel_driver(struct libusb_device_handle *handle, else if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; - usbi_err("detach failed error %d errno %d", r, errno); + usbi_err(HANDLE_CTX(handle), + "detach failed error %d errno %d", r, errno); return LIBUSB_ERROR_OTHER; } @@ -1170,7 +1190,8 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer, if (errno == ENODEV) { r = LIBUSB_ERROR_NO_DEVICE; } else { - usbi_err("submiturb failed error %d errno=%d", r, errno); + usbi_err(TRANSFER_CTX(transfer), + "submiturb failed error %d errno=%d", r, errno); r = LIBUSB_ERROR_IO; } @@ -1203,7 +1224,8 @@ static int submit_bulk_transfer(struct usbi_transfer *itransfer, else if (errno == EINVAL) tpriv->awaiting_reap++; else - usbi_warn("unrecognised discard return %d", tmp); + usbi_warn(TRANSFER_CTX(transfer), + "unrecognised discard return %d", tmp); } usbi_dbg("reporting successful submission but waiting for %d " @@ -1324,7 +1346,8 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer) if (errno == ENODEV) { r = LIBUSB_ERROR_NO_DEVICE; } else { - usbi_err("submiturb failed error %d errno=%d", r, errno); + usbi_err(TRANSFER_CTX(transfer), + "submiturb failed error %d errno=%d", r, errno); r = LIBUSB_ERROR_IO; } @@ -1357,7 +1380,8 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer) else if (errno == EINVAL) tpriv->awaiting_reap++; else - usbi_warn("unrecognised discard return %d", tmp); + usbi_warn(TRANSFER_CTX(transfer), + "unrecognised discard return %d", tmp); } usbi_dbg("reporting successful submission but waiting for %d " @@ -1402,7 +1426,8 @@ static int submit_control_transfer(struct usbi_transfer *itransfer) if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; - usbi_err("submiturb failed error %d errno=%d", r, errno); + usbi_err(TRANSFER_CTX(transfer), + "submiturb failed error %d errno=%d", r, errno); return LIBUSB_ERROR_IO; } return 0; @@ -1423,7 +1448,8 @@ static int op_submit_transfer(struct usbi_transfer *itransfer) case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS: return submit_iso_transfer(itransfer); default: - usbi_err("unknown endpoint type %d", transfer->type); + usbi_err(TRANSFER_CTX(transfer), + "unknown endpoint type %d", transfer->type); return LIBUSB_ERROR_INVALID_PARAM; } } @@ -1444,7 +1470,8 @@ static int cancel_control_transfer(struct usbi_transfer *itransfer) usbi_dbg("URB not found --> assuming ready to be reaped"); return 0; } else { - usbi_err("unrecognised DISCARD code %d", errno); + usbi_err(TRANSFER_CTX(transfer), + "unrecognised DISCARD code %d", errno); return LIBUSB_ERROR_OTHER; } } @@ -1469,7 +1496,8 @@ static void cancel_bulk_transfer(struct usbi_transfer *itransfer) else if (errno == EINVAL) tpriv->awaiting_reap++; else - usbi_warn("unrecognised discard return %d", errno); + usbi_warn(TRANSFER_CTX(transfer), + "unrecognised discard return %d", errno); } } @@ -1490,7 +1518,8 @@ static void cancel_iso_transfer(struct usbi_transfer *itransfer) else if (errno == EINVAL) tpriv->awaiting_reap++; else - usbi_warn("unrecognised discard return %d", errno); + usbi_warn(TRANSFER_CTX(transfer), + "unrecognised discard return %d", errno); } } @@ -1510,7 +1539,8 @@ static int op_cancel_transfer(struct usbi_transfer *itransfer) cancel_iso_transfer(itransfer); return 0; default: - usbi_err("unknown endpoint type %d", transfer->type); + usbi_err(TRANSFER_CTX(transfer), + "unknown endpoint type %d", transfer->type); return LIBUSB_ERROR_INVALID_PARAM; } } @@ -1531,7 +1561,8 @@ static void op_clear_transfer_priv(struct usbi_transfer *itransfer) free_iso_urbs(tpriv); break; default: - usbi_err("unknown endpoint type %d", transfer->type); + usbi_err(TRANSFER_CTX(transfer), + "unknown endpoint type %d", transfer->type); } } @@ -1555,7 +1586,8 @@ static int handle_bulk_completion(struct usbi_transfer *itransfer, if (urb->status == -ENOENT) { usbi_dbg("CANCEL: detected a cancelled URB"); if (tpriv->awaiting_discard == 0) - usbi_err("CANCEL: cancelled URB but not awaiting discards?"); + usbi_err(ITRANSFER_CTX(itransfer), + "CANCEL: cancelled URB but not awaiting discards?"); else tpriv->awaiting_discard--; } else if (urb->status == 0) { @@ -1564,20 +1596,23 @@ static int handle_bulk_completion(struct usbi_transfer *itransfer, /* FIXME we could solve this extreme corner case with a memmove * or something */ if (tpriv->reap_action == COMPLETED_EARLY) - usbi_warn("SOME DATA LOST! (completed early but remaining " - "urb completed)"); + usbi_warn(ITRANSFER_CTX(itransfer), "SOME DATA LOST! " + "(completed early but remaining urb completed)"); if (tpriv->awaiting_reap == 0) - usbi_err("CANCEL: completed URB not awaiting reap?"); + usbi_err(ITRANSFER_CTX(itransfer), + "CANCEL: completed URB not awaiting reap?"); else tpriv->awaiting_reap--; } else if (urb->status == -EPIPE || urb->status == -EOVERFLOW) { if (tpriv->awaiting_reap == 0) - usbi_err("CANCEL: completed URB not awaiting reap?"); + usbi_err(ITRANSFER_CTX(itransfer), + "CANCEL: completed URB not awaiting reap?"); else tpriv->awaiting_reap--; } else { - usbi_warn("unhandled CANCEL urb status %d", urb->status); + usbi_warn(ITRANSFER_CTX(itransfer), + "unhandled CANCEL urb status %d", urb->status); } if (tpriv->awaiting_reap == 0 && tpriv->awaiting_discard == 0) { @@ -1606,7 +1641,8 @@ static int handle_bulk_completion(struct usbi_transfer *itransfer, status = LIBUSB_TRANSFER_OVERFLOW; goto out; } else if (urb->status != 0) { - usbi_warn("unrecognised urb status %d", urb->status); + usbi_warn(ITRANSFER_CTX(itransfer), + "unrecognised urb status %d", urb->status); } /* if we're the last urb or we got less data than requested then we're @@ -1620,8 +1656,8 @@ static int handle_bulk_completion(struct usbi_transfer *itransfer, __device_handle_priv(transfer->dev_handle); int i; - usbi_dbg("short transfer %d/%d --> complete!", - urb->actual_length, urb->buffer_length); + usbi_dbg("short transfer %d/%d --> complete!", urb->actual_length, + urb->buffer_length); /* we have to cancel the remaining urbs and wait for their completion * before reporting results */ @@ -1633,7 +1669,8 @@ static int handle_bulk_completion(struct usbi_transfer *itransfer, else if (errno == EINVAL) tpriv->awaiting_reap++; else - usbi_warn("unrecognised discard return %d", errno); + usbi_warn(ITRANSFER_CTX(itransfer), + "unrecognised discard return %d", errno); } return 0; } else { @@ -1663,7 +1700,7 @@ static int handle_iso_completion(struct usbi_transfer *itransfer, } } if (urb_idx == 0) { - usbi_err("could not locate urb!"); + usbi_err(TRANSFER_CTX(transfer), "could not locate urb!"); return LIBUSB_ERROR_NOT_FOUND; } @@ -1686,17 +1723,20 @@ static int handle_iso_completion(struct usbi_transfer *itransfer, if (urb->status == -ENOENT) { usbi_dbg("CANCEL: detected a cancelled URB"); if (tpriv->awaiting_discard == 0) - usbi_err("CANCEL: cancelled URB but not awaiting discards?"); + usbi_err(TRANSFER_CTX(transfer), + "CANCEL: cancelled URB but not awaiting discards?"); else tpriv->awaiting_discard--; } else if (urb->status == 0) { usbi_dbg("CANCEL: detected a completed URB"); if (tpriv->awaiting_reap == 0) - usbi_err("CANCEL: completed URB not awaiting reap?"); + usbi_err(TRANSFER_CTX(transfer), + "CANCEL: completed URB not awaiting reap?"); else tpriv->awaiting_reap--; } else { - usbi_warn("unhandled CANCEL urb status %d", urb->status); + usbi_warn(TRANSFER_CTX(transfer), + "unhandled CANCEL urb status %d", urb->status); } if (tpriv->awaiting_reap == 0 && tpriv->awaiting_discard == 0) { @@ -1712,7 +1752,8 @@ static int handle_iso_completion(struct usbi_transfer *itransfer, } if (urb->status != 0) - usbi_warn("unrecognised urb status %d", urb->status); + usbi_warn(TRANSFER_CTX(transfer), + "unrecognised urb status %d", urb->status); /* if we're the last urb or we got less data than requested then we're * done */ @@ -1738,7 +1779,8 @@ static int handle_control_completion(struct usbi_transfer *itransfer, if (tpriv->reap_action == CANCELLED) { if (urb->status != 0 && urb->status != -ENOENT) - usbi_warn("cancel: unrecognised urb status %d", urb->status); + usbi_warn(ITRANSFER_CTX(itransfer), + "cancel: unrecognised urb status %d", urb->status); free(tpriv->urbs); usbi_handle_transfer_cancellation(itransfer); return 0; @@ -1749,7 +1791,8 @@ static int handle_control_completion(struct usbi_transfer *itransfer, status = LIBUSB_TRANSFER_STALL; goto out; } else if (urb->status != 0) { - usbi_warn("unrecognised urb status %d", urb->status); + usbi_warn(ITRANSFER_CTX(itransfer), + "unrecognised urb status %d", urb->status); status = LIBUSB_TRANSFER_ERROR; goto out; } @@ -1777,7 +1820,8 @@ static int reap_for_handle(struct libusb_device_handle *handle) if (errno == ENODEV) return LIBUSB_ERROR_NO_DEVICE; - usbi_err("reap failed error %d errno=%d", r, errno); + usbi_err(HANDLE_CTX(handle), "reap failed error %d errno=%d", + r, errno); return LIBUSB_ERROR_IO; } @@ -1796,17 +1840,19 @@ static int reap_for_handle(struct libusb_device_handle *handle) case LIBUSB_TRANSFER_TYPE_CONTROL: return handle_control_completion(itransfer, urb); default: - usbi_err("unrecognised endpoint type %x", transfer->type); + usbi_err(HANDLE_CTX(handle), "unrecognised endpoint type %x", + transfer->type); return LIBUSB_ERROR_OTHER; } } -static int op_handle_events(struct pollfd *fds, nfds_t nfds, int num_ready) +static int op_handle_events(struct libusb_context *ctx, + struct pollfd *fds, nfds_t nfds, int num_ready) { int r; int i = 0; - pthread_mutex_lock(&usbi_open_devs_lock); + pthread_mutex_lock(&ctx->open_devs_lock); for (i = 0; i < nfds && num_ready > 0; i++) { struct pollfd *pollfd = &fds[i]; struct libusb_device_handle *handle; @@ -1816,14 +1862,14 @@ static int op_handle_events(struct pollfd *fds, nfds_t nfds, int num_ready) continue; num_ready--; - list_for_each_entry(handle, &usbi_open_devs, list) { + list_for_each_entry(handle, &ctx->open_devs, list) { hpriv = __device_handle_priv(handle); if (hpriv->fd == pollfd->fd) break; } if (pollfd->revents & POLLERR) { - usbi_remove_pollfd(hpriv->fd); + usbi_remove_pollfd(HANDLE_CTX(handle), hpriv->fd); usbi_handle_disconnect(handle); continue; } @@ -1837,7 +1883,7 @@ static int op_handle_events(struct pollfd *fds, nfds_t nfds, int num_ready) r = 0; out: - pthread_mutex_unlock(&usbi_open_devs_lock); + pthread_mutex_unlock(&ctx->open_devs_lock); return r; } diff --git a/libusb/sync.c b/libusb/sync.c index 55450c4..92e7833 100644 --- a/libusb/sync.c +++ b/libusb/sync.c @@ -102,11 +102,11 @@ API_EXPORTED int libusb_control_transfer(libusb_device_handle *dev_handle, } while (!completed) { - r = libusb_handle_events(); + r = libusb_handle_events(HANDLE_CTX(dev_handle)); if (r < 0) { libusb_cancel_transfer(transfer); while (!completed) - if (libusb_handle_events() < 0) + if (libusb_handle_events(HANDLE_CTX(dev_handle)) < 0) break; libusb_free_transfer(transfer); return r; @@ -131,7 +131,8 @@ API_EXPORTED int libusb_control_transfer(libusb_device_handle *dev_handle, r = LIBUSB_ERROR_NO_DEVICE; break; default: - usbi_warn("unrecognised status code %d", transfer->status); + usbi_warn(HANDLE_CTX(dev_handle), + "unrecognised status code %d", transfer->status); r = LIBUSB_ERROR_OTHER; } @@ -169,11 +170,11 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, } while (!completed) { - r = libusb_handle_events(); + r = libusb_handle_events(HANDLE_CTX(dev_handle)); if (r < 0) { libusb_cancel_transfer(transfer); while (!completed) - if (libusb_handle_events() < 0) + if (libusb_handle_events(HANDLE_CTX(dev_handle)) < 0) break; libusb_free_transfer(transfer); return r; @@ -198,7 +199,8 @@ static int do_sync_bulk_transfer(struct libusb_device_handle *dev_handle, r = LIBUSB_ERROR_NO_DEVICE; break; default: - usbi_warn("unrecognised status code %d", transfer->status); + usbi_warn(HANDLE_CTX(dev_handle), + "unrecognised status code %d", transfer->status); r = LIBUSB_ERROR_OTHER; } -- cgit v1.2.1