-
Notifications
You must be signed in to change notification settings - Fork 85
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
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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_events
in 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_events
in nonblocking mode.
This PR mostly draws inspiration from: this comment, PR #143, Multi-threaded applications and asynchonrous I/O.
InnerTransfer
andTransfer
like in this comment.NonNull<libusb_transfer>
and implementsSend
such it can be sent across threads, since it is effectively guarded by anArc<Mutex<T>>
.CancellationToken
that 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_SIZE
asCONTROL_SETUP_SIZE
as users of USB control packets need to allocate buffers with at leastCONTROL_SETUP_SIZE
bytes 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
std
crate 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.