Skip to main content

dope_core/driver/schedule/
mod.rs

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