hidapi
hidapi copied to clipboard
reading and writing from different threads in linux - or how to avoid busy loop polling
I have a device which both reports events and can have state set. It's a USB HID speakerphone.
For example, to make it ring you have to send it something, then if the user presses answer or hangup it sends something back - BUT the call could drop in the meantime, and we still need to be able to send "stop ringing" even while we are waiting for a keypress.
I can't figure out how this can be done while keeping read and write "synchronized" (in the Java sense) and without doing non blocking read (i.e. busy looping) etc. A slight improvement on busy looping would be read with timeout. That mitigates the busy looping to some degree but adds a latency in handling one of the two events.
The traditional non-threaded model would be to use UNIX select(), but there is no file descriptor to select on.
How can this be done?
I'm not sure anyone besides yourself can determine the single best answer for your product, but my approach to this is to have a single "busy looping" thread processing all reads and writes. Other threads can put writes onto a queue, and anytime the read-write thread comes around and is not currently serving a write request, it dequeues the next write and calls hid_write with it. I call hid_read_timeout on every iteration of the read-write loop regardless of the device state. The timeout duration was determined by the nominal HID processing loop duration on the device, which was determined by the firmware developer (not me, but another developer at my company).
Another approach for your case might be to set a timer event that calls hid_read periodically. That would be less CPU-intensive than a busy loop. Of course, hid_read_timeout takes the pressure off the CPU during the I/O wait time, so the result is effectively the same.
@amullins83 : Thanks. That's almost exactly what I did. I don't know anything about the "nominal HID processing loop duration" - I'm very new to the world of USB device programming and HID so this is my first attempt.
I used a 250ms timeout and it seems to react fairly decently to host-side events.
I had also implemented an interface to the device using /dev/hidraw device on linux, and that implementation had no such limitations, so I know the limitation is not in the actual kernel/device but in the API so I was hoping that I had missed something.
All of the aforementioned approaches are really just work-arounds. The portable (think: POSIX) way of non-blocking access is via file descriptors. We should have a way to access these. https://github.com/signal11/hidapi/issues/210 is also about this, its author unfortunately abandoned hidapi rather than cooking a patch.