#![cfg_attr(nightly_tls_active, feature(thread_local))]
pub mod hybrid;
pub mod metrics;
pub mod registry;
pub mod schedule;
pub mod task;
pub use hybrid::HybridExecutor;
pub use metrics::ExecutorMetrics;
pub use registry::TaskRegistry;
pub use schedule::{
AcceleratorCounts, AcceleratorId, AcceleratorKind, AcceleratorRoute, AcceleratorRoutePolicy,
AsyncLaneId, AsyncLanesPerProcess, AsyncTask, BlockingTask, HybridRoutePolicy, HybridRouter,
ProcessCount, ProcessId, ProcessRoute, RoutePolicy, RouteSummary, RouteTopology,
ScheduleMetrics, SchedulerRoute, SchedulerScope, ServerCount, ServerId, ServerRoute,
ServerRoutePolicy, SyncTask, ThreadId, ThreadRoute, ThreadRoutePolicy, ThreadScheduler,
WorkClass, WorkerCount,
};
#[cfg(feature = "scheduler-diagnostics")]
pub use schedule::{
ContendedWakeDecision, DiagnosticWakeDecision, EmptyWakeDecision, SaturatedWakeDecision,
};
pub use task::TaskMetadata;
pub fn block_on<F>(future: F) -> F::Output
where
F: core::future::Future,
{
schedule::wake::block_on_current_thread(future)
}
pub struct ExecutorBuilder {
worker_threads: usize,
async_threads: usize,
}
impl ExecutorBuilder {
pub fn new() -> Self {
Self {
worker_threads: std::thread::available_parallelism()
.map(|n| n.get())
.unwrap_or(4),
async_threads: 4,
}
}
pub fn worker_threads(mut self, count: usize) -> Self {
self.worker_threads = count;
self
}
pub fn async_threads(mut self, count: usize) -> Self {
self.async_threads = count;
self
}
pub fn build(self) -> Result<HybridExecutor, Box<dyn std::error::Error>> {
let config = moirai_core::executor::ExecutorConfig {
worker_threads: self.worker_threads,
async_threads: self.async_threads,
..moirai_core::executor::ExecutorConfig::default()
};
HybridExecutor::new(config).map_err(|e| Box::new(e) as Box<dyn std::error::Error>)
}
}
impl Default for ExecutorBuilder {
fn default() -> Self {
Self::new()
}
}
#[derive(Copy, Clone)]
struct SendPtr(usize);
unsafe fn melinoe_executor_bridge(
num_tasks: usize,
task_fn: unsafe fn(usize, *mut ()),
data: *mut (),
) {
let data_ptr = SendPtr(data as usize);
let res = global().for_each_indexed::<SyncTask, _>(num_tasks, move |index| {
let p = data_ptr;
unsafe {
task_fn(index, p.0 as *mut ());
}
});
if let Err(e) = res {
panic!(
"Moirai executor failure in Melinoe parallel driver: {:?}",
e
);
}
}
const MELINOE_EXECUTOR: melinoe::ParallelExecutor =
unsafe { melinoe::ParallelExecutor::new(melinoe_executor_bridge) };
fn global_arc() -> &'static std::sync::Arc<HybridExecutor> {
static GLOBAL_EXECUTOR: std::sync::OnceLock<std::sync::Arc<HybridExecutor>> =
std::sync::OnceLock::new();
GLOBAL_EXECUTOR.get_or_init(|| {
let exec = std::sync::Arc::new(
ExecutorBuilder::new()
.build()
.expect("initialize global Moirai executor"),
);
melinoe::register_parallel_executor(MELINOE_EXECUTOR);
exec
})
}
pub fn global() -> &'static HybridExecutor {
global_arc()
}
pub fn shared() -> std::sync::Arc<HybridExecutor> {
std::sync::Arc::clone(global_arc())
}