dope_runtime/executor/
mod.rs1use std::{io, marker::PhantomData};
2
3use dope_core::driver::CompletionBackend;
4
5pub use dope_core::profile::{Profile, Tail, Throughput};
6
7mod ctx;
8mod external;
9pub mod join_handle;
10mod runner;
11pub mod runtime_tuning;
12pub mod task_queue;
13mod timer_heap;
14
15pub use ctx::{RuntimeCtx, RuntimeHandles};
16pub use dope_core::driver::ExternalDispatch;
17pub use external::install_external;
18pub use join_handle::JoinHandle;
19pub use runner::{block_on, current, spawn};
20pub use runtime_tuning::RuntimeTuning;
21pub use task_queue::{DEFAULT_READY_BUDGET, TaskQueue};
22pub(crate) use timer_heap::TimerHeap;
23
24use crate::runtime::{Manifold, Runtime};
25use external::{ExternalRouter, current_external};
26use runtime_tuning::IdleParkPolicy;
27
28#[inline(always)]
29pub fn current_driver_mut<'a, B: CompletionBackend>() -> &'a mut B::Driver {
30 let p = B::current_driver_mut();
31 debug_assert!(
32 !p.is_null(),
33 "dope-runtime: no current driver (called outside runtime?)"
34 );
35
36 unsafe { &mut *p }
37}
38
39#[inline(always)]
40pub fn in_runtime<B: CompletionBackend>() -> bool {
41 !B::current_driver_mut().is_null()
42}
43
44pub struct LocalExecutor<B: CompletionBackend, P: Profile = Throughput> {
45 pub(super) exec: Box<TaskQueue>,
46 pub(super) timers: Box<TimerHeap>,
47 pub(super) idle_park_policy: IdleParkPolicy,
48 pub(super) marker: PhantomData<(B, P)>,
49}
50
51impl<B: CompletionBackend, P: Profile> LocalExecutor<B, P> {
52 pub(super) fn new(idle_park_policy: IdleParkPolicy) -> Self {
53 Self {
54 exec: Box::new(TaskQueue::new()),
55 timers: Box::new(TimerHeap::new()),
56 idle_park_policy,
57 marker: PhantomData,
58 }
59 }
60}
61
62#[inline(always)]
63pub(super) fn run_ready<P: Profile>(exec: &TaskQueue) -> usize {
64 match P::TASK_BUDGET {
65 None => exec.run_ready_all(),
66 Some(n) => exec.run_ready_with_budget(n),
67 }
68}
69
70impl<B: dope_core::driver::PoolDriver, P: Profile> Manifold for LocalExecutor<B, P> {
71 type Backend = B;
72
73 #[inline(always)]
74 fn has_pending(&self, _driver: &mut B::Driver) -> bool {
75 !self.exec.is_empty()
76 }
77
78 #[inline(always)]
79 fn drive(&mut self, driver: &mut B::Driver) {
80 let aux = current_external::<B>();
81 let _ = B::drive_with(driver, &mut ExternalRouter::<B> { aux });
82 if let Some(a) = aux {
83 unsafe { (a.pump)(a.state, driver) };
84 }
85 self.timers.wake_due();
86 run_ready::<P>(&self.exec);
87 }
88}
89
90impl<B, P> Runtime<LocalExecutor<B, P>>
91where
92 B: dope_core::driver::PoolDriver,
93 P: Profile,
94{
95 pub fn new_local() -> io::Result<Self> {
96 Self::new_local_with_tuning(RuntimeTuning::for_profile::<P>())
97 }
98
99 pub fn new_local_with_tuning(
100 tuning: runtime_tuning::RuntimeTuning<B::Config>,
101 ) -> io::Result<Self> {
102 let driver = B::new_driver(tuning.driver)?;
103 let reactor = LocalExecutor::<B, P>::new(tuning.idle_park_policy);
104 Ok(Self::new(reactor, driver))
105 }
106}