-
Notifications
You must be signed in to change notification settings - Fork 397
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
Deadlock prevention patch for Connection-callback feature #676
Deadlock prevention patch for Connection-callback feature #676
Conversation
The hotplug thread in all 4 implementations goes through all callbacks on every iteration of it's loop to see if any were marked for removal. This consumes a ton of CPU power in that thread. I am going to add an additional flag to mark if the check is needed at all. Returning the draft status. In hindsight, it could've been a better idea to use bit fields for some of the flags in the context structure, unless this practice is frowned upon. Will be doing that in a moment. Additionally, added the cleanup procedure to the Register call anyway. Theoretically, there is nothing that would make removal of a callback by it's return value impossible if it gets cancelled inside a Register call. The only reason it would not work right now is because the documentation dictates so. |
All done. If needed, I can write a simple test code that does a few operations with the callbacks that would inevitably cause undefined behavior on the old implementations (including the original Windows implementation by @DJm00n ). However, a debugger would be needed to see what's going on on the inside. |
That would be great. I can carry out some tests with the test code. I was testing libusb Windows hotplug PR but the issue is a lack of good test utility. |
Here is the exploit piece (not the full testing application code, just the "important" bit). This should trigger the postponing mechanism in the PR, and cause undefined behavior in the original on Windows and deadlock on Linux, if at least 1 HID device is present.
|
@mcuee found a typo that prevented the tests on Linux from receiving input. Found a couple of errors that caused a segfault with libusb backend and a deadlock with hidraw backend, both in the cleanup sequence. Fixed them, I think this should do it. There are ways to make the implementation better (the hotplug thread shutdown for HIDRAW may still cause issues - theoretically), but for now this is the best I can write. As for windows, I accidentally broke my debugger installation :( |
Now I get the same segfault results under macOS. Simple step to reproduce, press Run log
|
Minor thing for the test, it is better to echo the option chosen by the user ( |
No crash under Linux, tested under Ubuntu 20.04.
|
I apologize for the delay, suddenly got a ton of things to take care of. |
Windows debugger is still causing me trouble, reinstalling my IDE now. |
For some reason it crashes in |
it was |
@mcuee I took care of that too 👌 |
Good. Now it no longer crashes under VS2019, Windows 10.
|
Dynamic Hotplug Test: remove the Dell dock and then insert back the Dell dock (with multiple HID devices). Looks good.
|
@DJm00n It would be great if you could review this PR as well! |
Resolved conflicts with the latest commit that got into the connection-callback branch. |
If any reviews/additional fixes - will be applied with additional PR. |
This PR provides a solution to the possible issues that happen when a register or de-register call is made from inside a callback. The way it works is the same for all platforms and is described below.
Resolves #673
Themutex_ready
variable is renamed tomutex_state
, it is no longer a boolean value, and the value of 2 in it now indicates that the mutex is "In Use" (locked by a function that calls a callback).mutex_ready
kept intact, added 2 more flags,mutex_in_use
andcb_list_dirty
.When the value of mutex_state is set to 2,When themitex_in_use
flag is set, the Deregister call is no longer allowed to immediately remove any callbacks from the list. Instead, theevents
field in the callback is set to 0, which makes it "invalid", as it will no longer match any events, and thecb_list_dirty
flag is set to 1 to indicate that the list needs to be checked for invalid events later.cb_list_dirty
flag is set, the list of callbacks is checked for any callbacks marked for removal (events
field set to 0), and those are only removed after all the processing is finished.HID_API_HOTPLUG_ENUMERATE
is specified,themutex_state
variable is set to 2 before it is called, while the old value is preserved and restored later.mutex_in_use
flag is set to prevent callback removal in that new callback.For extra safety, no callbacks are removed from the list at the end of processing in the Register call, even if there are no valid callbacks left.Fixed.