-
Notifications
You must be signed in to change notification settings - Fork 414
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
Windows hotplug: Mutex for callback actions #646
Windows hotplug: Mutex for callback actions #646
Conversation
87a8bc6
to
04d2eba
Compare
@DJm00n Could you have a look on the code in this PR? |
@DJm00n all suggestions applied, thank you! |
Just noticed that the cleanup code on exit won't really do anything if any callbacks are still armed; going to fix that in a moment. |
windows/hid.c
Outdated
@@ -943,24 +1010,23 @@ DWORD WINAPI hid_internal_notify_callback(HCMNOTIFICATION notify, PVOID context, | |||
return ERROR_SUCCESS; | |||
} | |||
|
|||
device = hid_internal_get_device_info(event_data->u.DeviceInterface.SymbolicLink, read_handle); | |||
device = hid_internal_get_device_info(event_data->u.DeviceInterface.SymbolicLink, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need of newline here
Would it be fine to throw in a small change for the hidtest (in the hotplug testing section)? Ran some tests, had to add this in, with it everything seems to work. UPD: added the change. Should help with testing the events with the added mutex. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apart from the formatting issues: is there're a specific reason to init/deinit the hotplug routines during hid_init/hid_exit?
can we initialize the whoe thing only when hid_hotplug_register_callback
is called?
that way there would be less overhead for those users (all up until now) who don't use the hotplug API yet
The main reason here is allowing the register/deregister functions being called from multiple threads simultaneously. This is the original reason to add the mutex at all, and, unfortunately, the mutex has to be initialized somewhere before use. hid_init seemed like the most reasonable place to do so, as the chance of getting a second call to it from a different thread at the same time (before the mutex is initialized) is negligible. If we happen to get two simultaneous register calls from two different threads with an uninitialized mutex, both could attempt to make a new one, which would lead to either thread locking a different mutex, from where we can encounter all sorts of weird behaviors, including possible memory leak scenarios where the first cached device list is leaked, or one of the callbacks is lost. I believe the mutex initialization overhead to be a sacrifice small enough to ignore. UPD: I found a way to avoid the mutex initialization with critical sectiona, investigating. |
I have to apoligize for not asking this earlier: why do we even need to allow calling register/deregister functions from different threads? hid_init/hid_exit<->hid_enumerate<->hid_open/hid_open_path/hid_close are not thread-safe in general case (as per my testing on 4 platforms) and I don't see good reason why making register/deregister functions as thread safe Originally I assumed that mutex is needed for some kind of data syncronisation internally and I didn't actually payed attention to what actually was being done. |
That too, by the way, the events are processed in a background thread, and the register calls can potentially interfere with the processing. If we don't want to ensure the register/deregister call safety, I could move the initialization to the register function. However, I don't know how good of an idea it would be to deinitialize it in the deregister function, need to think on that for a bit. |
go for it
I see two trade offs here:
NOTE: in any case, user may not call deregister function at all, and that could be fine, i.e. More than that - multiple calls to deregister has to be safe (for the similar reason why |
Took the asymmetric approach. The register call now initializes the synchronization. It is only deleted in hid_exit. We lose nothing by keeping it initialized. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks very good.
The only thing needs fixing (apart of one of my last comments) is the formatting. I'm ready to fix it myself at some point.
Simple test results seem to be good. Tested under Windows.
test using hidtest
|
9a098b2
to
a015e6e
Compare
Testing again under Windows 10 Dell Laptop to make sure it works -- the results are good.
|
Another test with WIndows 11 Acer laptop and it is also good.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am looking forward of this getting merged :)
Resolves #538