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