Skip to main content

dope_runtime/executor/raw/
mod.rs

1//! Raw application boundary. [`App`] owns complete lifecycle traversal;
2//! runtime-owned session roots choose when it may run.
3use std::{convert, mem, num::NonZero, pin};
4
5use dope_core::driver::{
6    self,
7    life::{self, finish},
8    retained, schedule,
9};
10use o3::base::{
11    cell::region,
12    num::bounded::{self, U32},
13};
14
15use crate::executor;
16
17mod activate;
18mod app;
19mod cursor;
20mod dispatch;
21mod owner;
22mod park;
23mod progress;
24mod released;
25
26pub use activate::Activate;
27pub use app::{App, Layout};
28pub use cursor::Cursor;
29pub use dispatch::Dispatch;
30pub(crate) use owner::{Backing, Draining, Live, Owner, Parent, View};
31pub use park::Park;
32pub use progress::Progress;
33pub use released::Released;
34
35/// Cooperative drain while the complete application remains installed.
36///
37/// # Safety
38/// Preserve every admitted owner's identity, presence, address, and routes through
39/// finish. `begin` and `force` must not replace owners or reclaim retained storage.
40/// Cooperative quiescence does not authorize reclamation: the runtime still
41/// shuts down every admitted owner and drains native operations before finish.
42pub unsafe trait Drain<'d>: executor::raw::App<'d> {
43    fn begin(
44        self: pin::Pin<&mut Self>,
45        turn: schedule::Turn<'_, 'd>,
46        driver: &mut retained::Context<'_, '_, 'd>,
47    );
48
49    /// Reports drain work after the application's pre-park traversal.
50    /// `Runnable` requires another turn for work that can proceed now;
51    /// `Waiting` retains the external wake or deadline needed to proceed.
52    /// `Quiescent` reports completed cooperative drain, not reclaimed owners.
53    /// The runtime combines this signal with application progress before waiting.
54    fn progress(
55        self: pin::Pin<&Self>,
56        region: &region::Token<region::Identity<'d>>,
57    ) -> schedule::Progress<'d>;
58
59    fn force(
60        self: pin::Pin<&mut Self>,
61        turn: schedule::Turn<'_, 'd>,
62        driver: &mut retained::Context<'_, '_, 'd>,
63    );
64}
65
66/// One exact capability invocation joining its pinned owner, selection, and operation.
67pub struct Call<'app, R, P, O> {
68    app: pin::Pin<&'app mut R>,
69    plan: P,
70    op: O,
71}
72
73impl<'app, R, P, O> Call<'app, R, P, O> {
74    /// Joins one runtime-owned operation with its exact pinned root.
75    pub const fn new(app: pin::Pin<&'app mut R>, plan: P, op: O) -> Self {
76        Self { app, plan, op }
77    }
78
79    pub fn into_parts(self) -> (pin::Pin<&'app mut R>, P, O) {
80        (self.app, self.plan, self.op)
81    }
82
83    /// Projects the pinned owner while preserving the selection and operation proofs.
84    pub fn map_owner<U>(
85        self,
86        map: impl FnOnce(pin::Pin<&'app mut R>) -> pin::Pin<&'app mut U>,
87    ) -> Call<'app, U, P, O> {
88        Call {
89            app: map(self.app),
90            plan: self.plan,
91            op: self.op,
92        }
93    }
94}
95
96impl<R, O> Call<'_, R, convert::Infallible, O> {
97    /// Consumes an invocation whose selection proof has no inhabitants.
98    pub fn into_never(self) -> ! {
99        match self {}
100    }
101}
102
103/// One complete coordinator count classified at installation.
104#[derive(Clone, Copy, Debug)]
105pub enum Count {
106    Bounded(U32<0, { schedule::LIMIT as u32 }>),
107    Excess(NonZero<usize>),
108}
109
110impl Count {
111    pub const fn new(value: usize) -> Self {
112        match U32::from_usize(value) {
113            Some(value) => Self::Bounded(value),
114            None => Self::Excess(NonZero::<usize>::MIN.saturating_add(value - 1)),
115        }
116    }
117
118    pub fn sum<const N: usize>(values: [usize; N]) -> Option<Self> {
119        values
120            .into_iter()
121            .try_fold(0usize, |count, value| count.checked_add(value))
122            .map(Self::new)
123    }
124
125    pub const fn get(self) -> usize {
126        match self {
127            Self::Bounded(value) => value.into_usize(),
128            Self::Excess(value) => value.get(),
129        }
130    }
131
132    pub(in crate::executor::raw) fn admit(self) -> Result<(), executor::InstallError> {
133        match self {
134            Self::Bounded(_) => Ok(()),
135            Self::Excess(count) => Err(executor::InstallError::Coordinators {
136                count,
137                limit: schedule::LIMIT,
138            }),
139        }
140    }
141}
142
143/// Coordinator shares prepared once for one installed application.
144#[repr(transparent)]
145pub struct Weights<const N: usize> {
146    values: [U32<0, { schedule::LIMIT as u32 }>; N],
147}
148
149impl<const N: usize> Weights<N> {
150    pub const ZERO: Self = Self {
151        values: [U32::exact::<0>(); N],
152    };
153
154    pub fn prepare(&mut self, values: [usize; N]) -> Option<Count> {
155        let count = Count::sum(values)?;
156        if let Count::Bounded(_) = count {
157            self.values = values.map(|value| {
158                // SAFETY: the admitted sum bounds each nonnegative share and its representation.
159                unsafe { bounded::raw::Proof::assume(value as u32) }.retain()
160            });
161        }
162        Some(count)
163    }
164
165    pub fn values(&self) -> [usize; N] {
166        self.values.map(U32::into_usize)
167    }
168}
169
170pub trait Finishes<'d, R = Self> {
171    fn call<'app, 'finish, 'owner, 'epoch>(
172        finish: Finish<'app, 'finish, 'owner, 'epoch, 'd, R>,
173    ) -> Finish<'app, 'finish, 'owner, 'epoch, 'd, R>;
174}
175
176/// Installation traversal carrying its exact pinned root and owner proof.
177#[must_use]
178pub struct Install<'app, 'owner, 'd, R> {
179    app: pin::Pin<&'app mut R>,
180    install: life::Install<'owner, 'd>,
181}
182
183/// Shutdown traversal carrying its exact pinned root and driver turn.
184#[must_use]
185pub struct Shutdown<'app, 'turn, 'driver, 'owner, 'd: 'owner, R> {
186    app: pin::Pin<&'app mut R>,
187    turn: schedule::Turn<'turn, 'd>,
188    driver: retained::Context<'driver, 'owner, 'd>,
189}
190
191/// Final traversal carrying installation and post-quiescence proofs together.
192#[must_use]
193pub struct Finish<'app, 'finish, 'owner, 'epoch, 'd, R> {
194    app: pin::Pin<&'app mut R>,
195    install: life::Install<'owner, 'd>,
196    finish: &'finish mut finish::Finish<'epoch, 'd>,
197}
198
199impl<'app, 'owner, 'd, R> Install<'app, 'owner, 'd, R> {
200    pub fn new(app: pin::Pin<&'app mut R>, install: life::Install<'owner, 'd>) -> Self {
201        Self { app, install }
202    }
203
204    pub fn into_parts(self) -> (pin::Pin<&'app mut R>, life::Install<'owner, 'd>) {
205        (self.app, self.install)
206    }
207
208    pub fn into_install(self) -> life::Install<'owner, 'd> {
209        self.install
210    }
211}
212
213impl<'app, 'turn, 'driver, 'owner, 'd: 'owner, R> Shutdown<'app, 'turn, 'driver, 'owner, 'd, R> {
214    pub fn new(
215        app: pin::Pin<&'app mut R>,
216        turn: schedule::Turn<'turn, 'd>,
217        driver: retained::Context<'driver, 'owner, 'd>,
218    ) -> Self {
219        Self { app, turn, driver }
220    }
221
222    pub fn into_parts(
223        self,
224    ) -> (
225        pin::Pin<&'app mut R>,
226        schedule::Turn<'turn, 'd>,
227        retained::Context<'driver, 'owner, 'd>,
228    ) {
229        (self.app, self.turn, self.driver)
230    }
231
232    pub fn into_drive(
233        self,
234    ) -> (
235        schedule::Turn<'turn, 'd>,
236        retained::Context<'driver, 'owner, 'd>,
237    ) {
238        (self.turn, self.driver)
239    }
240
241    pub(crate) fn into_driver(self) -> driver::Context<'driver, 'd> {
242        self.driver.into_driver()
243    }
244}
245
246impl<'app, 'finish, 'owner, 'epoch, 'd, R> Finish<'app, 'finish, 'owner, 'epoch, 'd, R> {
247    pub fn new(
248        app: pin::Pin<&'app mut R>,
249        install: life::Install<'owner, 'd>,
250        finish: &'finish mut finish::Finish<'epoch, 'd>,
251    ) -> Self {
252        Self {
253            app,
254            install,
255            finish,
256        }
257    }
258
259    pub fn into_parts(
260        self,
261    ) -> (
262        pin::Pin<&'app mut R>,
263        life::Install<'owner, 'd>,
264        &'finish mut finish::Finish<'epoch, 'd>,
265    ) {
266        (self.app, self.install, self.finish)
267    }
268
269    pub fn into_finish(
270        self,
271    ) -> (
272        life::Install<'owner, 'd>,
273        &'finish mut finish::Finish<'epoch, 'd>,
274    ) {
275        (self.install, self.finish)
276    }
277}
278
279struct Drive<'driver, 'turn, 'root, 'd: 'root> {
280    turn: schedule::Turn<'turn, 'd>,
281    driver: retained::Context<'driver, 'root, 'd>,
282}
283
284impl<'driver, 'turn, 'root, 'd: 'root> Drive<'driver, 'turn, 'root, 'd> {
285    fn reborrow(&mut self) -> Drive<'_, '_, 'root, 'd> {
286        Drive {
287            turn: self.turn.reborrow(),
288            driver: self.driver.reborrow(),
289        }
290    }
291}
292
293const fn assert_layout() {
294    assert!(
295        mem::size_of::<Drive<'static, 'static, 'static, 'static>>() == 2 * mem::size_of::<usize>()
296    );
297    assert!(
298        mem::align_of::<Drive<'static, 'static, 'static, 'static>>() == mem::align_of::<usize>()
299    );
300    assert!(mem::size_of::<Install<'static, 'static, 'static, ()>>() == mem::size_of::<usize>());
301    assert!(
302        mem::size_of::<Shutdown<'static, 'static, 'static, 'static, 'static, ()>>()
303            == 3 * mem::size_of::<usize>()
304    );
305    assert!(
306        mem::size_of::<Finish<'static, 'static, 'static, 'static, 'static, ()>>()
307            == 2 * mem::size_of::<usize>()
308    );
309}
310
311const _: () = assert_layout();