summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libusb/io.c61
1 files changed, 33 insertions, 28 deletions
diff --git a/libusb/io.c b/libusb/io.c
index 2e1daf4..f08fe72 100644
--- a/libusb/io.c
+++ b/libusb/io.c
@@ -1703,12 +1703,13 @@ static int handle_timeouts(struct libusb_context *ctx)
return 0;
}
#else
-static int handle_timeouts_locked(struct libusb_context *ctx)
+static int handle_timeouts(struct libusb_context *ctx)
{
int r;
struct timespec systime_ts;
struct timeval systime;
- struct usbi_transfer *transfer;
+ struct usbi_transfer *transfer, *to_handle;
+ USBI_GET_CONTEXT(ctx);
if (list_empty(&ctx->flying_transfers))
return 0;
@@ -1721,39 +1722,43 @@ static int handle_timeouts_locked(struct libusb_context *ctx)
TIMESPEC_TO_TIMEVAL(&systime, &systime_ts);
/* iterate through flying transfers list, finding all transfers that
- * have expired timeouts */
- list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
- struct timeval *cur_tv = &transfer->timeout;
+ * have expired timeouts. Same trick as usbi_handle_disconnect() so
+ * that usbi_handle_transfer_cancellation() can be called in cancel()
+ * on the backend. */
+ while (1) {
+ to_handle = NULL;
+ pthread_mutex_lock(&ctx->flying_transfers_lock);
- /* if we've reached transfers of infinite timeout, we're all done */
- if (!timerisset(cur_tv))
- return 0;
+ list_for_each_entry(transfer, &ctx->flying_transfers, list, struct usbi_transfer) {
+ struct timeval *cur_tv = &transfer->timeout;
- /* ignore timeouts we've already handled */
- if (transfer->flags & USBI_TRANSFER_TIMED_OUT)
- continue;
+ /* if we've reached transfers of infinite timeout, we're all done */
+ if (!timerisset(cur_tv))
+ break;
- /* if transfer has non-expired timeout, nothing more to do */
- if ((cur_tv->tv_sec > systime.tv_sec) ||
- (cur_tv->tv_sec == systime.tv_sec &&
- cur_tv->tv_usec > systime.tv_usec))
- return 0;
-
+ /* ignore timeouts we've already handled */
+ if (transfer->flags & USBI_TRANSFER_TIMED_OUT)
+ continue;
+
+ /* if transfer has non-expired timeout, nothing more to do */
+ if ((cur_tv->tv_sec > systime.tv_sec) ||
+ (cur_tv->tv_sec == systime.tv_sec &&
+ cur_tv->tv_usec > systime.tv_usec))
+ break;
+
+ to_handle = transfer;
+ break;
+ }
+ pthread_mutex_unlock(&ctx->flying_transfers_lock);
+
+ if (!to_handle)
+ break;
+
/* otherwise, we've got an expired timeout to handle */
- handle_timeout(transfer);
+ handle_timeout(to_handle);
}
return 0;
}
-
-static int handle_timeouts(struct libusb_context *ctx)
-{
- int r;
- USBI_GET_CONTEXT(ctx);
- pthread_mutex_lock(&ctx->flying_transfers_lock);
- r = handle_timeouts_locked(ctx);
- pthread_mutex_unlock(&ctx->flying_transfers_lock);
- return r;
-}
#endif
#ifdef USBI_TIMERFD_AVAILABLE