Skip to main content

dope_core/driver/schedule/
mod.rs

1use std::{cell, marker, mem, time};
2
3use o3::{alloc, base::cell::region, mem::quota};
4use state::{lanes::Quota, scope};
5
6use crate::{
7    driver,
8    driver::{
9        receive::{credit, credit::storage},
10        route::table::conn,
11        settings,
12    },
13};
14
15pub mod clock;
16
17pub mod app;
18pub mod maint;
19pub mod ready;
20pub mod sequence;
21#[doc(hidden)]
22pub mod state;
23mod timers;
24
25pub const LIMIT: usize = 256;
26
27/// Exact result of acquiring scheduler capacity from a non-empty source.
28#[must_use = "capacity reports whether the scheduler granted the operation"]
29pub enum Capacity<T> {
30    Available(T),
31    Exhausted,
32}
33
34#[derive(Clone, Copy)]
35#[repr(transparent)]
36pub struct Turn<'turn, 'd> {
37    state: &'turn state::Core<'d>,
38    driver: marker::PhantomData<fn(&'d ()) -> &'d ()>,
39}
40
41impl<'turn, 'd> Turn<'turn, 'd> {
42    pub(in crate::driver::schedule) const fn new(state: &'turn state::Core<'d>) -> Self {
43        Self {
44            state,
45            driver: marker::PhantomData,
46        }
47    }
48
49    pub fn reborrow(&self) -> Turn<'_, 'd> {
50        Turn::new(self.state)
51    }
52
53    pub fn clock(self) -> clock::Clock<'turn, 'd> {
54        self.state.driver.scheduler().clock()
55    }
56
57    pub fn app(self) -> app::Work<'turn, 'd> {
58        app::Work { state: self.state }
59    }
60
61    pub fn maint(self) -> maint::Work<'turn, 'd> {
62        maint::Work { state: self.state }
63    }
64
65    /// Runs one sibling with refundable application, maintenance and control
66    /// shares. Ranks choose the remainder recipients when fewer credits than
67    /// siblings remain; sufficiently funded shares keep ceiling division.
68    #[doc(hidden)]
69    pub fn share<const N: usize, T>(
70        self,
71        ranks: [usize; 3],
72        weights: [usize; 2],
73        run: impl for<'scope> FnOnce(Turn<'scope, 'd>) -> T,
74    ) -> T {
75        let _app = Quota::share::<N, _>(&self.state.lanes.app, ranks[0]);
76        let _maint = Quota::share::<N, _>(&self.state.lanes.maint, ranks[1]);
77        let _coord = Quota::weighted::<N, _>(&self.state.lanes.coord, ranks[2], weights);
78        run(Turn::new(self.state))
79    }
80
81    #[doc(hidden)]
82    pub fn coord(self) -> scope::Coord<'turn, 'd> {
83        scope::Coord::new(self.state)
84    }
85}
86
87const _: () = {
88    let word = mem::size_of::<usize>();
89    assert!(mem::size_of::<Turn<'static, 'static>>() == word);
90    assert!(mem::size_of::<quota::Admission<usize>>() == 2 * word);
91    assert!(mem::size_of::<Capacity<&'static u8>>() == word);
92};
93
94/// Aggregate liveness of retained work owned by one driver.
95#[must_use]
96pub enum Progress<'d> {
97    Runnable,
98    Waiting(Wait<'d>),
99    Quiescent,
100}
101
102impl<'d> Progress<'d> {
103    pub fn waiting(region: &region::Token<region::Identity<'d>>) -> Self {
104        Self::Waiting(Wait::event(region))
105    }
106
107    pub fn until(deadline: clock::Deadline<'d>) -> Self {
108        Self::Waiting(Wait::until(deadline))
109    }
110
111    pub fn reduce(self, other: Self) -> Self {
112        match self {
113            runnable @ Self::Runnable => runnable,
114            Self::Waiting(left) => match other {
115                runnable @ Self::Runnable => runnable,
116                Self::Waiting(right) => Self::Waiting(left.reduce(right)),
117                Self::Quiescent => Self::Waiting(left),
118            },
119            Self::Quiescent => other,
120        }
121    }
122}
123
124const _: () = assert!(mem::size_of::<Progress<'static>>() <= 24);
125
126pub(in crate::driver) struct State {
127    pub(in crate::driver) owner: storage::Owner<ready::Stored, credit::Wake, ready::Arena>,
128    clock: cell::Cell<time::Instant>,
129}
130
131impl State {
132    pub(in crate::driver) fn try_new(plan: settings::Plan) -> Result<Self, alloc::Error> {
133        Ok(Self {
134            owner: storage::Owner::try_new(plan)?,
135            clock: cell::Cell::new(time::Instant::now()),
136        })
137    }
138}
139
140#[derive(Clone, Copy)]
141#[repr(transparent)]
142pub struct Context<'d>(driver::Reference<'d>);
143
144impl<'d> Context<'d> {
145    pub(in crate::driver) const fn new(driver: driver::Reference<'d>) -> Self {
146        Self(driver)
147    }
148
149    pub(in crate::driver) fn clock(self) -> clock::Clock<'d, 'd> {
150        clock::Clock::new(&self.0.shared.context().schedule.clock, self.0.brand)
151    }
152
153    pub(in crate::driver) fn set_turn_now(self, now: time::Instant) {
154        self.0.shared.context().schedule.clock.set(now);
155    }
156
157    /// Allocates fixed retained-credit storage in this driver generation.
158    pub fn try_storage(
159        self,
160        capacity: conn::Capacity,
161    ) -> Result<credit::Storage<'d>, alloc::Error> {
162        let shared: &'d driver::Shared = self.0.shared.context();
163        let owner = &shared.schedule.owner;
164        owner.try_storage(capacity, self.0.brand)
165    }
166}
167
168const _: () = assert!(
169    std::mem::size_of::<Context<'static>>() == std::mem::size_of::<driver::Reference<'static>>()
170);
171
172enum Reason<'d> {
173    Event(region::Proof<region::Identity<'d>>),
174    Until(clock::Deadline<'d>),
175}
176
177/// Driver-scoped evidence that a retained owner is waiting for an external
178/// wake or a monotonic deadline.
179#[must_use]
180#[repr(transparent)]
181pub struct Wait<'d> {
182    state: Reason<'d>,
183}
184
185impl<'d> Wait<'d> {
186    pub fn event(region: &region::Token<region::Identity<'d>>) -> Self {
187        Self {
188            state: Reason::Event(region.proof()),
189        }
190    }
191
192    pub fn until(deadline: clock::Deadline<'d>) -> Self {
193        Self {
194            state: Reason::Until(deadline),
195        }
196    }
197
198    pub fn deadline(self) -> Option<clock::Deadline<'d>> {
199        match self.state {
200            Reason::Event(_proof) => None,
201            Reason::Until(deadline) => Some(deadline),
202        }
203    }
204
205    pub(super) fn reduce(self, other: Self) -> Self {
206        match self.state {
207            Reason::Event(_proof) => other,
208            Reason::Until(left) => match other.state {
209                Reason::Event(_proof) => Self {
210                    state: Reason::Until(left),
211                },
212                Reason::Until(right) => Self {
213                    state: Reason::Until(left.min(right)),
214                },
215            },
216        }
217    }
218}
219
220const _: () = {
221    assert!(mem::size_of::<Wait<'static>>() == mem::size_of::<Option<clock::Deadline<'static>>>());
222    assert!(
223        mem::align_of::<Wait<'static>>() == mem::align_of::<Option<clock::Deadline<'static>>>()
224    );
225    assert!(mem::size_of::<Option<Wait<'static>>>() == mem::size_of::<Wait<'static>>());
226    assert!(!mem::needs_drop::<Wait<'static>>());
227};