linux: Feature gate async runtime, allowing opting between Tokio or smol#27
Conversation
|
nice solution 👍 |
| tokio = ["rtnetlink/tokio_socket"] | ||
| smol_socket = ["rtnetlink/smol_socket"] |
There was a problem hiding this comment.
So what happens if I am on windows and activate the tokio feature flag?
There was a problem hiding this comment.
So, I tried compiling with default features, tokio and --no-default-features.
All compile normally and produce the same Cargo.lock.
Btw should we name the features as rtnetlink names them or generify to smol and tokio ?
There was a problem hiding this comment.
That is surprising to me. I would have expected cargo to choke on a feature that points to a dependency that is not present in the manifest for this target.
There was a problem hiding this comment.
I'd prefer if we just name them after the executor and drop the _socket.
by making smol the default `IfWatcher` and introducing `TokioIfWatcher`.
There was a problem hiding this comment.
Thanks! Couple of comments to ponder over :)
Is my understanding correct that rtnetlinks handling of sockets with this try_spawn_blocking stuff doesn't actually affect us because we are not using those APIs?
That is great news because I think it means we can actually fully encapsulate the way we enable executors without any upstream changes!
| tokio = ["rtnetlink/tokio_socket"] | ||
| smol_socket = ["rtnetlink/smol_socket"] |
There was a problem hiding this comment.
I'd prefer if we just name them after the executor and drop the _socket.
| The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), | ||
| and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). | ||
|
|
||
| ## [2.1.0] - [unreleased] |
There was a problem hiding this comment.
Missing version bump in Cargo.toml and it is also breaking atm because you are removing the IfWatcher symbol for linux :)
|
@jxs if I am not mistaken this is not blocked on anything, right? Not to rush, just to make sure you are not waiting on anyone's input. |
3a0c0ab to
7d6efc4
Compare
7d6efc4 to
4818613
Compare
| pub fn new() -> Result<Self> { | ||
| let (tx, rx) = mpsc::channel(1); | ||
| std::thread::spawn(|| background_task(tx)); | ||
| T::spawn(async { background_task(tx) }); |
There was a problem hiding this comment.
Spawning a non-async function is a bit odd. Can we make it async?
I think this will block the executor thread otherwise.
There was a problem hiding this comment.
I think this will block the executor thread otherwise.
interesting, why do you say this?
btw was able to test on a mac and confirm background_task's CFRunLoop::run_current() seems to run forever, and per tokio spawn_blocking doc for example:
This function is intended for non-async operations that eventually finish on their own. If you want to spawn an ordinary thread, you should use thread::spawn instead.
so we should probably maintain the plain old std::thread::spawn, wdyt?
There was a problem hiding this comment.
I think this will block the executor thread otherwise.
interesting, why do you say this?
Unless interrupted otherwise, a task will run on an executor thread until it yields, i.e. returns Poll::Pending.
async_std has a mechanism to detect blocked executor threads and spawn new ones: https://async.rs/blog/stop-worrying-about-blocking-the-new-async-std-runtime/
Tokio doesn't though and it is a conscious design decision AFAIK.
btw was able to test on a mac and confirm
background_task'sCFRunLoop::run_current()seems to run forever, and pertokiospawn_blockingdoc for example:This function is intended for non-async operations that eventually finish on their own. If you want to spawn an ordinary thread, you should use thread::spawn instead.
But you are not using spawn_blocking right? So how is that relevant?
so we should probably maintain the plain old
std::thread::spawn, wdyt?
Can we refactor this to be similar to the linux implementation where we register a waker and call it in a callback?
There was a problem hiding this comment.
Unless interrupted otherwise, a task will run on an executor thread until it yields, i.e. returns Poll::Pending.
async_std has a mechanism to detect blocked executor threads and spawn new ones: https://async.rs/blog/stop-worrying->about-blocking-the-new-async-std-runtime/
Tokio doesn't though and it is a conscious design decision AFAIK.
Right yeah, but a function just by not being async doesn't mean it will block the thread.
But you are not using spawn_blocking right? So how is that relevant?
because background_task's CFRunLoop::run_current() seems to run forever, therefore blocking the thread.
Can we refactor this to be similar to the linux implementation where we register a waker and call it in a callback?
Yeah I think so, but there still still need for a blocking thread as CFRunLoop::run_current() is blocking, while the Windows NotifyIpInterfaceChange isn't.
There was a problem hiding this comment.
Unless interrupted otherwise, a task will run on an executor thread until it yields, i.e. returns Poll::Pending.
async_std has a mechanism to detect blocked executor threads and spawn new ones: https://async.rs/blog/stop-worrying->about-blocking-the-new-async-std-runtime/
Tokio doesn't though and it is a conscious design decision AFAIK.Right yeah, but a function just by not being
asyncdoesn't mean it will block the thread.
That is correct. I think we are saying the same thing, it is CFRunLoop::run_current() that is the problem.
But you are not using spawn_blocking right? So how is that relevant?
because
background_task'sCFRunLoop::run_current()seems to run forever, therefore blocking the thread.Can we refactor this to be similar to the linux implementation where we register a waker and call it in a callback?
Yeah I think so, but there still still need for a blocking thread as
CFRunLoop::run_current()is blocking, while the WindowsNotifyIpInterfaceChangeisn't.
That really is unfortunate. I guess we will have to stick with a regular thread then for MacOS.
There was a problem hiding this comment.
That really is unfortunate. I guess we will have to stick with a regular thread then for MacOS.
yeah 😞 Reverted to an implementation similar to Windows ptal Thomas. Still, I think this approach makes sense and is more idiomatic the inicial one of overriding features
2efad4b to
ba8e1d4
Compare
to fix android ci build. It was failing with: `libif_watch.so` doesn't exist.
mxinden
left a comment
There was a problem hiding this comment.
Thanks for the thorough work on this.
Following #21 and confirming @dignifiedquire's #21 (comment), we still can't define features per target.
But it seems we can define features for dependencies, and then dependencies can be defined per target.
With that we can apply the similar technique
rtnetlinkuses to support both runtimes, with the difference that in our case assmol_socketis the default (to maintain backwards compatibility) we invert the feature combination and if both are enabledtokiotakes priority.Only downside that comes to mind with this approach is if someone uses
if-watchwithdefault-features = falsecrate compilation breaks (which is also the reason this change is technically a breaking change). We can usecompile_error!to give a better compilation error.CC @thomaseizinger