use std::fmt;
use std::io;
use crate::rt::runtime::{self, Builder};
use crate::rt::task::Task;
use crate::rt::workers::Workers;
#[derive(Default)]
pub struct GlobalExecutorConfig {
env_var: Option<&'static str>,
min_threads: Option<usize>,
max_threads: Option<usize>,
thread_name_fn: Option<Box<dyn Fn() -> String + Send + Sync>>,
}
impl fmt::Debug for GlobalExecutorConfig {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("GlobalExecutorConfig")
.field("env_var", &self.env_var)
.field("min_threads", &self.min_threads)
.field("max_threads", &self.max_threads)
.finish_non_exhaustive()
}
}
impl GlobalExecutorConfig {
pub fn with_env_var(mut self, env_var: &'static str) -> Self {
self.env_var = Some(env_var);
self
}
pub fn with_min_threads(mut self, min_threads: usize) -> Self {
self.min_threads = Some(min_threads);
self
}
pub fn with_max_threads(mut self, max_threads: usize) -> Self {
self.max_threads = Some(max_threads);
self
}
pub fn with_thread_name_fn(
mut self,
thread_name_fn: impl Fn() -> String + Send + Sync + 'static,
) -> Self {
self.thread_name_fn = Some(Box::new(thread_name_fn));
self
}
fn builder(self) -> Builder {
let from_env = self
.env_var
.and_then(|name| std::env::var(name).ok())
.and_then(|threads| threads.parse::<usize>().ok());
let min = from_env
.or(self.min_threads)
.unwrap_or_else(|| std::thread::available_parallelism().map_or(1, usize::from));
let mut builder = match self.max_threads {
Some(0) => Builder::new().worker_threads(0),
max => {
let min = min.max(1);
Builder::new()
.worker_threads(min)
.max_worker_threads(max.unwrap_or(min.saturating_mul(4)).max(min))
}
};
if let Some(name) = self.thread_name_fn {
builder = builder.thread_name_fn(name);
}
builder
}
}
pub fn init() {
runtime::default_runtime();
}
pub fn init_with_config(config: GlobalExecutorConfig) {
match config.builder().build_global() {
Ok(_) => {}
Err(err) if err.kind() == io::ErrorKind::AlreadyExists => {}
Err(err) => log::error!("the default runtime could not start as configured: {err}"),
}
}
pub async fn spawn_more_threads(count: usize) -> io::Result<usize> {
Workers::start(&runtime::current(), count)
}
pub fn stop_thread() -> Task<bool> {
crate::runtime::spawn(async { runtime::current().workers.stop_one() })
}
pub fn stop_current_thread() -> Task<bool> {
crate::runtime::spawn_local(async {
let inner = runtime::current();
crate::rt::context::current(|current| {
current
.filter(|shard| shard.worker_index(inner.id()).is_some())
.is_some_and(|shard| inner.workers.stop(&shard.shared))
})
})
}