Files
tokio/tokio/tests/rt_local.rs
T
Noah Kennedy 512e9decfb rt: add LocalRuntime (#6808)
This change adds LocalRuntime, a new unstable runtime type which cannot be transferred across thread boundaries and supports spawn_local when called from the thread which owns the runtime.

The initial set of docs for this are iffy. Documentation is absent right now at the module level, with the docs for the LocalRuntime struct itself being somewhat duplicative of those for the `Runtime` type. This can be addressed later as stabilization nears.

This API has a few interesting implementation details:
- because it was considered beneficial to reuse the same Handle as the normal runtime, it is possible to call spawn_local from a runtime context while on a different thread from the one which drives the runtime and owns it. This forces us to check the thread ID before attempting a local spawn.
- An empty LocalOptions struct is passed into the build_local method in order to build the runtime. This will eventually have stuff in it like hooks.

Relates to #6739.
2024-10-12 10:39:23 -05:00

101 lines
2.0 KiB
Rust

#![allow(unknown_lints, unexpected_cfgs)]
#![warn(rust_2018_idioms)]
#![cfg(all(feature = "full", tokio_unstable))]
use tokio::runtime::LocalOptions;
use tokio::task::spawn_local;
#[test]
fn test_spawn_local_in_runtime() {
let rt = rt();
let res = rt.block_on(async move {
let (tx, rx) = tokio::sync::oneshot::channel();
spawn_local(async {
tokio::task::yield_now().await;
tx.send(5).unwrap();
});
rx.await.unwrap()
});
assert_eq!(res, 5);
}
#[test]
fn test_spawn_from_handle() {
let rt = rt();
let (tx, rx) = tokio::sync::oneshot::channel();
rt.handle().spawn(async {
tokio::task::yield_now().await;
tx.send(5).unwrap();
});
let res = rt.block_on(async move { rx.await.unwrap() });
assert_eq!(res, 5);
}
#[test]
fn test_spawn_local_on_runtime_object() {
let rt = rt();
let (tx, rx) = tokio::sync::oneshot::channel();
rt.spawn_local(async {
tokio::task::yield_now().await;
tx.send(5).unwrap();
});
let res = rt.block_on(async move { rx.await.unwrap() });
assert_eq!(res, 5);
}
#[test]
fn test_spawn_local_from_guard() {
let rt = rt();
let (tx, rx) = tokio::sync::oneshot::channel();
let _guard = rt.enter();
spawn_local(async {
tokio::task::yield_now().await;
tx.send(5).unwrap();
});
let res = rt.block_on(async move { rx.await.unwrap() });
assert_eq!(res, 5);
}
#[test]
#[should_panic]
fn test_spawn_local_from_guard_other_thread() {
let (tx, rx) = std::sync::mpsc::channel();
std::thread::spawn(move || {
let rt = rt();
let handle = rt.handle().clone();
tx.send(handle).unwrap();
});
let handle = rx.recv().unwrap();
let _guard = handle.enter();
spawn_local(async {});
}
fn rt() -> tokio::runtime::LocalRuntime {
tokio::runtime::Builder::new_current_thread()
.enable_all()
.build_local(&LocalOptions::default())
.unwrap()
}