-
Notifications
You must be signed in to change notification settings - Fork 29
linux: Feature gate async runtime, allowing opting between Tokio or smol #27
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
Conversation
|
nice solution 👍 |
Cargo.toml
Outdated
| tokio = ["rtnetlink/tokio_socket"] | ||
| smol_socket = ["rtnetlink/smol_socket"] |
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.
So what happens if I am on windows and activate the tokio feature flag?
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.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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!
Cargo.toml
Outdated
| tokio = ["rtnetlink/tokio_socket"] | ||
| smol_socket = ["rtnetlink/smol_socket"] |
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.
I'd prefer if we just name them after the executor and drop the _socket.
CHANGELOG.md
Outdated
| 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing version bump in Cargo.toml and it is also breaking atm because you are removing the IfWatcher symbol for linux :)
mxinden
left a comment
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.
Thanks for looking into this @jxs!
|
@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
src/apple.rs
Outdated
| 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
thomaseizinger
left a comment
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.
Thanks, LGTM!
mxinden
left a comment
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.
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