Introduce contexts to the API
authorDaniel Drake <dsd@gentoo.org>
Wed, 25 Jun 2008 04:01:51 +0000 (23:01 -0500)
committerDaniel Drake <dsd@gentoo.org>
Fri, 27 Jun 2008 03:42:59 +0000 (22:42 -0500)
Suggested by David Zeuthen. This allows multiple libraries in the same
process to independently use libusb without interfering.

TODO
examples/dpfp.c
examples/dpfp_threaded.c
examples/lsusb.c
libusb/core.c
libusb/descriptor.c
libusb/io.c
libusb/libusb.h
libusb/libusbi.h
libusb/os/linux_usbfs.c
libusb/sync.c

diff --git a/TODO b/TODO
index 5cb36db..5fb4100 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,6 +1,4 @@
 new sysfs descriptors format
-contexts
-event handling/threads issue
 
 for 1.1 or future
 ==================
index 7808184..bd9702a 100644 (file)
@@ -67,7 +67,7 @@ static int do_exit = 0;
 
 static int find_dpfp_device(void)
 {
-       devh = libusb_open_device_with_vid_pid(0x05ba, 0x000a);
+       devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a);
        return devh ? 0 : -EIO;
 }
 
@@ -347,7 +347,7 @@ static int init_capture(void)
        if (r < 0) {
                libusb_cancel_transfer(irq_transfer);
                while (irq_transfer)
-                       if (libusb_handle_events() < 0)
+                       if (libusb_handle_events(NULL) < 0)
                                break;
                return r;
        }
@@ -419,7 +419,7 @@ int main(void)
        struct sigaction sigact;
        int r = 1;
 
-       r = libusb_init();
+       r = libusb_init(NULL);
        if (r < 0) {
                fprintf(stderr, "failed to initialise libusb\n");
                exit(1);
@@ -464,7 +464,7 @@ int main(void)
        sigaction(SIGQUIT, &sigact, NULL);
 
        while (!do_exit) {
-               r = libusb_handle_events();
+               r = libusb_handle_events(NULL);
                if (r < 0)
                        goto out_deinit;
        }
@@ -484,7 +484,7 @@ int main(void)
        }
        
        while (irq_transfer || img_transfer)
-               if (libusb_handle_events() < 0)
+               if (libusb_handle_events(NULL) < 0)
                        break;
        
        if (do_exit == 1)
@@ -501,7 +501,7 @@ out_release:
        libusb_release_interface(devh, 0);
 out:
        libusb_close(devh);
-       libusb_exit();
+       libusb_exit(NULL);
        return r >= 0 ? r : -r;
 }
 
index 2d106d3..59540e3 100644 (file)
@@ -83,7 +83,7 @@ static void *poll_thread_main(void *arg)
 
        while (!do_exit) {
                struct timeval tv = { 1, 0 };
-               r = libusb_handle_events_timeout(&tv);
+               r = libusb_handle_events_timeout(NULL, &tv);
                if (r < 0) {
                        request_exit(2);
                        break;
@@ -96,7 +96,7 @@ static void *poll_thread_main(void *arg)
 
 static int find_dpfp_device(void)
 {
-       devh = libusb_open_device_with_vid_pid(0x05ba, 0x000a);
+       devh = libusb_open_device_with_vid_pid(NULL, 0x05ba, 0x000a);
        return devh ? 0 : -EIO;
 }
 
@@ -374,7 +374,7 @@ static int init_capture(void)
        if (r < 0) {
                libusb_cancel_transfer(irq_transfer);
                while (irq_transfer)
-                       if (libusb_handle_events() < 0)
+                       if (libusb_handle_events(NULL) < 0)
                                break;
                return r;
        }
@@ -446,7 +446,7 @@ int main(void)
        struct sigaction sigact;
        int r = 1;
 
-       r = libusb_init();
+       r = libusb_init(NULL);
        if (r < 0) {
                fprintf(stderr, "failed to initialise libusb\n");
                exit(1);
@@ -522,7 +522,7 @@ int main(void)
        }
 
        while (img_transfer || irq_transfer)
-               if (libusb_handle_events() < 0)
+               if (libusb_handle_events(NULL) < 0)
                        break;
 
        if (do_exit == 1)
@@ -539,7 +539,7 @@ out_release:
        libusb_release_interface(devh, 0);
 out:
        libusb_close(devh);
-       libusb_exit();
+       libusb_exit(NULL);
        return r >= 0 ? r : -r;
 }
 
index 5a83020..7e9f48e 100644 (file)
@@ -47,18 +47,18 @@ int main(void)
        int r;
        ssize_t cnt;
 
-       r = libusb_init();
+       r = libusb_init(NULL);
        if (r < 0)
                return r;
 
-       cnt = libusb_get_device_list(&devs);
+       cnt = libusb_get_device_list(NULL, &devs);
        if (cnt < 0)
                return (int) cnt;
 
        print_devs(devs);
        libusb_free_device_list(devs, 1);
 
-       libusb_exit();
+       libusb_exit(NULL);
        return 0;
 }
 
index 20aed50..a6c70d4 100644 (file)
 #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
@@ -234,6 +227,37 @@ if (cfg != desired)
  */
 
 /**
+ * \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 <em>context</em> 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
  * must be performed before using any libusb functionality, and similarly you
@@ -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
 
index 37dcc64..2fed1e9 100644 (file)
@@ -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;
index 5f3d617..f2de833 100644 (file)
 
 #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, &current_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;
index 40d1a87..20d1988 100644 (file)
@@ -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
 }
index 5c00a63..8eb4c5c 100644 (file)
@@ -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
index fb50d34..5ca8640 100644 (file)
@@ -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;
 }
 
index 55450c4..92e7833 100644 (file)
@@ -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;
        }