Skip to content

Commit

Permalink
libusb: fix race condition on device close (#189)
Browse files Browse the repository at this point in the history
Read callback may fire itself on its own even after its been
requested to stop and exactly before the calling code
waits for its completion in indefinite loop.

Explicitly preventing re-fireing the submission loop,
fixes the issue.

Fixes: #142.

Signed-off-by: Ihor Dutchak <ihor.youw@gmail.com>
  • Loading branch information
Youw committed Nov 23, 2020
1 parent 88c60e9 commit 1f64764
Showing 1 changed file with 10 additions and 8 deletions.
18 changes: 10 additions & 8 deletions libusb/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ struct hid_device_ {
pthread_cond_t condition;
pthread_barrier_t barrier; /* Ensures correct startup sequence */
int shutdown_thread;
int cancelled;
int transfer_loop_finished;
struct libusb_transfer *transfer;

/* List of received input reports. */
Expand Down Expand Up @@ -787,13 +787,9 @@ static void read_callback(struct libusb_transfer *transfer)
}
else if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
dev->shutdown_thread = 1;
dev->cancelled = 1;
return;
}
else if (transfer->status == LIBUSB_TRANSFER_NO_DEVICE) {
dev->shutdown_thread = 1;
dev->cancelled = 1;
return;
}
else if (transfer->status == LIBUSB_TRANSFER_TIMED_OUT) {
//LOG("Timeout (normal)\n");
Expand All @@ -802,12 +798,17 @@ static void read_callback(struct libusb_transfer *transfer)
LOG("Unknown transfer code: %d\n", transfer->status);
}

if (dev->shutdown_thread) {
dev->transfer_loop_finished = 1;
return;
}

/* Re-submit the transfer object. */
res = libusb_submit_transfer(transfer);
if (res != 0) {
LOG("Unable to submit URB. libusb error code: %d\n", res);
dev->shutdown_thread = 1;
dev->cancelled = 1;
dev->transfer_loop_finished = 1;
}
}

Expand Down Expand Up @@ -850,6 +851,7 @@ static void *read_thread(void *param)
res != LIBUSB_ERROR_TIMEOUT &&
res != LIBUSB_ERROR_OVERFLOW &&
res != LIBUSB_ERROR_INTERRUPTED) {
dev->shutdown_thread = 1;
break;
}
}
Expand All @@ -859,8 +861,8 @@ static void *read_thread(void *param)
if no transfers are pending, but that's OK. */
libusb_cancel_transfer(dev->transfer);

while (!dev->cancelled)
libusb_handle_events_completed(usb_context, &dev->cancelled);
while (!dev->transfer_loop_finished)
libusb_handle_events_completed(usb_context, &dev->transfer_loop_finished);

/* Now that the read thread is stopping, Wake any threads which are
waiting on data (in hid_read_timeout()). Do this under a mutex to
Expand Down

0 comments on commit 1f64764

Please sign in to comment.