1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-26 23:04:49 +03:00

promise: add tokio_spawn helper

This starts up the tokio runtime on a secondary thread
and spawns a future into it.
This commit is contained in:
Wez Furlong 2020-01-19 09:59:30 -08:00
parent 7aa0994b0f
commit 1d9678706c
3 changed files with 132 additions and 1 deletions

77
Cargo.lock generated
View File

@ -286,6 +286,12 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
[[package]]
name = "bytes"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10004c15deb332055f7a4a208190aed362cf9a7c2f6ab70a305fba50e1105f38"
[[package]]
name = "c2-chacha"
version = "0.2.3"
@ -1558,7 +1564,7 @@ dependencies = [
"kernel32-sys",
"libc",
"log",
"miow",
"miow 0.2.1",
"net2",
"slab",
"winapi 0.2.8",
@ -1576,6 +1582,18 @@ dependencies = [
"slab",
]
[[package]]
name = "mio-named-pipes"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3"
dependencies = [
"log",
"mio",
"miow 0.3.3",
"winapi 0.3.8",
]
[[package]]
name = "mio-uds"
version = "0.6.7"
@ -1599,6 +1617,16 @@ dependencies = [
"ws2_32-sys",
]
[[package]]
name = "miow"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226"
dependencies = [
"socket2",
"winapi 0.3.8",
]
[[package]]
name = "native-tls"
version = "0.2.3"
@ -2125,6 +2153,7 @@ dependencies = [
"async-task",
"lazy_static",
"thiserror",
"tokio",
]
[[package]]
@ -2666,6 +2695,18 @@ dependencies = [
"wayland-protocols",
]
[[package]]
name = "socket2"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"winapi 0.3.8",
]
[[package]]
name = "ssh2"
version = "0.6.0"
@ -2996,6 +3037,40 @@ dependencies = [
"winapi 0.3.8",
]
[[package]]
name = "tokio"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffa2fdcfa937b20cb3c822a635ceecd5fc1a27a6a474527e5516aa24b8c8820a"
dependencies = [
"bytes",
"fnv",
"futures-core",
"iovec",
"lazy_static",
"libc",
"memchr",
"mio",
"mio-named-pipes",
"mio-uds",
"num_cpus",
"pin-project-lite",
"signal-hook-registry",
"slab",
"tokio-macros",
"winapi 0.3.8",
]
[[package]]
name = "tokio-macros"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50a61f268a3db2acee8dcab514efc813dc6dbe8a00e86076f935f94304b59a7a"
dependencies = [
"quote 1.0.2",
"syn 1.0.13",
]
[[package]]
name = "toml"
version = "0.4.10"

View File

@ -7,6 +7,7 @@ edition = "2018"
[dependencies]
async-task = "1.2"
async-std = "1.4"
tokio = {version="0.2", features=["full"]}
anyhow = "1.0"
thiserror = "1.0"
lazy_static = "1.3"

View File

@ -14,13 +14,68 @@ fn no_schedule_configured(_: Task<()>) {
lazy_static::lazy_static! {
static ref ON_MAIN_THREAD: Mutex<ScheduleFunc> = Mutex::new(Box::new(no_schedule_configured));
static ref ON_MAIN_THREAD_LOW_PRI: Mutex<ScheduleFunc> = Mutex::new(Box::new(no_schedule_configured));
static ref TOKIO: tokio::runtime::Handle = start_tokio();
}
/// Set callbacks for scheduling normal and low priority futures.
/// Why this and not "just tokio"? In a GUI application there is typically
/// a special GUI processing loop that may need to run on the "main thread",
/// so we can't just run a tokio/mio loop in that context.
/// This particular crate has no real knowledge of how that plumbing works,
/// it just provides the abstraction for scheduling the work.
/// This function allows the embedding application to set that up.
pub fn set_schedulers(main: ScheduleFunc, low_pri: ScheduleFunc) {
*ON_MAIN_THREAD.lock().unwrap() = Box::new(main);
*ON_MAIN_THREAD_LOW_PRI.lock().unwrap() = Box::new(low_pri);
}
/// Spawn the tokio runtime and run it on a secondary thread.
/// We can't run it on the main thread for the reasons mentioned above.
/// This is called implicitly when the TOKIO global is accessed by the
/// `tokio_spawn` function below.
fn start_tokio() -> tokio::runtime::Handle {
let mut runtime = tokio::runtime::Builder::new()
.threaded_scheduler()
.core_threads(1)
.build()
.expect("failed to initialize tokio runtime");
let handle = runtime.handle().clone();
// Run the runtime in another thread.
// I'm not sure that it is strictly needed, or whether we can just
// keep it alive without actively polling anything.
std::thread::spawn(move || {
// A future that never completes
struct Never {}
impl Future for Never {
type Output = ();
fn poll(
self: std::pin::Pin<&mut Self>,
_: &mut std::task::Context,
) -> Poll<Self::Output> {
Poll::Pending
}
}
// manage the runtime forever
runtime.block_on(Never {});
});
handle
}
/// Spawn a future into the tokio runtime, spawning the tokio runtime
/// if it hasn't already been started up. The tokio runtime (in the
/// context of this crate) is intended primarily for scheduling network
/// IO. Most futures should be spawned via the other functions provided
/// by this module.
pub fn tokio_spawn<F>(future: F) -> tokio::task::JoinHandle<F::Output>
where
F: Future + Send + 'static,
F::Output: Send + 'static,
{
TOKIO.spawn(future)
}
/// Spawn a new thread to execute the provided function.
/// Returns a JoinHandle that implements the Future trait
/// and that can be used to await and yield the return value