/* 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_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 */
static inline void list_cut(struct list_head *list, struct list_head *head)
{
- if (list_empty(head))
+ if (list_empty(head)) {
+ list_init(list);
return;
+ }
list->next = head->next;
list->next->prev = list;
list_init(head);
}
+static inline void list_splice_front(struct list_head *list, struct list_head *head)
+{
+ list->next->prev = head;
+ list->prev->next = head->next;
+ head->next = list->next;
+}
+
static inline void *usbi_reallocf(void *ptr, size_t size)
{
void *ret = realloc(ptr, size);
#define for_each_open_device(ctx, h) \
for_each_helper(h, &(ctx)->open_devs, struct libusb_device_handle)
+#define __for_each_transfer(list, t) \
+ for_each_helper(t, (list), struct usbi_transfer)
+
#define for_each_transfer(ctx, t) \
- for_each_helper(t, &(ctx)->flying_transfers, struct usbi_transfer)
+ __for_each_transfer(&(ctx)->flying_transfers, t)
+
+#define __for_each_transfer_safe(list, t, n) \
+ for_each_safe_helper(t, n, (list), struct usbi_transfer)
#define for_each_transfer_safe(ctx, t, n) \
- for_each_safe_helper(t, n, &(ctx)->flying_transfers, struct usbi_transfer)
+ __for_each_transfer_safe(&(ctx)->flying_transfers, t, n)
#define for_each_event_source(ctx, e) \
for_each_helper(e, &(ctx)->event_sources, struct usbi_event_source)
struct pollfd *pollfd = &fds[n];
struct libusb_device_handle *handle;
struct linux_device_handle_priv *hpriv = NULL;
+ int reap_count;
if (!pollfd->revents)
continue;
continue;
}
+ reap_count = 0;
do {
r = reap_for_handle(handle);
- } while (r == 0);
+ } while (r == 0 && ++reap_count <= 25);
+
if (r == 1 || r == LIBUSB_ERROR_NO_DEVICE)
continue;
else if (r < 0)
-#define LIBUSB_NANO 11552
+#define LIBUSB_NANO 11553