core: update usbi_dbg to take the context as an argument
[platform/upstream/libusb.git] / libusb / io.c
index 54bef8a..f2743b9 100644 (file)
@@ -22,9 +22,6 @@
  */
 
 #include "libusbi.h"
-#include "hotplug.h"
-
-#include <errno.h>
 
 /**
  * \page libusb_io Synchronous and asynchronous device I/O
@@ -75,7 +72,7 @@
  * a single function call. When the function call returns, the transfer has
  * completed and you can parse the results.
  *
- * If you have used the libusb-0.1 before, this I/O style will seem familar to
+ * If you have used the libusb-0.1 before, this I/O style will seem familiar to
  * you. libusb-0.1 only offered a synchronous interface.
  *
  * In our input device example, to read button presses you might write code
@@ -101,7 +98,7 @@ if (r == 0 && actual_length == sizeof(data)) {
  * sleeping for that long. Execution will be tied up inside the library -
  * the entire thread will be useless for that duration.
  *
- * Another issue is that by tieing up the thread with that single transaction
+ * Another issue is that by tying up the thread with that single transaction
  * there is no possibility of performing I/O with multiple endpoints and/or
  * multiple devices simultaneously, unless you resort to creating one thread
  * per transaction.
@@ -410,7 +407,7 @@ if (r == 0 && actual_length == sizeof(data)) {
  * wLength of the setup packet, rather than the size of the data buffer. So,
  * if your wLength was 4, your transfer's <tt>length</tt> was 12, then you
  * should expect an <tt>actual_length</tt> of 4 to indicate that the data was
- * transferred in entirity.
+ * transferred in entirety.
  *
  * To simplify parsing of setup packets and obtaining the data from the
  * correct offset, you may wish to use the libusb_control_transfer_get_data()
@@ -572,7 +569,7 @@ if (r == 0 && actual_length == sizeof(data)) {
  *
  * Lets begin with stating the obvious: If you're going to use a separate
  * thread for libusb event handling, your callback functions MUST be
- * threadsafe.
+ * thread-safe.
  *
  * Other then that doing event handling from a separate thread, is mostly
  * simple. You can use an event thread function as follows:
@@ -812,7 +809,7 @@ while (user has not requested application exit) {
  * system calls. This is directly exposed at the
  * \ref libusb_asyncio "asynchronous interface" but it is important to note that the
  * \ref libusb_syncio "synchronous interface" is implemented on top of the
- * asynchonrous interface, therefore the same considerations apply.
+ * asynchronous interface, therefore the same considerations apply.
  *
  * The issue is that if two or more threads are concurrently calling poll()
  * or select() on libusb's file descriptors then only one of those threads
@@ -1022,7 +1019,7 @@ printf("completed!\n");
  * event handling), because the event waiter seems to have taken the event
  * waiters lock while waiting for an event. However, the system does support
  * multiple event waiters, because libusb_wait_for_event() actually drops
- * the lock while waiting, and reaquires it before continuing.
+ * the lock while waiting, and reacquires it before continuing.
  *
  * We have now implemented code which can dynamically handle situations where
  * nobody is handling events (so we should do it ourselves), and it can also
@@ -1183,12 +1180,12 @@ int usbi_io_init(struct libusb_context *ctx)
 #ifdef HAVE_OS_TIMER
        r = usbi_create_timer(&ctx->timer);
        if (r == 0) {
-               usbi_dbg("using timer for timeouts");
+               usbi_dbg(ctx, "using timer for timeouts");
                r = usbi_add_event_source(ctx, USBI_TIMER_OS_HANDLE(&ctx->timer), USBI_TIMER_POLL_EVENTS);
                if (r < 0)
                        goto err_destroy_timer;
        } else {
-               usbi_dbg("timer not available for timeouts");
+               usbi_dbg(ctx, "timer not available for timeouts");
        }
 #endif
 
@@ -1241,32 +1238,24 @@ void usbi_io_exit(struct libusb_context *ctx)
        free(ctx->event_data);
 }
 
-static int calculate_timeout(struct usbi_transfer *itransfer)
+static void calculate_timeout(struct usbi_transfer *itransfer)
 {
-       int r;
        unsigned int timeout =
                USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout;
 
        if (!timeout) {
                TIMESPEC_CLEAR(&itransfer->timeout);
-               return 0;
+               return;
        }
 
-       r = usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &itransfer->timeout);
-       if (r < 0) {
-               usbi_err(ITRANSFER_CTX(itransfer),
-                       "failed to read monotonic clock, errno=%d", errno);
-               return LIBUSB_ERROR_OTHER;
-       }
+       usbi_get_monotonic_time(&itransfer->timeout);
 
        itransfer->timeout.tv_sec += timeout / 1000U;
        itransfer->timeout.tv_nsec += (timeout % 1000U) * 1000000L;
-       if (itransfer->timeout.tv_nsec >= 1000000000L) {
+       if (itransfer->timeout.tv_nsec >= NSEC_PER_SEC) {
                ++itransfer->timeout.tv_sec;
-               itransfer->timeout.tv_nsec -= 1000000000L;
+               itransfer->timeout.tv_nsec -= NSEC_PER_SEC;
        }
-
-       return 0;
 }
 
 /** \ingroup libusb_asyncio
@@ -1320,7 +1309,6 @@ struct libusb_transfer * LIBUSB_CALL libusb_alloc_transfer(
        itransfer->priv = ptr;
        usbi_mutex_init(&itransfer->lock);
        transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
-       usbi_dbg("transfer %p", transfer);
        return transfer;
 }
 
@@ -1350,7 +1338,7 @@ void API_EXPORTED libusb_free_transfer(struct libusb_transfer *transfer)
        if (!transfer)
                return;
 
-       usbi_dbg("transfer %p", transfer);
+       usbi_dbg(TRANSFER_CTX(transfer), "transfer %p", transfer);
        if (transfer->flags & LIBUSB_TRANSFER_FREE_BUFFER)
                free(transfer->buffer);
 
@@ -1386,12 +1374,12 @@ static int arm_timer_for_next_timeout(struct libusb_context *ctx)
 
                /* act on first transfer that has not already been handled */
                if (!(itransfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))) {
-                       usbi_dbg("next timeout originally %ums", USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout);
+                       usbi_dbg(ctx, "next timeout originally %ums", USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout);
                        return usbi_arm_timer(&ctx->timer, cur_ts);
                }
        }
 
-       usbi_dbg("no timeouts, disarming timer");
+       usbi_dbg(ctx, "no timeouts, disarming timer");
        return usbi_disarm_timer(&ctx->timer);
 }
 #else
@@ -1410,12 +1398,10 @@ static int add_to_flying_list(struct usbi_transfer *itransfer)
        struct usbi_transfer *cur;
        struct timespec *timeout = &itransfer->timeout;
        struct libusb_context *ctx = ITRANSFER_CTX(itransfer);
-       int r;
+       int r = 0;
        int first = 1;
 
-       r = calculate_timeout(itransfer);
-       if (r)
-               return r;
+       calculate_timeout(itransfer);
 
        /* if we have no other flying transfers, start the list with this one */
        if (list_empty(&ctx->flying_transfers)) {
@@ -1450,7 +1436,7 @@ out:
        if (first && usbi_using_timer(ctx) && TIMESPEC_IS_SET(timeout)) {
                /* if this transfer has the lowest timeout of all active transfers,
                 * rearm the timer with this transfer's timeout */
-               usbi_dbg("arm timer for timeout in %ums (first in line)",
+               usbi_dbg(ctx, "arm timer for timeout in %ums (first in line)",
                        USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer)->timeout);
                r = usbi_arm_timer(&ctx->timer, timeout);
        }
@@ -1506,7 +1492,7 @@ int API_EXPORTED libusb_submit_transfer(struct libusb_transfer *transfer)
        struct libusb_context *ctx = TRANSFER_CTX(transfer);
        int r;
 
-       usbi_dbg("transfer %p", transfer);
+       usbi_dbg(ctx, "transfer %p", transfer);
 
        /*
         * Important note on locking, this function takes / releases locks
@@ -1594,9 +1580,10 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer)
 {
        struct usbi_transfer *itransfer =
                LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer);
+       struct libusb_context *ctx = ITRANSFER_CTX(itransfer);
        int r;
 
-       usbi_dbg("transfer %p", transfer );
+       usbi_dbg(ctx, "transfer %p", transfer );
        usbi_mutex_lock(&itransfer->lock);
        if (!(itransfer->state_flags & USBI_TRANSFER_IN_FLIGHT)
                        || (itransfer->state_flags & USBI_TRANSFER_CANCELLING)) {
@@ -1607,10 +1594,9 @@ int API_EXPORTED libusb_cancel_transfer(struct libusb_transfer *transfer)
        if (r < 0) {
                if (r != LIBUSB_ERROR_NOT_FOUND &&
                    r != LIBUSB_ERROR_NO_DEVICE)
-                       usbi_err(TRANSFER_CTX(transfer),
-                               "cancel transfer failed error %d", r);
+                       usbi_err(ctx, "cancel transfer failed error %d", r);
                else
-                       usbi_dbg("cancel transfer failed error %d", r);
+                       usbi_dbg(ctx, "cancel transfer failed error %d", r);
 
                if (r == LIBUSB_ERROR_NO_DEVICE)
                        itransfer->state_flags |= USBI_TRANSFER_DEVICE_DISAPPEARED;
@@ -1674,12 +1660,13 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
        struct libusb_transfer *transfer =
                USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
        struct libusb_device_handle *dev_handle = transfer->dev_handle;
+       struct libusb_context *ctx = ITRANSFER_CTX(itransfer);
        uint8_t flags;
        int r;
 
        r = remove_from_flying_list(itransfer);
        if (r < 0)
-               usbi_err(ITRANSFER_CTX(itransfer), "failed to set timer for next timeout");
+               usbi_err(ctx, "failed to set timer for next timeout");
 
        usbi_mutex_lock(&itransfer->lock);
        itransfer->state_flags &= ~USBI_TRANSFER_IN_FLIGHT;
@@ -1691,7 +1678,7 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
                if (transfer->type == LIBUSB_TRANSFER_TYPE_CONTROL)
                        rqlen -= LIBUSB_CONTROL_SETUP_SIZE;
                if (rqlen != itransfer->transferred) {
-                       usbi_dbg("interpreting short transfer as error");
+                       usbi_dbg(ctx, "interpreting short transfer as error");
                        status = LIBUSB_TRANSFER_ERROR;
                }
        }
@@ -1699,7 +1686,7 @@ int usbi_handle_transfer_completion(struct usbi_transfer *itransfer,
        flags = transfer->flags;
        transfer->status = status;
        transfer->actual_length = itransfer->transferred;
-       usbi_dbg("transfer %p has callback %p", transfer, transfer->callback);
+       usbi_dbg(ctx, "transfer %p has callback %p", transfer, transfer->callback);
        if (transfer->callback)
                transfer->callback(transfer);
        /* transfer might have been freed by the above call, do not use from
@@ -1727,7 +1714,7 @@ int usbi_handle_transfer_cancellation(struct usbi_transfer *itransfer)
 
        /* if the URB was cancelled due to timeout, report timeout to the user */
        if (timed_out) {
-               usbi_dbg("detected timeout cancellation");
+               usbi_dbg(ctx, "detected timeout cancellation");
                return usbi_handle_transfer_completion(itransfer, LIBUSB_TRANSFER_TIMED_OUT);
        }
 
@@ -1788,12 +1775,12 @@ int API_EXPORTED libusb_try_lock_events(libusb_context *ctx)
        ru = ctx->device_close;
        usbi_mutex_unlock(&ctx->event_data_lock);
        if (ru) {
-               usbi_dbg("someone else is closing a device");
+               usbi_dbg(ctx, "someone else is closing a device");
                return 1;
        }
 
        r = usbi_mutex_trylock(&ctx->events_lock);
-       if (r)
+       if (!r)
                return 1;
 
        ctx->event_handler_active = 1;
@@ -1880,7 +1867,7 @@ int API_EXPORTED libusb_event_handling_ok(libusb_context *ctx)
        r = ctx->device_close;
        usbi_mutex_unlock(&ctx->event_data_lock);
        if (r) {
-               usbi_dbg("someone else is closing a device");
+               usbi_dbg(ctx, "someone else is closing a device");
                return 0;
        }
 
@@ -1909,7 +1896,7 @@ int API_EXPORTED libusb_event_handler_active(libusb_context *ctx)
        r = ctx->device_close;
        usbi_mutex_unlock(&ctx->event_data_lock);
        if (r) {
-               usbi_dbg("someone else is closing a device");
+               usbi_dbg(ctx, "someone else is closing a device");
                return 1;
        }
 
@@ -1930,7 +1917,7 @@ void API_EXPORTED libusb_interrupt_event_handler(libusb_context *ctx)
 {
        unsigned int event_flags;
 
-       usbi_dbg(" ");
+       usbi_dbg(ctx, " ");
 
        ctx = usbi_get_context(ctx);
        usbi_mutex_lock(&ctx->event_data_lock);
@@ -1954,7 +1941,7 @@ void API_EXPORTED libusb_interrupt_event_handler(libusb_context *ctx)
  *
  * You only need to use this lock if you are developing an application
  * which calls poll() or select() on libusb's file descriptors directly,
- * <b>and</b> may potentially be handling events from 2 threads simultaenously.
+ * <b>and</b> may potentially be handling events from 2 threads simultaneously.
  * If you stick to libusb's event handling loop functions (e.g.
  * libusb_handle_events()) then you do not need to be concerned with this
  * locking.
@@ -2002,6 +1989,7 @@ void API_EXPORTED libusb_unlock_event_waiters(libusb_context *ctx)
  * indicates unlimited timeout.
  * \returns 0 after a transfer completes or another thread stops event handling
  * \returns 1 if the timeout expired
+ * \returns LIBUSB_ERROR_INVALID_PARAM if timeval is invalid
  * \ref libusb_mtasync
  */
 int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
@@ -2009,18 +1997,20 @@ int API_EXPORTED libusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
        int r;
 
        ctx = usbi_get_context(ctx);
-       if (tv == NULL) {
+       if (!tv) {
                usbi_cond_wait(&ctx->event_waiters_cond, &ctx->event_waiters_lock);
                return 0;
        }
 
+       if (!TIMEVAL_IS_VALID(tv))
+               return LIBUSB_ERROR_INVALID_PARAM;
+
        r = usbi_cond_timedwait(&ctx->event_waiters_cond,
                &ctx->event_waiters_lock, tv);
-
        if (r < 0)
-               return r;
-       else
-               return (r == ETIMEDOUT);
+               return r == LIBUSB_ERROR_TIMEOUT;
+
+       return 0;
 }
 
 static void handle_timeout(struct usbi_transfer *itransfer)
@@ -2035,24 +2025,19 @@ static void handle_timeout(struct usbi_transfer *itransfer)
                itransfer->timeout_flags |= USBI_TRANSFER_TIMED_OUT;
        else
                usbi_warn(TRANSFER_CTX(transfer),
-                       "async cancel failed %d errno=%d", r, errno);
+                       "async cancel failed %d", r);
 }
 
-static int handle_timeouts_locked(struct libusb_context *ctx)
+static void handle_timeouts_locked(struct libusb_context *ctx)
 {
-       int r;
        struct timespec systime;
        struct usbi_transfer *itransfer;
 
        if (list_empty(&ctx->flying_transfers))
-               return 0;
+               return;
 
        /* get current time */
-       r = usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &systime);
-       if (r < 0) {
-               usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno);
-               return LIBUSB_ERROR_OTHER;
-       }
+       usbi_get_monotonic_time(&systime);
 
        /* iterate through flying transfers list, finding all transfers that
         * have expired timeouts */
@@ -2061,7 +2046,7 @@ static int handle_timeouts_locked(struct libusb_context *ctx)
 
                /* if we've reached transfers of infinite timeout, we're all done */
                if (!TIMESPEC_IS_SET(cur_ts))
-                       return 0;
+                       return;
 
                /* ignore timeouts we've already handled */
                if (itransfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))
@@ -2069,31 +2054,28 @@ static int handle_timeouts_locked(struct libusb_context *ctx)
 
                /* if transfer has non-expired timeout, nothing more to do */
                if (TIMESPEC_CMP(cur_ts, &systime, >))
-                       return 0;
+                       return;
 
                /* otherwise, we've got an expired timeout to handle */
                handle_timeout(itransfer);
        }
-       return 0;
 }
 
-static int handle_timeouts(struct libusb_context *ctx)
+static void handle_timeouts(struct libusb_context *ctx)
 {
-       int r;
-
        ctx = usbi_get_context(ctx);
        usbi_mutex_lock(&ctx->flying_transfers_lock);
-       r = handle_timeouts_locked(ctx);
+       handle_timeouts_locked(ctx);
        usbi_mutex_unlock(&ctx->flying_transfers_lock);
-       return r;
 }
 
 static int handle_event_trigger(struct libusb_context *ctx)
 {
        struct list_head hotplug_msgs;
+       int hotplug_event = 0;
        int r = 0;
 
-       usbi_dbg("event triggered");
+       usbi_dbg(ctx, "event triggered");
 
        list_init(&hotplug_msgs);
 
@@ -2102,42 +2084,57 @@ static int handle_event_trigger(struct libusb_context *ctx)
 
        /* check if someone modified the event sources */
        if (ctx->event_flags & USBI_EVENT_EVENT_SOURCES_MODIFIED)
-               usbi_dbg("someone updated the event sources");
+               usbi_dbg(ctx, "someone updated the event sources");
 
        if (ctx->event_flags & USBI_EVENT_USER_INTERRUPT) {
-               usbi_dbg("someone purposefully interrupted");
+               usbi_dbg(ctx, "someone purposefully interrupted");
                ctx->event_flags &= ~USBI_EVENT_USER_INTERRUPT;
        }
 
+       if (ctx->event_flags & USBI_EVENT_HOTPLUG_CB_DEREGISTERED) {
+               usbi_dbg(ctx, "someone unregistered a hotplug cb");
+               ctx->event_flags &= ~USBI_EVENT_HOTPLUG_CB_DEREGISTERED;
+               hotplug_event = 1;
+       }
+
        /* check if someone is closing a device */
        if (ctx->event_flags & USBI_EVENT_DEVICE_CLOSE)
-               usbi_dbg("someone is closing a device");
+               usbi_dbg(ctx, "someone is closing a device");
 
        /* check for any pending hotplug messages */
        if (ctx->event_flags & USBI_EVENT_HOTPLUG_MSG_PENDING) {
-               usbi_dbg("hotplug message received");
+               usbi_dbg(ctx, "hotplug message received");
                ctx->event_flags &= ~USBI_EVENT_HOTPLUG_MSG_PENDING;
+               hotplug_event = 1;
                assert(!list_empty(&ctx->hotplug_msgs));
                list_cut(&hotplug_msgs, &ctx->hotplug_msgs);
        }
 
        /* complete any pending transfers */
        if (ctx->event_flags & USBI_EVENT_TRANSFER_COMPLETED) {
+               struct usbi_transfer *itransfer, *tmp;
+               struct list_head completed_transfers;
+
                assert(!list_empty(&ctx->completed_transfers));
-               while (r == 0 && !list_empty(&ctx->completed_transfers)) {
-                       struct usbi_transfer *itransfer =
-                               list_first_entry(&ctx->completed_transfers, struct usbi_transfer, completed_list);
+               list_cut(&completed_transfers, &ctx->completed_transfers);
+               usbi_mutex_unlock(&ctx->event_data_lock);
 
+               __for_each_completed_transfer_safe(&completed_transfers, itransfer, tmp) {
                        list_del(&itransfer->completed_list);
-                       usbi_mutex_unlock(&ctx->event_data_lock);
                        r = usbi_backend.handle_transfer_completion(itransfer);
-                       if (r)
+                       if (r) {
                                usbi_err(ctx, "backend handle_transfer_completion failed with error %d", r);
-                       usbi_mutex_lock(&ctx->event_data_lock);
+                               break;
+                       }
                }
 
-               if (list_empty(&ctx->completed_transfers))
+               usbi_mutex_lock(&ctx->event_data_lock);
+               if (!list_empty(&completed_transfers)) {
+                       /* an error occurred, put the remaining transfers back on the list */
+                       list_splice_front(&completed_transfers, &ctx->completed_transfers);
+               } else if (list_empty(&ctx->completed_transfers)) {
                        ctx->event_flags &= ~USBI_EVENT_TRANSFER_COMPLETED;
+               }
        }
 
        /* if no further pending events, clear the event */
@@ -2146,20 +2143,9 @@ static int handle_event_trigger(struct libusb_context *ctx)
 
        usbi_mutex_unlock(&ctx->event_data_lock);
 
-       /* process the hotplug messages, if any */
-       while (!list_empty(&hotplug_msgs)) {
-               struct libusb_hotplug_message *message =
-                       list_first_entry(&hotplug_msgs, struct libusb_hotplug_message, list);
-
-               usbi_hotplug_match(ctx, message->device, message->event);
-
-               /* the device left, dereference the device */
-               if (message->event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT)
-                       libusb_unref_device(message->device);
-
-               list_del(&message->list);
-               free(message);
-       }
+       /* process the hotplug events, if any */
+       if (hotplug_event)
+               usbi_hotplug_process(ctx, &hotplug_msgs);
 
        return r;
 }
@@ -2172,15 +2158,13 @@ static int handle_timer_trigger(struct libusb_context *ctx)
        usbi_mutex_lock(&ctx->flying_transfers_lock);
 
        /* process the timeout that just happened */
-       r = handle_timeouts_locked(ctx);
-       if (r < 0)
-               goto out;
+       handle_timeouts_locked(ctx);
 
        /* arm for next timeout */
        r = arm_timer_for_next_timeout(ctx);
 
-out:
        usbi_mutex_unlock(&ctx->flying_transfers_lock);
+
        return r;
 }
 #endif
@@ -2202,7 +2186,7 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
         * save the additional overhead */
        usbi_mutex_lock(&ctx->event_data_lock);
        if (ctx->event_flags & USBI_EVENT_EVENT_SOURCES_MODIFIED) {
-               usbi_dbg("event sources modified, reallocating event data");
+               usbi_dbg(ctx, "event sources modified, reallocating event data");
 
                /* free anything removed since we last ran */
                cleanup_removed_event_sources(ctx);
@@ -2229,12 +2213,16 @@ static int handle_events(struct libusb_context *ctx, struct timeval *tv)
        if (tv->tv_usec % 1000)
                timeout_ms++;
 
+       reported_events.event_bits = 0;
+
        usbi_start_event_handling(ctx);
 
        r = usbi_wait_for_events(ctx, &reported_events, timeout_ms);
        if (r != LIBUSB_SUCCESS) {
-               if (r == LIBUSB_ERROR_TIMEOUT)
-                       r = handle_timeouts(ctx);
+               if (r == LIBUSB_ERROR_TIMEOUT) {
+                       handle_timeouts(ctx);
+                       r = LIBUSB_SUCCESS;
+               }
                goto done;
        }
 
@@ -2319,7 +2307,9 @@ static int get_next_timeout(libusb_context *ctx, struct timeval *tv,
  * \param tv the maximum time to block waiting for events, or an all zero
  * timeval struct for non-blocking mode
  * \param completed pointer to completion integer to check, or NULL
- * \returns 0 on success, or a LIBUSB_ERROR code on failure
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_INVALID_PARAM if timeval is invalid
+ * \returns another LIBUSB_ERROR code on other failure
  * \ref libusb_mtasync
  */
 int API_EXPORTED libusb_handle_events_timeout_completed(libusb_context *ctx,
@@ -2328,18 +2318,22 @@ int API_EXPORTED libusb_handle_events_timeout_completed(libusb_context *ctx,
        int r;
        struct timeval poll_timeout;
 
+       if (!TIMEVAL_IS_VALID(tv))
+               return LIBUSB_ERROR_INVALID_PARAM;
+
        ctx = usbi_get_context(ctx);
        r = get_next_timeout(ctx, tv, &poll_timeout);
        if (r) {
                /* timeout already expired */
-               return handle_timeouts(ctx);
+               handle_timeouts(ctx);
+               return 0;
        }
 
 retry:
        if (libusb_try_lock_events(ctx) == 0) {
                if (completed == NULL || !*completed) {
                        /* we obtained the event lock: do our own event handling */
-                       usbi_dbg("doing our own event handling");
+                       usbi_dbg(ctx, "doing our own event handling");
                        r = handle_events(ctx, &poll_timeout);
                }
                libusb_unlock_events(ctx);
@@ -2357,11 +2351,11 @@ retry:
                /* 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(ctx);
-               usbi_dbg("event handler was active but went away, retrying");
+               usbi_dbg(ctx, "event handler was active but went away, retrying");
                goto retry;
        }
 
-       usbi_dbg("another thread is doing event handling");
+       usbi_dbg(ctx, "another thread is doing event handling");
        r = libusb_wait_for_event(ctx, &poll_timeout);
 
 already_done:
@@ -2370,9 +2364,8 @@ already_done:
        if (r < 0)
                return r;
        else if (r == 1)
-               return handle_timeouts(ctx);
-       else
-               return 0;
+               handle_timeouts(ctx);
+       return 0;
 }
 
 /** \ingroup libusb_poll
@@ -2399,7 +2392,7 @@ int API_EXPORTED libusb_handle_events_timeout(libusb_context *ctx,
 
 /** \ingroup libusb_poll
  * Handle any pending events in blocking mode. There is currently a timeout
- * hardcoded at 60 seconds but we plan to make it unlimited in future. For
+ * hard-coded at 60 seconds but we plan to make it unlimited in future. For
  * finer control over whether this function is blocking or non-blocking, or
  * for control over the timeout, use libusb_handle_events_timeout_completed()
  * instead.
@@ -2456,7 +2449,9 @@ int API_EXPORTED libusb_handle_events_completed(libusb_context *ctx,
  * \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
+ * \returns 0 on success
+ * \returns LIBUSB_ERROR_INVALID_PARAM if timeval is invalid
+ * \returns another LIBUSB_ERROR code on other failure
  * \ref libusb_mtasync
  */
 int API_EXPORTED libusb_handle_events_locked(libusb_context *ctx,
@@ -2465,11 +2460,15 @@ int API_EXPORTED libusb_handle_events_locked(libusb_context *ctx,
        int r;
        struct timeval poll_timeout;
 
+       if (!TIMEVAL_IS_VALID(tv))
+               return LIBUSB_ERROR_INVALID_PARAM;
+
        ctx = usbi_get_context(ctx);
        r = get_next_timeout(ctx, tv, &poll_timeout);
        if (r) {
                /* timeout already expired */
-               return handle_timeouts(ctx);
+               handle_timeouts(ctx);
+               return 0;
        }
 
        return handle_events(ctx, &poll_timeout);
@@ -2543,7 +2542,6 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
        struct usbi_transfer *itransfer;
        struct timespec systime;
        struct timespec next_timeout = { 0, 0 };
-       int r;
 
        ctx = usbi_get_context(ctx);
        if (usbi_using_timer(ctx))
@@ -2552,7 +2550,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
        usbi_mutex_lock(&ctx->flying_transfers_lock);
        if (list_empty(&ctx->flying_transfers)) {
                usbi_mutex_unlock(&ctx->flying_transfers_lock);
-               usbi_dbg("no URBs, no timeout!");
+               usbi_dbg(ctx, "no URBs, no timeout!");
                return 0;
        }
 
@@ -2561,7 +2559,7 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
                if (itransfer->timeout_flags & (USBI_TRANSFER_TIMEOUT_HANDLED | USBI_TRANSFER_OS_HANDLES_TIMEOUT))
                        continue;
 
-               /* if we've reached transfers of infinte timeout, we're done looking */
+               /* if we've reached transfers of infinite timeout, we're done looking */
                if (!TIMESPEC_IS_SET(&itransfer->timeout))
                        break;
 
@@ -2571,23 +2569,19 @@ int API_EXPORTED libusb_get_next_timeout(libusb_context *ctx,
        usbi_mutex_unlock(&ctx->flying_transfers_lock);
 
        if (!TIMESPEC_IS_SET(&next_timeout)) {
-               usbi_dbg("no URB with timeout or all handled by OS; no timeout!");
+               usbi_dbg(ctx, "no URB with timeout or all handled by OS; no timeout!");
                return 0;
        }
 
-       r = usbi_clock_gettime(USBI_CLOCK_MONOTONIC, &systime);
-       if (r < 0) {
-               usbi_err(ctx, "failed to read monotonic clock, errno=%d", errno);
-               return 0;
-       }
+       usbi_get_monotonic_time(&systime);
 
        if (!TIMESPEC_CMP(&systime, &next_timeout, <)) {
-               usbi_dbg("first timeout already expired");
+               usbi_dbg(ctx, "first timeout already expired");
                timerclear(tv);
        } else {
                TIMESPEC_SUB(&next_timeout, &systime, &next_timeout);
                TIMESPEC_TO_TIMEVAL(tv, &next_timeout);
-               usbi_dbg("next timeout in %ld.%06lds", (long)tv->tv_sec, (long)tv->tv_usec);
+               usbi_dbg(ctx, "next timeout in %ld.%06lds", (long)tv->tv_sec, (long)tv->tv_usec);
        }
 
        return 1;
@@ -2618,7 +2612,7 @@ void API_EXPORTED libusb_set_pollfd_notifiers(libusb_context *ctx,
        libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb,
        void *user_data)
 {
-#if !defined(_WIN32) && !defined(__CYGWIN__)
+#if !defined(PLATFORM_WINDOWS)
        ctx = usbi_get_context(ctx);
        ctx->fd_added_cb = added_cb;
        ctx->fd_removed_cb = removed_cb;
@@ -2658,7 +2652,7 @@ int usbi_add_event_source(struct libusb_context *ctx, usbi_os_handle_t os_handle
        if (!ievent_source)
                return LIBUSB_ERROR_NO_MEM;
 
-       usbi_dbg("add " USBI_OS_HANDLE_FORMAT_STRING " events %d", os_handle, poll_events);
+       usbi_dbg(ctx, "add " USBI_OS_HANDLE_FORMAT_STRING " events %d", os_handle, poll_events);
        ievent_source->data.os_handle = os_handle;
        ievent_source->data.poll_events = poll_events;
        usbi_mutex_lock(&ctx->event_data_lock);
@@ -2666,7 +2660,7 @@ int usbi_add_event_source(struct libusb_context *ctx, usbi_os_handle_t os_handle
        usbi_event_source_notification(ctx);
        usbi_mutex_unlock(&ctx->event_data_lock);
 
-#if !defined(_WIN32) && !defined(__CYGWIN__)
+#if !defined(PLATFORM_WINDOWS)
        if (ctx->fd_added_cb)
                ctx->fd_added_cb(os_handle, poll_events, ctx->fd_cb_user_data);
 #endif
@@ -2680,7 +2674,7 @@ void usbi_remove_event_source(struct libusb_context *ctx, usbi_os_handle_t os_ha
        struct usbi_event_source *ievent_source;
        int found = 0;
 
-       usbi_dbg("remove " USBI_OS_HANDLE_FORMAT_STRING, os_handle);
+       usbi_dbg(ctx, "remove " USBI_OS_HANDLE_FORMAT_STRING, os_handle);
        usbi_mutex_lock(&ctx->event_data_lock);
        for_each_event_source(ctx, ievent_source) {
                if (ievent_source->data.os_handle == os_handle) {
@@ -2690,7 +2684,7 @@ void usbi_remove_event_source(struct libusb_context *ctx, usbi_os_handle_t os_ha
        }
 
        if (!found) {
-               usbi_dbg("couldn't find " USBI_OS_HANDLE_FORMAT_STRING " to remove", os_handle);
+               usbi_dbg(ctx, "couldn't find " USBI_OS_HANDLE_FORMAT_STRING " to remove", os_handle);
                usbi_mutex_unlock(&ctx->event_data_lock);
                return;
        }
@@ -2700,7 +2694,7 @@ void usbi_remove_event_source(struct libusb_context *ctx, usbi_os_handle_t os_ha
        usbi_event_source_notification(ctx);
        usbi_mutex_unlock(&ctx->event_data_lock);
 
-#if !defined(_WIN32) && !defined(__CYGWIN__)
+#if !defined(PLATFORM_WINDOWS)
        if (ctx->fd_removed_cb)
                ctx->fd_removed_cb(os_handle, ctx->fd_cb_user_data);
 #endif
@@ -2725,7 +2719,7 @@ DEFAULT_VISIBILITY
 const struct libusb_pollfd ** LIBUSB_CALL libusb_get_pollfds(
        libusb_context *ctx)
 {
-#if !defined(_WIN32) && !defined(__CYGWIN__)
+#if !defined(PLATFORM_WINDOWS)
        struct libusb_pollfd **ret = NULL;
        struct usbi_event_source *ievent_source;
        size_t i;
@@ -2772,7 +2766,7 @@ out:
  */
 void API_EXPORTED libusb_free_pollfds(const struct libusb_pollfd **pollfds)
 {
-#if !defined(_WIN32) && !defined(__CYGWIN__)
+#if !defined(PLATFORM_WINDOWS)
        free((void *)pollfds);
 #else
        UNUSED(pollfds);
@@ -2789,7 +2783,7 @@ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle)
        struct usbi_transfer *cur;
        struct usbi_transfer *to_cancel;
 
-       usbi_dbg("device %d.%d",
+       usbi_dbg(ctx, "device %d.%d",
                dev_handle->dev->bus_number, dev_handle->dev->device_address);
 
        /* terminate all pending transfers with the LIBUSB_TRANSFER_NO_DEVICE
@@ -2824,7 +2818,7 @@ void usbi_handle_disconnect(struct libusb_device_handle *dev_handle)
                if (!to_cancel)
                        break;
 
-               usbi_dbg("cancelling transfer %p from disconnect",
+               usbi_dbg(ctx, "cancelling transfer %p from disconnect",
                         USBI_TRANSFER_TO_LIBUSB_TRANSFER(to_cancel));
 
                usbi_mutex_lock(&to_cancel->lock);