Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Asynchronous server loop
Note
Marking this as draft for now, due to severe test failures
If anyone comes by and sees this PR, and wants the functionality it provides, feel free to pick up development.
I don't think I'll be able to work on this for quite a while.
This depends on #31
This PR creates an alternative server loop, in which the incoming URB requests are handled in parallel. There are some kinds of devices which rely on this feature, where it might send several requests to different interfaces, or even just different endpoints on the same interface before the device will send the URB responses.
The flow would look something like this:
In order to solve this, I've made use of the async-scoped library, to allow us to keep API with the socket trait object from
UsbIpServer::handler
. If I've understood it correctly, this is because the trait object is not static and lives on the stack, while normal multithreaded async tokio requires everything to have a static lifetime, as it cannot provide any guarantees about how long the threads are going to live. The library solves this by providing unsafe async functions that assumes you've ensured the threads will be shut down before closing the scope.This library also seem to be part of the reason why the tests are failing. I am not exactly sure what is going on, but the
MockSocket
tests are flaky and the TCP Socket tests seem to crash or deadlock. I believe there is either one or more race conditions, which leads to the wakers potentially getting dropped. However, this only seems to be the test driver, as the implementation has been working with some basic interaction testing.The current design shares the socket between two threads, where one thread (the rx thread) is responsible for handling the incoming packages, and transferring responses to the other thread (the tx thread). The tx thread is responsible for sending all incoming messages. In the event that an
USBIP_CMD_SUBMIT
is requested, the rx thread will spin up a new thread for handling this request and then sending the response to the tx thread. This ensures the rx thread is ready to receive new requests, and can then spin up multipleUSBIP_CMD_SUBMIT
handler threads simultaneously.Breaking Changes
async-trait
andasync-scoped
UsbIpServer
has been remade into a traitUsbIpServer
has been renamed toSyncUsbIpServer
and is now namespaced beneathusbip::server
AsyncUsbIpServer
struct which implementsUsbIpServer
, also located atusbip::server
usbip
namespace (in earlierlib.rs
) has been moved into theUsbIpServer
traitSend
trait restriction to handlersocket
.Clone
restriction toUsbIpServer
, meaning theArc
is no longer required when working with it.Some remaining TODOs of varying importance:
async-trait
to upcoming rust async traits.unwrap()
sexplaining the difference between the implementations, and when to use which one.
USBIP_CMD_SUBMIT
handler threads in a cleaner way (there's nothing aborting them when rx/tx thread dies, they'll currently just die off on their own whenever the device is finished doing whatever it needs to)UsbIpServer::handler