dope-runtime 0.2.0

Thin io_uring adaptor with "Manifolds"
Documentation
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))
    }
}