implement asynchronous bulk/control transfers#153
Conversation
|
Can we split this in to two PR. I mostly OK with replace |
Sure, sounds good to me. |
|
About async. I want made async in separate crate(as in #143). So can you just create PR with separate crate. You can use |
|
|
||
| fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| // Poll libusb for any complete events. | ||
| if let Err(e) = self.context.handle_events(Some(Duration::from_micros(0))) { |
There was a problem hiding this comment.
This doesn't belong here.
When the transfer is not ready, it is poll's responsibility to save the waker and arrange for it to be woken when the event loop should poll your future again. You save the waker on the transfer and wake it from libusb's completion callback. But where does libusb check for events and call the completion callback? Yep, that's what libusb_handle_events and variants are for. So you need to call it somewhere other than poll so that libusb can call the callback, callback can wake the waker, and let the executor know that it has to call poll.
You have two options:
- Require a dedicated background thread that loops calling
libusb_handle_eventsin blocking mode. - If you don't want a background thread and don't need Windows support, you can do the complicated dance to get a set of file descriptors from libusb in a thread safe manner, and arrange for tokio/mio to poll them. When that reports a ready fd, then call
handle_eventsin nonblocking mode.
This PR mostly draws inspiration from: this comment, PR #143, Multi-threaded applications and asynchonrous I/O.
InnerTransferandTransferlike in this comment.NonNull<libusb_transfer>and implementsSendsuch it can be sent across threads, since it is effectively guarded by anArc<Mutex<T>>.CancellationTokenthat can be constructed fromTransfer, such that the transfer can be cancelled from other tasks.UsbContext::handle_events()with a thread-safe version as implemented by PR First try rusb-async #143 (and as described by the libusb documentation).handle_events()does not make any progress when the timeout is zero.LIBUSB_CONTROL_SETUP_SIZEasCONTROL_SETUP_SIZEas users of USB control packets need to allocate buffers with at leastCONTROL_SETUP_SIZEbytes to store the control request setup header.This integrates nicely with tokio, but should be agnostic of the run-time used since it just relies on the
stdcrate for futures, i.e. any asynchronous executor should work.I have tried this with a device that supports USB control packets and it seems to work nicely. However, I don't have any experience with isochronous packets, so this PR does not implement that part.