New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Race condition in event-handling thread example #1291
Comments
From libusb_handle_events:
Maybe the documentation should indeed be updated. |
BTW: I've never seen any hangs when closing the device in HIDAPI and it uses libusb_handle_events. |
How would I use I would like to implement an event thread that forcibly processes all events, i.e. even when I use synchronous I/O functions on other threads, those should never do the event processing and call the callbacks; those should always come from my "main" event handling thread. Therefore, I thought I could lock the event lock permanently in this thread to stop other threads from processing and run |
PS: Isn't there also a race condition in The other thread could try to acquire the event lock before setting Perhaps we need to refactor the "completed" interface, as this also caused #1263. Perhaps there should be a dedicated mutex protecting access to the Define an opaque data structure for signaling completion: struct libusb_completion_signal {
int completed;
usbi_mutex_t mutex;
}; Give API users a way to set it to complete (which can then be called from all contexts, including other threads): void libusb_signal_completion (struct libusb_context *ctx, struct libusb_completion_signal* completion_signal) {
usbi_mutex_lock (&completion_signal->mutex);
completion_signal->completed = 1;
usbi_mutex_unlock (&completion_signal->mutex);
usbi_signal_event(&ctx->event);
} And then, change int API_EXPORTED libusb_handle_events_timeout_completed(libusb_context *ctx,
struct timeval *tv, struct libusb_completion_signal *completion_signal)
{
int completed = 0;
...
retry:
if (completion_signal != NULL) {
usbi_mutex_lock (&sign->mutex);
completed = completion_signal->completed;
usbi_mutex_unlock (&sign->mutex);
}
if (libusb_try_lock_events(ctx) == 0) {
if (!completed) {
/* we obtained the event lock: do our own event handling */
usbi_dbg(ctx, "doing our own event handling");
r = handle_events(ctx, &poll_timeout);
}
libusb_unlock_events(ctx);
return r;
}
... The We could then even revert #1267 but instead call This would also make it easy to quit an event-handling thread at any point in time, even if no devices are open at all (thereby obviating the need for the Is that a remotely good idea? |
How do you like the enhancement idea from @Erlkoenig90? Please help to comment when you have some time. Thanks. |
In the documentation for implementing event handling threads, the example code about quitting such a thread without using hotplug has a race condition that can lead to the thread not quitting immediately, but running into the internal timeout (60sec), possibly freezing an application upon quitting.
The proposed event handling thread:
When this thread's execution is right after the check to
event_thread_run
and before the call tolibusb_handle_events
, and then another thread calls the proposedmy_close_handle
function, the event handling thread will still enterlibusb_handle_events
which doesn't see anything to do (as no devices are open anymore) and will then run until the internal timeout of 60sec expires.Does this mean there is currently no safe race-free way to quit an event-handling thread? Perhaps we need a way to send/dispatch custom callbacks to the currently executing event loop. This could be used to send a "quit" message to the event handling thread, which could set
event_thread_run
and therefore quit the event handling thread immediately and safely.The text was updated successfully, but these errors were encountered: