Skip to content
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

add task::LocalSet API for running !Send futures #1733

Merged
merged 76 commits into from Nov 27, 2019
Merged

Conversation

hawkw
Copy link
Member

@hawkw hawkw commented Nov 5, 2019

Motivation

In earlier versions of tokio, the current_thread::Runtime type could
be used to run !Send futures. However, PR #1716 merged the
current-thread and threadpool runtimes into a single type, which can no
longer run !Send futures. There is still a need in some cases to
support futures that don't implement Send, and the tokio-compat
crate requires this in order to provide APIs that existed in tokio
0.1.

Solution

This branch implements the API described by @carllerche in
#1716 (comment). It
adds a new LocalSet type and spawn_local function to tokio::task.
The LocalSet type is used to group together a set of tasks which must
run on the same thread and don't implement Send. These are available
when a new "rt-util" feature flag is enabled.

Currently, the local task set is run by passing it a reference to a
Runtime and a future to block_on. In the future, we may also want
to investigate allowing spawned futures to construct their own local
task sets, which would be executed on the worker that the future is
executing on.

In order to implement the new API, I've made some internal changes to
the task module and Schedule trait to support scheduling both Send
and !Send futures.

@hawkw hawkw added the C-enhancement Category: A PR with an enhancement or bugfix. label Nov 5, 2019
@hawkw hawkw self-assigned this Nov 5, 2019
@hawkw
Copy link
Member Author

hawkw commented Nov 5, 2019

I would love any feedback on the API surface of the new local module — if there's anything we can do to make it more ergonomic to use, that would be great. In particular, I wasn't really sure if we would prefer the free function for spawning on the local task set to be used as tokio::spawn_local, or as tokio::local::spawn. I could go either way...

tokio/src/local.rs Outdated Show resolved Hide resolved
tokio/src/local.rs Outdated Show resolved Hide resolved
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
This adds a marker type to the `Task` struct and `Schedule` trait
indicating whether or not the task is `Send`, and changes `Task` to only
implement `Send` when the `Send` marker is present. Schedulers must
indicate whether they are capable of scheduling `Send` or `!Send` tasks.

This solution is singnificantly better than the previous one of using an
unsafe wrapper to make `!Send` tasks implement `Send`, which was
necessary due to the bounds on the `Task` struct. Although the previous
solution was correct, since the `!Send` tasks were only ever scheduled
locally, the compiler could no longer verify that this was the case.
Now, the typesystem actually _helps_ us ensure that schedulers that can
only schedule `Send` tasks will never schedule `!Send` tasks.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
These assertions asserted that the scheduler was current in all calls
to its methods. However, the `TaskSet::spawn_local` method allows
scheduling tasks to be run on the `TaskSet` when it is _not_ currently
running. Therefore, these assertions are wrong.

This test moves the assertion to the _right_ place: when the scheduler
actually _runs_ scheduled tasks.

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
@hawkw
Copy link
Member Author

hawkw commented Nov 14, 2019

@carllerche BTW, the local task set now requires the "rt-full" feature flag. this is because it now requires the "sync" feature (due to the use of AtomicWaker), which I didn't think "rt-core" should require, and we didn't want to add a separate feature for local. I think that ideally, it would be possible to enable just the single-threaded runtime + LocalSet without also enabling the threadpool runtime, but I think that can wait until we give all the feature flags a pass.

Does that seem right to you?

thanks @jonhoo!

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
}
}

fn with<F>(&self, f: impl FnOnce() -> F) -> F {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens when you nest with calls? Looks like bad things might happen? Either we want to allow it or disallow it via panic.

tokio/src/task/local.rs Outdated Show resolved Hide resolved
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Copied from `basic_scheduler`

Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
tokio/src/task/mod.rs Outdated Show resolved Hide resolved
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
Signed-off-by: Eliza Weisman <eliza@buoyant.io>
@hawkw hawkw merged commit 38e602f into master Nov 27, 2019
@carllerche carllerche deleted the eliza/local-spawn branch November 28, 2019 04:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-enhancement Category: A PR with an enhancement or bugfix.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants