Skip to content
This repository has been archived by the owner on Oct 5, 2023. It is now read-only.

Commit

Permalink
hidapi/libusb/hid.c: fix race condition on device close (bug #5484)
Browse files Browse the repository at this point in the history
From hidapi mainstream git: libusb/hidapi#142
libusb/hidapi@d2c3a98

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.
  • Loading branch information
sezero committed Jan 19, 2021
1 parent dfe952e commit 78946cd
Showing 1 changed file with 10 additions and 8 deletions.
18 changes: 10 additions & 8 deletions src/hidapi/libusb/hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ struct hid_device_ {
SDL_cond *condition;
SDL_ThreadBarrier 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 @@ -823,13 +823,9 @@ static void LIBUSB_CALL 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 @@ -838,12 +834,17 @@ static void LIBUSB_CALL 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 @@ -886,6 +887,7 @@ static int read_thread(void *param)
res != LIBUSB_ERROR_TIMEOUT &&
res != LIBUSB_ERROR_OVERFLOW &&
res != LIBUSB_ERROR_INTERRUPTED) {
dev->shutdown_thread = 1;
break;
}
}
Expand All @@ -895,8 +897,8 @@ static int 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 78946cd

Please sign in to comment.