Skip to main content

dope_core/driver/life/
mod.rs

1use std::{marker, mem, os::fd, pin};
2
3use dope_sys::memory::Context as _;
4pub(in crate::driver) use epochs::Final;
5use finish::Finish;
6use o3::{
7    base::{
8        cell::{brand, region},
9        marker::ThreadBound,
10    },
11    buffer,
12    buffer::storage::{provided, provided::fixed},
13};
14use plans::{Build, Create, Direct, Provided};
15use schedule::state::Core;
16use state::scope;
17
18use crate::{
19    Engine, driver,
20    driver::{
21        life::recovery::{Observe, Recover},
22        retained::flight,
23        route::lease::Registry,
24        schedule,
25        schedule::state,
26        storage,
27        storage::{resident, resident::Alloc},
28    },
29    io,
30};
31
32pub mod creation;
33pub mod domain;
34pub mod finish;
35pub(crate) mod native;
36mod plans;
37pub mod recovery;
38
39/// Application completions still require ordinary driver dispatch before startup.
40#[derive(Clone, Copy, Debug, Eq, PartialEq)]
41pub struct Busy;
42
43/// Owner-bound primitives for generated installation roots.
44pub mod raw;
45
46/// Runs once inside the generation which owns a built storage output and source.
47pub trait Operation<S: storage::Plan, Q: ?Sized>: Sized {
48    type Output;
49
50    fn run<'a, 'p, 'd>(
51        self,
52        scope: Scope<'a, 'd>,
53        storage: storage::Loan<'a, 'p, 'd, S>,
54        source: &'a Q,
55    ) -> Self::Output
56    where
57        'd: 'p,
58        'p: 'a,
59        'd: 'a,
60        Self: 'd,
61        S: 'd,
62        Q: 'd;
63}
64
65/// Mutable driver-local authority owned by one generative scope.
66/// `driver::Context` lends this root as one pointer.
67pub(crate) struct Local<'d> {
68    pub(crate) driver: driver::Reference<'d>,
69    pub(crate) backend: fixed::Loan<'d, Engine>,
70    pub(in crate::driver) retry: bool,
71    pub(crate) flights: &'d mut flight::Arena,
72    pub(in crate::driver) resident: Alloc<'d>,
73    pub(in crate::driver) routes: Registry,
74    pub(in crate::driver) region: (
75        region::Token<region::Identity<'d>>,
76        region::Token<region::Identity<'d, 1>>,
77    ),
78    pub(crate) lifecycle: Lifecycle<'d>,
79}
80
81/// Generation-owned source and the policy responsible for its transitions.
82pub(crate) struct Lifecycle<'d> {
83    pub(crate) source: Option<fd::BorrowedFd<'d>>,
84    pub(crate) resuming: bool,
85    pub(crate) pending: bool,
86    pub(crate) report: &'d mut dyn FnMut(io::Reclaimed),
87    pub(in crate::driver) recover: &'d dyn recovery::Recover,
88}
89
90impl Lifecycle<'_> {
91    pub(crate) fn report(&mut self, event: io::Reclaimed) {
92        if matches!(event, io::Reclaimed::Shutdown) {
93            let owned = self.source.take().is_some();
94            if self.resuming && owned {
95                self.pending = true;
96                return;
97            }
98        }
99        (self.report)(event);
100    }
101}
102
103pub(in crate::driver) struct State<'d> {
104    local: Local<'d>,
105    work: Core<'d>,
106    token: brand::Token<brand::Identity<'d>>,
107}
108
109impl<'d> State<'d> {
110    fn new(local: Local<'d>, token: brand::Token<brand::Identity<'d>>) -> Self {
111        Self {
112            work: Core::new(local.driver),
113            local,
114            token,
115        }
116    }
117}
118
119mod epochs;
120
121pub(in crate::driver) struct Lease<'a> {
122    driver: pin::Pin<&'a mut driver::Driver>,
123}
124
125/// One lexical view of the hidden owner for an exact driver generation.
126///
127#[repr(transparent)]
128pub struct Scope<'a, 'd> {
129    state: &'a mut State<'d>,
130}
131
132impl<'a, 'd> Scope<'a, 'd> {
133    fn new(state: &'a mut State<'d>) -> Self {
134        Self { state }
135    }
136
137    pub fn context(&mut self) -> driver::Context<'_, 'd> {
138        let state = &mut *self.state;
139        driver::Context::new(&mut state.local)
140    }
141
142    pub fn token(&mut self) -> &mut brand::Token<brand::Identity<'d>> {
143        &mut self.state.token
144    }
145
146    /// Runs with the sole schedule authority for this driver scope.
147    pub fn with_turn<R>(
148        &mut self,
149        run: impl for<'scope> FnOnce(
150            &'scope mut brand::Token<brand::Identity<'d>>,
151            driver::Context<'scope, 'd>,
152            scope::Scope<'scope, 'd>,
153        ) -> R,
154    ) -> R {
155        let state = &mut *self.state;
156        let ctx = driver::Context::new(&mut state.local);
157        run(&mut state.token, ctx, scope::Scope::new(&mut state.work))
158    }
159
160    /// Runs a driver turn that performs no branded application projection.
161    pub fn with_driver<R>(
162        &mut self,
163        run: impl for<'scope> FnOnce(driver::Context<'scope, 'd>, scope::Scope<'scope, 'd>) -> R,
164    ) -> R {
165        let state = &mut *self.state;
166        let ctx = driver::Context::new(&mut state.local);
167        run(ctx, scope::Scope::new(&mut state.work))
168    }
169
170    pub fn driver_ref(&self) -> driver::Reference<'d> {
171        self.state.local.driver
172    }
173
174    /// Admits startup polling before any application completion can be emitted.
175    /// Keep exclusive scope authority and do not submit operations during startup.
176    pub fn try_boot(&self) -> Result<(), Busy> {
177        if self.state.local.flights.is_pending() {
178            Err(Busy)
179        } else {
180            Ok(())
181        }
182    }
183
184    /// Drains every retained operation before captured owners may be released.
185    /// A failed native transition retains its owner and invokes the fatal policy.
186    /// Only successful native quiescence permits the borrowed scope to return.
187    pub fn quiesce(&mut self) {
188        let state = &mut *self.state;
189        let ctx = driver::Context::new(&mut state.local);
190        Final::suspend(ctx).resume()
191    }
192
193    /// Quiesces before lending finish authority, then reaps the released owner.
194    /// A failed transition invokes the fatal policy with the exact native owner.
195    #[doc(hidden)]
196    pub fn finish<R>(
197        &mut self,
198        forced: bool,
199        run: impl for<'finish> FnOnce(
200            &mut brand::Token<brand::Identity<'d>>,
201            &mut Finish<'finish, 'd>,
202        ) -> R,
203    ) -> R {
204        let state = &mut *self.state;
205        let ctx = driver::Context::new(&mut state.local);
206        let last = Final::suspend(ctx);
207        let mut finish = Finish::new(last, forced);
208        let output = run(&mut state.token, &mut finish);
209        finish.resume();
210        output
211    }
212}
213
214impl<'a> Lease<'a> {
215    pub(crate) fn take(driver: pin::Pin<&'a mut driver::Driver>) -> Self {
216        Self { driver }
217    }
218
219    fn run_with<S, Q: ?Sized, O>(
220        self,
221        plan: S,
222        source: &domain::Source<Q>,
223        op: O,
224        report: &mut dyn Observe,
225    ) -> O::Output
226    where
227        S: storage::Direct,
228        O: Operation<S, Q>,
229    {
230        self.scope(
231            source,
232            Direct {
233                plan,
234                operation: op,
235            },
236            report,
237        )
238    }
239
240    fn try_run_with<S, Q: ?Sized, O>(
241        self,
242        plan: S,
243        source: &domain::Source<Q>,
244        op: O,
245        report: &mut dyn Observe,
246    ) -> Result<O::Output, domain::Rejected<S::Error, O>>
247    where
248        S: storage::Build,
249        O: Operation<S, Q>,
250    {
251        self.scope(
252            source,
253            Build {
254                plan,
255                operation: op,
256            },
257            report,
258        )
259    }
260
261    fn try_create<S, Q: ?Sized, O>(
262        self,
263        plan: S,
264        source: &domain::Source<Q>,
265        op: O,
266        report: &mut dyn Observe,
267    ) -> Result<O::Output, domain::Rejected<S::Error, O>>
268    where
269        S: storage::Create,
270        O: Operation<S, Q>,
271    {
272        self.scope(
273            source,
274            Create {
275                plan,
276                operation: op,
277            },
278            report,
279        )
280    }
281
282    fn run_scope<A, Q: ?Sized, O>(
283        self,
284        arenas: A,
285        source: &domain::Source<Q>,
286        op: O,
287        report: &mut dyn Observe,
288    ) -> O::Output
289    where
290        A: buffer::raw::Arenas,
291        O: Operation<storage::Scope<A>, Q>,
292    {
293        let runtime = &mut self.driver.get_mut().runtime;
294        let (report, recover) = report.split();
295        let root = Root {
296            flights: &mut runtime.flights,
297            resident: &mut runtime.resident,
298            source,
299            report,
300            recover,
301        };
302        runtime.shared.run(
303            pin::pin!((root, arenas)),
304            runtime.shared.context().buffer().layout().0.accounts(),
305            &mut runtime.backend,
306            Provided(op),
307        )
308    }
309
310    fn scope<'b, Q: ?Sized, O>(
311        self,
312        source: &'b domain::Source<Q>,
313        op: O,
314        report: &'b mut dyn Observe,
315    ) -> O::Output
316    where
317        'a: 'b,
318        O: fixed::Operation<Root<'b, Q>, driver::Buffer, driver::Shared, Terminal = crate::Engine>,
319    {
320        let runtime = &mut self.driver.get_mut().runtime;
321        let (report, recover) = report.split();
322        let root = Root {
323            flights: &mut runtime.flights,
324            resident: &mut runtime.resident,
325            source,
326            report,
327            recover,
328        };
329        runtime.shared.run(
330            pin::pin!(root),
331            runtime.shared.context().buffer().layout().0.accounts(),
332            &mut runtime.backend,
333            op,
334        )
335    }
336}
337
338const _: () = {
339    assert!(mem::size_of::<Scope<'static, 'static>>() == mem::size_of::<&mut ()>());
340    assert!(mem::align_of::<Scope<'static, 'static>>() == mem::align_of::<&mut ()>());
341};
342
343struct Root<'a, Q: ?Sized> {
344    flights: &'a mut flight::Arena,
345    resident: &'a mut resident::Arena,
346    source: &'a domain::Source<Q>,
347    report: &'a mut dyn FnMut(io::Reclaimed),
348    recover: &'a dyn Recover,
349}
350
351impl<Q: ?Sized> Root<'_, Q> {
352    fn enter<'d>(
353        &'d mut self,
354        shared: provided::Root<'d, driver::Buffer, driver::Shared, ()>,
355        token: brand::Token<brand::Identity<'d>>,
356        regions: (
357            region::Token<region::Identity<'d>>,
358            region::Token<region::Identity<'d, 1>>,
359        ),
360        backend: fixed::Loan<'d, Engine>,
361    ) -> (State<'d>, &'d Q) {
362        let alloc = self.resident.enter(&regions.0);
363        let local = Local {
364            driver: driver::Reference::new(shared),
365            backend,
366            retry: false,
367            flights: &mut *self.flights,
368            resident: alloc,
369            routes: Registry::new(),
370            region: regions,
371            lifecycle: Lifecycle {
372                source: self.source.descriptor(),
373                resuming: false,
374                pending: false,
375                report: &mut *self.report,
376                recover: self.recover,
377            },
378        };
379        let state = State::new(local, token);
380        (state, &self.source.value)
381    }
382}
383
384/// Proof that nested resources are installed beneath their pinned owner.
385#[must_use]
386pub struct Install<'a, 'd> {
387    owner: marker::PhantomData<(&'a mut raw::Anchor<'a>, ThreadBound)>,
388    _driver: driver::Invariant<'d>,
389}
390
391impl<'a, 'd> Install<'a, 'd> {
392    /// Binds installation to `root` and its driver generation.
393    pub fn new<T: raw::Root<'a>>(root: T, driver: driver::Reference<'d>) -> Self {
394        Self {
395            owner: root.anchor().owner(),
396            _driver: driver.brand,
397        }
398    }
399}
400
401const _: () = {
402    assert!(mem::size_of::<Install<'static, 'static>>() == 0);
403    assert!(mem::align_of::<Install<'static, 'static>>() == 1);
404};