use std::{io, marker::PhantomData};
use dope_core::driver::CompletionBackend;
pub use dope_core::profile::{Profile, Tail, Throughput};
mod ctx;
mod external;
pub mod join_handle;
mod runner;
pub mod runtime_tuning;
pub mod task_queue;
mod timer_heap;
pub use ctx::{RuntimeCtx, RuntimeHandles};
pub use dope_core::driver::ExternalDispatch;
pub use external::install_external;
pub use join_handle::JoinHandle;
pub use runner::{block_on, current, spawn};
pub use runtime_tuning::RuntimeTuning;
pub use task_queue::{DEFAULT_READY_BUDGET, TaskQueue};
pub(crate) use timer_heap::TimerHeap;
use crate::runtime::{Manifold, Runtime};
use external::{ExternalRouter, current_external};
use runtime_tuning::IdleParkPolicy;
#[inline(always)]
pub fn current_driver_mut<'a, B: CompletionBackend>() -> &'a mut B::Driver {
let p = B::current_driver_mut();
debug_assert!(
!p.is_null(),
"dope-runtime: no current driver (called outside runtime?)"
);
unsafe { &mut *p }
}
#[inline(always)]
pub fn in_runtime<B: CompletionBackend>() -> bool {
!B::current_driver_mut().is_null()
}
pub struct LocalExecutor<B: CompletionBackend, P: Profile = Throughput> {
pub(super) exec: Box<TaskQueue>,
pub(super) timers: Box<TimerHeap>,
pub(super) idle_park_policy: IdleParkPolicy,
pub(super) marker: PhantomData<(B, P)>,
}
impl<B: CompletionBackend, P: Profile> LocalExecutor<B, P> {
pub(super) fn new(idle_park_policy: IdleParkPolicy) -> Self {
Self {
exec: Box::new(TaskQueue::new()),
timers: Box::new(TimerHeap::new()),
idle_park_policy,
marker: PhantomData,
}
}
}
#[inline(always)]
pub(super) fn run_ready<P: Profile>(exec: &TaskQueue) -> usize {
match P::TASK_BUDGET {
None => exec.run_ready_all(),
Some(n) => exec.run_ready_with_budget(n),
}
}
impl<B: dope_core::driver::PoolDriver, P: Profile> Manifold for LocalExecutor<B, P> {
type Backend = B;
#[inline(always)]
fn has_pending(&self, _driver: &mut B::Driver) -> bool {
!self.exec.is_empty()
}
#[inline(always)]
fn drive(&mut self, driver: &mut B::Driver) {
let aux = current_external::<B>();
let _ = B::drive_with(driver, &mut ExternalRouter::<B> { aux });
if let Some(a) = aux {
unsafe { (a.pump)(a.state, driver) };
}
self.timers.wake_due();
run_ready::<P>(&self.exec);
}
}
impl<B, P> Runtime<LocalExecutor<B, P>>
where
B: dope_core::driver::PoolDriver,
P: Profile,
{
pub fn new_local() -> io::Result<Self> {
Self::new_local_with_tuning(RuntimeTuning::for_profile::<P>())
}
pub fn new_local_with_tuning(
tuning: runtime_tuning::RuntimeTuning<B::Config>,
) -> io::Result<Self> {
let driver = B::new_driver(tuning.driver)?;
let reactor = LocalExecutor::<B, P>::new(tuning.idle_park_policy);
Ok(Self::new(reactor, driver))
}
}