-
Notifications
You must be signed in to change notification settings - Fork 65
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
Lockup with USBPollerThread #16
Comments
I think the first step would be to check exactly where both threads are at when deadlocking. I think there are 3 places which call into libusb which may lock:
I am surprised to discover a new-ish section about a polling thread in libusb(x) asyncio API documentation which shows a much simpler version of the handling loop without mentioning whether it is compatible with synchronous API. @jwrdegoede : I think you added this paragraph. Is described event loop synchronous-API-compatible ? Would there be any serious reason to think some libusb internal change would have broken the older, more complex recommended way to implement such loop ? That page does mention that the event thread should be started after opening the first device and stopped before closing it. Just in case it also applies to the older/synchronous-compatible (not sure which apply here) approach, could you call |
Hi, On 13-06-16 02:41, Vincent Pelletier wrote:
Yes I added that bit to the docs, mostly to document how to cleanly exit such a loop. Note that for 1.0.21 I'm using such a loop with async functions only, but I see no reasons why it cannot work with sync functions,
I'm not sure what you mean with the older more complex way. If you read: http://libusb.sourceforge.net/api-1.0/group__poll.html Which I did not touch, it already gives you 2 options, with the simple In essence that is what my suggestion does, by using a dedicated thread, The other option described there with all the pollfd stuff + timeout-handling etc., Do note that using a separate thread means that your call-back functions need to As for your deadlock you may be hitting an issue introduced in 1.0.20, for https://github.com/jwrdegoede/libusbx/commits/master Which has a bunch of pending locking fixes. Chances are you are not hitting Or for something closer to v1.0.20: https://github.com/jwrdegoede/libusbx/commits/v1.0.20-fixes Regards, Hans
|
It is hard to debug, but I have some strace and ltrace logs. The main thread hangs in controlWrite, while the event was handled by the event handler thread. After a minute the main thread times out and continues. According to strace, the first thread hangs in futex(); I think it is relevant strace (1878 main thread, 1886 USB poller):
|
I mean this beast: http://libusb.sourceforge.net/api-1.0/mtasync.html#threadwait This is what I implemented in this python wrapper, as it describes that having a handler loop in a thread and a synchronous USB call (say, a bulk read), the handler loop could "steal" the completion event and let the synchronous call wait for an event which will the never arrive (I didn't check the code, and maybe I misunderstood the doc - or mis-remember it now as I did not re-read it entirely). Such issue does not exist at all if one only uses the async API. About thread-safety, thankfully (despite the Giant Interpreter Lock not being too popular) python takes care of this for us, so that's not a problem here.
Good idea to use ltrace/strace. Could you try building libusb from @jwrdegoede 's repository and try to reproduce with it, as he reported there is a known deadlock regression in 1.0.20 ? python-libusb1 honours OS's library lookup order: LD_LIBRARY_PATH for linux, something similar but with another name for OSX, and I think windows looks in the current directory before going to C:\Windows\System32 (or whatever it is nowadays). |
Hi, On 13-06-16 15:57, Vincent Pelletier wrote:
Ah, we need to remove that, that is no longer true. All the libusb sync functions Patches welcome ... Regards, Hans |
Hi, On 13-06-16 16:03, Hans de Goede wrote:
Never-mind, that section actually is correct. But this is talking about taking "You must take the events lock before polling libusb file descriptors, using libusb_lock_events(). You must release the lock as soon as you have aborted your poll()/select() loop, using libusb_unlock_events()." So you see this is only relevant if you're doing fd polling yourself, if If you look a couple of lines above the bit of the docs you're referring TL;DR: The complicated method you referring to is only necessary if Or to quote the docs: " Closing remarks The above may seem a little complicated, but hopefully I have made it clear why such complications are necessary. Also, do not forget that this only applies to applications that take libusb's file descriptors and integrate them into their own polling loops." Regards, Hans |
@jwrdegoede: So, two potential good news: python-libusb1 will get simpler (if I can remember exactly why I did it this way and changing it does not break stuff), and the deadlock/timeout reported here may be a known 1.0.20 issue (if confirmed by @jhoenicke ). |
@vpelletier Hello. I'm faced with same issue. |
@vpelletier When I tried to use another way (threading.Thread and event_thread_run, USBTransferHelper) no use USBPollerThread all OK (libusb 1.0.21 from LP Zesty, libusb1-1.6.2). |
Thanks for the update, this is indeed what I considered suggesting: if you do not actually need to poll other descriptors, this approach is indeed much simpler (hence less likely to have bugs). But I also want to reproduce this issue now that I have a usb device running linux - which makes testing python-libusb1 much easier (well, which should eventually make it easier, if functionfs and gadget-mode controller drivers did not fail so much). |
@eldarkg , @jhoenicke : What type of polling object did you pass to USBPollerThread ? If "poll", then I now see the deadlock: python poll object exposes |
@vpelletier Yes, I used the select.poll object. |
@vpelletier Why you want to deprecate USBPollerThread? Maybe need wrap this to USBPollerThread. It will be good helper. |
Because its job is to poll non-libusb descriptors, only abstracting the libusb descriptor dance. It was not intended to be used where the simpler loop would do. From there:
OTOH, maybe I should extend USBPoller to:
|
@vpelletier OK. Thank you for info |
After a bit over 3 years and 8 releases with a deprecation warning, libusb1 is now checking the result of its mutex de-allocation calls. When this thread has been able to acquire the event lock this mutex will fail when libusb1 tries to free it, as it is acquired. Releasing it requires the poller thread to be able to terminate before Most of this could be saved by converting pairs of acquisition/release methods into context managers so the lock release codepath does not need to acquire the context pointer mutex, which would bloat the API further and still not solve the fundamental lockup issue reported here, and caused by using any poller other than linux-only epoll. I am hence:
|
Released as 1.9 . |
the hack in checkPhase is no longer needed since the issue has been resolved: vpelletier/python-libusb1#16
As mentioned in the pull request for Hantek 6022 library, I have a problem with the USBPollerThread and synchronous API. The synchronous API will not be woken up if the event is handled by the poller thread and the call continues only after a timeout.
This happens with Ubuntu 16.04, libusb-1.0.20-1, libusb1-1.5.0
Any ideas how to test this further?
Minimal test program (for a hantek 6022):
The text was updated successfully, but these errors were encountered: