native_executor/polyfill/
executor.rs1#![allow(dead_code)]
2
3use async_task::{self as async_task_crate, Runnable};
4use executor_core::{Executor, async_task::AsyncTask};
5use futures_lite::future::block_on;
6use std::{
7 future::Future,
8 panic::catch_unwind,
9 sync::{Once, OnceLock},
10 thread,
11};
12
13use crate::{
14 PlatformExecutor,
15 polyfill::{assert_main_thread, register_main_thread, timer::PolyfillTimer},
16};
17
18#[derive(Debug, Clone, Copy, Default)]
25pub struct PolyfillExecutor;
26
27static EXECUTOR: OnceLock<async_executor::Executor<'static>> = OnceLock::new();
28static WORKER_THREADS: Once = Once::new();
29
30fn global() -> &'static async_executor::Executor<'static> {
31 let executor = EXECUTOR.get_or_init(async_executor::Executor::new);
32 WORKER_THREADS.call_once(|| spawn_worker_threads(executor));
33 executor
34}
35
36fn spawn_worker_threads(executor: &'static async_executor::Executor<'static>) {
37 let num_threads = num_cpus::get().max(1);
38 for idx in 0..num_threads {
39 let thread_name = format!("native-executor::polyfill-{idx}");
40 let exec = executor;
41 thread::Builder::new()
42 .name(thread_name)
43 .spawn(move || run_worker_loop(exec))
44 .expect("failed to spawn polyfill worker thread");
45 }
46}
47
48fn run_worker_loop(executor: &'static async_executor::Executor<'static>) {
49 loop {
50 let _ = catch_unwind(|| {
51 block_on(executor.run(std::future::pending::<()>()));
52 });
53 }
54}
55
56static MAIN_EXECUTOR: OnceLock<async_executor::Executor<'static>> = OnceLock::new();
57
58pub fn start_main_executor() {
70 register_main_thread();
71 let main_exec = async_executor::Executor::new();
72 MAIN_EXECUTOR
73 .set(main_exec)
74 .expect("Main executor already started");
75 let main_exec = MAIN_EXECUTOR
76 .get()
77 .expect("Unexpected error: main executor not set");
78 loop {
79 let _ = catch_unwind(|| {
80 block_on(main_exec.run(std::future::pending::<()>()));
81 });
82 }
83}
84
85fn main_executor() -> &'static async_executor::Executor<'static> {
86 MAIN_EXECUTOR.get().expect("polyfill main executor not started. Call `native_executor::polyfill::start_main_executor` on a dedicated thread before using `spawn_main` or `spawn_local`.")
87}
88
89impl PlatformExecutor for PolyfillExecutor {
90 type Timer = PolyfillTimer;
91 fn with_priority(_priority: crate::Priority) -> Self {
92 Self
94 }
95
96 fn spawn<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
97 where
98 Fut: Future<Output: Send> + Send + 'static,
99 {
100 global().spawn(fut).into()
101 }
102
103 fn spawn_main<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
104 where
105 Fut: Future<Output: Send> + Send + 'static,
106 {
107 main_executor().spawn(fut).into()
108 }
109
110 fn spawn_main_local<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
111 where
112 Fut: Future + 'static,
113 {
114 assert_main_thread("spawn_main_local");
115 let (runnable, task) = async_task_crate::spawn_local(fut, |runnable: Runnable| {
116 runnable.run();
117 });
118 runnable.run();
119 task.into()
120 }
121
122 fn sleep(duration: std::time::Duration) -> Self::Timer {
123 PolyfillTimer::after(duration)
124 }
125}
126
127impl Executor for PolyfillExecutor {
128 type Task<T: Send + 'static> = AsyncTask<T>;
129 fn spawn<Fut>(&self, fut: Fut) -> AsyncTask<Fut::Output>
130 where
131 Fut: Future<Output: Send> + Send + 'static,
132 {
133 global().spawn(fut).into()
134 }
135}