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    fn progress(
50        self: pin::Pin<&Self>,
51        region: &region::Token<region::Identity<'d>>,
52    ) -> schedule::Progress<'d>;
53
54    fn force(
55        self: pin::Pin<&mut Self>,
56        turn: schedule::Turn<'_, 'd>,
57        driver: &mut retained::Context<'_, '_, 'd>,
58    );
59}
60
61/// One exact capability invocation joining its pinned owner, selection, and operation.
62pub struct Call<'app, R, P, O> {
63    app: pin::Pin<&'app mut R>,
64    plan: P,
65    op: O,
66}
67
68impl<'app, R, P, O> Call<'app, R, P, O> {
69    /// Joins one runtime-owned operation with its exact pinned root.
70    pub const fn new(app: pin::Pin<&'app mut R>, plan: P, op: O) -> Self {
71        Self { app, plan, op }
72    }
73
74    pub fn into_parts(self) -> (pin::Pin<&'app mut R>, P, O) {
75        (self.app, self.plan, self.op)
76    }
77
78    /// Projects the pinned owner while preserving the selection and operation proofs.
79    pub fn map_owner<U>(
80        self,
81        map: impl FnOnce(pin::Pin<&'app mut R>) -> pin::Pin<&'app mut U>,
82    ) -> Call<'app, U, P, O> {
83        Call {
84            app: map(self.app),
85            plan: self.plan,
86            op: self.op,
87        }
88    }
89}
90
91impl<R, O> Call<'_, R, convert::Infallible, O> {
92    /// Consumes an invocation whose selection proof has no inhabitants.
93    pub fn into_never(self) -> ! {
94        match self {}
95    }
96}
97
98/// One complete coordinator count classified at installation.
99#[derive(Clone, Copy, Debug)]
100pub enum Count {
101    Bounded(U32<0, { schedule::LIMIT as u32 }>),
102    Excess(NonZero<usize>),
103}
104
105impl Count {
106    pub const fn new(value: usize) -> Self {
107        match U32::from_usize(value) {
108            Some(value) => Self::Bounded(value),
109            None => Self::Excess(NonZero::<usize>::MIN.saturating_add(value - 1)),
110        }
111    }
112
113    pub fn sum<const N: usize>(values: [usize; N]) -> Option<Self> {
114        values
115            .into_iter()
116            .try_fold(0usize, |count, value| count.checked_add(value))
117            .map(Self::new)
118    }
119
120    pub const fn get(self) -> usize {
121        match self {
122            Self::Bounded(value) => value.into_usize(),
123            Self::Excess(value) => value.get(),
124        }
125    }
126
127    pub(in crate::executor::raw) fn admit(self) -> Result<(), executor::InstallError> {
128        match self {
129            Self::Bounded(_) => Ok(()),
130            Self::Excess(count) => Err(executor::InstallError::Coordinators {
131                count,
132                limit: schedule::LIMIT,
133            }),
134        }
135    }
136}
137
138/// Coordinator shares prepared once for one installed application.
139#[repr(transparent)]
140pub struct Weights<const N: usize> {
141    values: [U32<0, { schedule::LIMIT as u32 }>; N],
142}
143
144impl<const N: usize> Weights<N> {
145    pub const ZERO: Self = Self {
146        values: [U32::exact::<0>(); N],
147    };
148
149    pub fn prepare(&mut self, values: [usize; N]) -> Option<Count> {
150        let count = Count::sum(values)?;
151        if let Count::Bounded(_) = count {
152            self.values = values.map(|value| {
153                // SAFETY: the admitted sum bounds each nonnegative share and its representation.
154                unsafe { bounded::raw::Proof::assume(value as u32) }.retain()
155            });
156        }
157        Some(count)
158    }
159
160    pub fn values(&self) -> [usize; N] {
161        self.values.map(U32::into_usize)
162    }
163}
164
165pub trait Finishes<'d, R = Self> {
166    fn call<'app, 'finish, 'owner, 'epoch>(
167        finish: Finish<'app, 'finish, 'owner, 'epoch, 'd, R>,
168    ) -> Finish<'app, 'finish, 'owner, 'epoch, 'd, R>;
169}
170
171/// Installation traversal carrying its exact pinned root and owner proof.
172#[must_use]
173pub struct Install<'app, 'owner, 'd, R> {
174    app: pin::Pin<&'app mut R>,
175    install: life::Install<'owner, 'd>,
176}
177
178/// Shutdown traversal carrying its exact pinned root and driver turn.
179#[must_use]
180pub struct Shutdown<'app, 'turn, 'driver, 'owner, 'd: 'owner, R> {
181    app: pin::Pin<&'app mut R>,
182    turn: schedule::Turn<'turn, 'd>,
183    driver: retained::Context<'driver, 'owner, 'd>,
184}
185
186/// Final traversal carrying installation and post-quiescence proofs together.
187#[must_use]
188pub struct Finish<'app, 'finish, 'owner, 'epoch, 'd, R> {
189    app: pin::Pin<&'app mut R>,
190    install: life::Install<'owner, 'd>,
191    finish: &'finish mut finish::Finish<'epoch, 'd>,
192}
193
194impl<'app, 'owner, 'd, R> Install<'app, 'owner, 'd, R> {
195    pub fn new(app: pin::Pin<&'app mut R>, install: life::Install<'owner, 'd>) -> Self {
196        Self { app, install }
197    }
198
199    pub fn into_parts(self) -> (pin::Pin<&'app mut R>, life::Install<'owner, 'd>) {
200        (self.app, self.install)
201    }
202
203    pub fn into_install(self) -> life::Install<'owner, 'd> {
204        self.install
205    }
206}
207
208impl<'app, 'turn, 'driver, 'owner, 'd: 'owner, R> Shutdown<'app, 'turn, 'driver, 'owner, 'd, R> {
209    pub fn new(
210        app: pin::Pin<&'app mut R>,
211        turn: schedule::Turn<'turn, 'd>,
212        driver: retained::Context<'driver, 'owner, 'd>,
213    ) -> Self {
214        Self { app, turn, driver }
215    }
216
217    pub fn into_parts(
218        self,
219    ) -> (
220        pin::Pin<&'app mut R>,
221        schedule::Turn<'turn, 'd>,
222        retained::Context<'driver, 'owner, 'd>,
223    ) {
224        (self.app, self.turn, self.driver)
225    }
226
227    pub fn into_drive(
228        self,
229    ) -> (
230        schedule::Turn<'turn, 'd>,
231        retained::Context<'driver, 'owner, 'd>,
232    ) {
233        (self.turn, self.driver)
234    }
235
236    pub(crate) fn into_driver(self) -> driver::Context<'driver, 'd> {
237        self.driver.into_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    const fn new(
281        turn: schedule::Turn<'turn, 'd>,
282        driver: retained::Context<'driver, 'root, 'd>,
283    ) -> Self {
284        Self { turn, driver }
285    }
286
287    fn reborrow(&mut self) -> Drive<'_, '_, 'root, 'd> {
288        Drive {
289            turn: self.turn.reborrow(),
290            driver: self.driver.reborrow(),
291        }
292    }
293
294    fn turn(&self) -> schedule::Turn<'_, 'd> {
295        self.turn.reborrow()
296    }
297
298    fn driver(&mut self) -> retained::Context<'_, 'root, 'd> {
299        self.driver.reborrow()
300    }
301
302    fn into_parts(
303        self,
304    ) -> (
305        schedule::Turn<'turn, 'd>,
306        retained::Context<'driver, 'root, 'd>,
307    ) {
308        (self.turn, self.driver)
309    }
310
311    fn into_driver(self) -> retained::Context<'driver, 'root, 'd> {
312        self.driver
313    }
314}
315
316const fn assert_layout() {
317    assert!(
318        mem::size_of::<Drive<'static, 'static, 'static, 'static>>() == 2 * mem::size_of::<usize>()
319    );
320    assert!(
321        mem::align_of::<Drive<'static, 'static, 'static, 'static>>() == mem::align_of::<usize>()
322    );
323    assert!(mem::size_of::<Install<'static, 'static, 'static, ()>>() == mem::size_of::<usize>());
324    assert!(
325        mem::size_of::<Shutdown<'static, 'static, 'static, 'static, 'static, ()>>()
326            == 3 * mem::size_of::<usize>()
327    );
328    assert!(
329        mem::size_of::<Finish<'static, 'static, 'static, 'static, 'static, ()>>()
330            == 2 * mem::size_of::<usize>()
331    );
332}
333
334const _: () = assert_layout();