rasi_syscall/
executor.rs

1//! syscall for async task.
2
3use std::sync::OnceLock;
4
5use futures::{future::BoxFuture, Future, SinkExt, StreamExt};
6
7/// Future task system call interface.
8pub trait Executor: Send + Sync {
9    /// Spawns a task that polls the given `boxed` future with output () to completion.
10    fn spawn_boxed(&self, fut: BoxFuture<'static, ()>);
11}
12
13/// Spawns a task that polls the given future with output () to completion.
14pub fn syscall_spawn<Fut>(syscall: &dyn Executor, fut: Fut)
15where
16    Fut: Future<Output = ()> + Send + 'static,
17{
18    syscall.spawn_boxed(Box::pin(fut))
19}
20
21/// Run a future to completion on the current thread.
22///
23/// This function will block the caller until the given future has completed.
24pub fn syscall_block_on<Fut, R>(syscall: &dyn Executor, fut: Fut) -> R
25where
26    Fut: Future<Output = R> + Send + 'static,
27    R: Send + 'static,
28{
29    let (mut sender, mut receiver) = futures::channel::mpsc::channel::<R>(0);
30
31    syscall_spawn(syscall, async move {
32        let r = fut.await;
33        _ = sender.send(r).await;
34    });
35
36    futures::executor::block_on(async move { receiver.next().await.unwrap() })
37}
38
39static GLOBAL_EXECUTOR: OnceLock<Box<dyn Executor>> = OnceLock::new();
40
41/// Register provided [`Executor`] as global executor implementation.
42///
43/// # Panic
44///
45/// Multiple calls to this function are not permitted!!!
46pub fn register_global_executor<E: Executor + 'static>(executor: E) {
47    if GLOBAL_EXECUTOR.set(Box::new(executor)).is_err() {
48        panic!("Multiple calls to register_global_executor are not permitted!!!");
49    }
50}
51
52/// Get the globally registered instance of [`Executor`].
53///
54/// # Panic
55///
56/// You should call [`register_global_executor`] first to register implementation,
57/// otherwise this function will cause a panic with `Call register_global_executor first`
58pub fn global_executor() -> &'static dyn Executor {
59    GLOBAL_EXECUTOR
60        .get()
61        .expect("Call register_global_executor first")
62        .as_ref()
63}