Skip to main content

dope_core/driver/retained/flight/
mod.rs

1use crate::{driver::life::finish, io::fd::handles};
2pub mod cancel;
3mod complete;
4pub(crate) mod raw;
5mod request;
6mod slots;
7pub mod storage;
8use std::{marker, mem};
9
10pub(crate) use complete::Complete;
11use dope_sys::{engine::admit::Cancelled, table::token::host};
12use o3::{alloc, base::marker::ThreadBound};
13pub(crate) use request::Request;
14use route::table;
15pub use slots::Slots;
16use table::conn;
17
18use crate::{
19    driver::{
20        self,
21        route::{self, kind},
22    },
23    io::fd::domain::retire,
24};
25
26type Invariant<'d> = (driver::Invariant<'d>, marker::PhantomData<ThreadBound>);
27
28const INDEX_BITS: u32 = route::SLOT_BITS;
29const GENERATION_BITS: u32 = 32;
30
31#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32#[repr(C)]
33struct Target {
34    epoch: route::Epoch,
35    slot: [u8; 3],
36    auxiliary: [u8; 3],
37    kind: kind::Native,
38    route: route::Route,
39}
40
41impl Target {
42    fn new<Tag: route::Tag, C: kind::Flight>(target: route::Operation<'_, Tag, C>) -> Self {
43        let parts = target.parts();
44        Self {
45            epoch: parts.epoch(),
46            slot: parts.slot().into_le24(),
47            auxiliary: [0; 3],
48            kind: C::FLIGHT,
49            route: Tag::ROUTE,
50        }
51    }
52
53    fn token(self) -> route::Token {
54        let [a, b, c] = self.slot;
55        let [d, e, f] = self.auxiliary;
56        route::Token::from_flight(self.epoch, [a, b, c, d, e, f], self.kind, self.route)
57    }
58
59    fn bind<'d, C: kind::Class>(self, driver: driver::Invariant<'d>) -> route::Erased<'d, C> {
60        route::Erased {
61            token: self.token(),
62            driver,
63            class: marker::PhantomData,
64        }
65    }
66}
67
68#[repr(transparent)]
69pub(crate) struct Arena(storage::Flights<Target, INDEX_BITS, GENERATION_BITS>);
70
71/// Exact kernel-flight capacity derived from an existing typed resource bound.
72#[derive(Clone, Copy, Eq, PartialEq)]
73#[repr(transparent)]
74pub struct Capacity(usize);
75
76/// Typed flight-group requirements retained until their shared preparation.
77pub struct Need<Tags, const GROUPS: usize = 1> {
78    caps: [Capacity; GROUPS],
79    tags: marker::PhantomData<Tags>,
80}
81
82/// Exact connection scaling rejected by the kernel-flight slot bound.
83#[derive(Clone, Copy, Eq, PartialEq, Debug)]
84pub enum ScaleError {
85    Product {
86        capacity: conn::Capacity,
87        factor: usize,
88    },
89    Limit {
90        actual: usize,
91        maximum: usize,
92    },
93}
94
95impl Capacity {
96    pub const fn fixed<const FLIGHTS: usize>() -> Self {
97        const { assert!(FLIGHTS > 0 && FLIGHTS <= route::SLOT_MASK as usize + 1) };
98        Self(FLIGHTS)
99    }
100
101    pub const fn table(capacity: table::Capacity) -> Self {
102        Self(capacity.count().get())
103    }
104
105    pub const fn connections<const PER_CONNECTION: usize>(
106        capacity: conn::Capacity,
107    ) -> Result<Self, ScaleError> {
108        const { assert!(PER_CONNECTION > 0) };
109        let Some(total) = (capacity.raw() as usize).checked_mul(PER_CONNECTION) else {
110            return Err(ScaleError::Product {
111                capacity,
112                factor: PER_CONNECTION,
113            });
114        };
115        let maximum = route::SLOT_MASK as usize + 1;
116        if total > maximum {
117            return Err(ScaleError::Limit {
118                actual: total,
119                maximum,
120            });
121        }
122        Ok(Self(total))
123    }
124
125    pub const fn capped<const MAX: usize>(capacity: table::Capacity) -> Self {
126        const { assert!(MAX > 0) };
127        let capacity = capacity.count().get();
128        Self(if capacity < MAX { capacity } else { MAX })
129    }
130
131    pub(crate) const fn get(self) -> usize {
132        self.0
133    }
134}
135
136impl<Tag: route::Tag> Need<Tag> {
137    pub const fn new(cap: Capacity) -> Self {
138        Self {
139            caps: [cap],
140            tags: marker::PhantomData,
141        }
142    }
143}
144
145impl<A: route::Tag> Need<A> {
146    pub fn pair<B: route::Tag>(self, other: Need<B>) -> Need<(A, B), 2> {
147        let Self {
148            caps: [first],
149            tags: marker::PhantomData,
150        } = self;
151        let Need {
152            caps: [second],
153            tags: marker::PhantomData,
154        } = other;
155        Need {
156            caps: [first, second],
157            tags: marker::PhantomData,
158        }
159    }
160}
161
162impl<A: route::Tag, B: route::Tag> Need<(A, B), 2> {
163    pub fn push<C: route::Tag>(self, other: Need<C>) -> Need<(A, B, C), 3> {
164        let Self {
165            caps: [first, second],
166            tags: marker::PhantomData,
167        } = self;
168        let Need {
169            caps: [third],
170            tags: marker::PhantomData,
171        } = other;
172        Need {
173            caps: [first, second, third],
174            tags: marker::PhantomData,
175        }
176    }
177}
178
179impl<Tags, const GROUPS: usize> Need<Tags, GROUPS> {
180    const fn into_caps(self) -> [Capacity; GROUPS] {
181        self.caps
182    }
183}
184
185#[must_use = "prepared flight slots must be committed"]
186pub struct Prepared<'a, 'd, Tags, const GROUPS: usize = 1> {
187    prepared: storage::Prepared<'a, 'd, Target, INDEX_BITS, GENERATION_BITS, GROUPS>,
188    driver: driver::Invariant<'d>,
189    tags: marker::PhantomData<Tags>,
190}
191
192#[must_use = "a validated flight vacancy must be reserved or released"]
193pub(crate) struct Vacant<'slot, 'd, Tag: route::Tag, C: kind::Class = <Tag as route::Tag>::Class> {
194    vacancy: storage::Vacant<'slot, 'd, Target, INDEX_BITS, GENERATION_BITS>,
195    target: Target,
196    driver: Invariant<'d>,
197    class: marker::PhantomData<(Tag, C)>,
198}
199
200#[must_use = "a reserved flight must be committed or released"]
201#[repr(transparent)]
202pub(crate) struct Reserved<'d, C: kind::Class = kind::Any> {
203    reservation: storage::Reserved<'d, Target, INDEX_BITS, GENERATION_BITS>,
204    driver: Invariant<'d>,
205    class: marker::PhantomData<C>,
206}
207
208/// Exact kernel-flight authority bound invariantly to its driver.
209/// Dropping this owner preserves any pending native completion.
210#[must_use = "a live flight must reach terminal completion or quiescence"]
211#[repr(transparent)]
212pub struct Flight<'d, C: kind::Class = kind::Any> {
213    flight: storage::Lease<'d, Target, INDEX_BITS, GENERATION_BITS>,
214    driver: Invariant<'d>,
215    class: marker::PhantomData<C>,
216}
217
218pub(crate) struct Drain<'q, 'd> {
219    drain: storage::Drain<'q, Target, INDEX_BITS, GENERATION_BITS>,
220    driver: driver::Reference<'d>,
221}
222
223impl Arena {
224    pub(crate) fn new() -> Self {
225        Self(storage::Flights::new())
226    }
227
228    pub(in crate::driver) fn is_pending(&self) -> bool {
229        self.0.is_pending()
230    }
231
232    pub(in crate::driver) fn finish(&self) {
233        self.0.finish();
234    }
235
236    pub(crate) fn try_prepare<'a, 'd, Tags, const GROUPS: usize>(
237        &'a mut self,
238        need: Need<Tags, GROUPS>,
239        driver: driver::Reference<'d>,
240    ) -> Result<Prepared<'a, 'd, Tags, GROUPS>, alloc::Error> {
241        let access = raw::Access::new(&mut self.0, driver);
242        let (prepared, driver) = access.try_batch(need.into_caps().map(Capacity::get))?;
243        Ok(Prepared {
244            prepared,
245            driver,
246            tags: marker::PhantomData,
247        })
248    }
249}
250
251impl<'d, Tags, const GROUPS: usize> Prepared<'_, 'd, Tags, GROUPS> {
252    fn commit(
253        self,
254    ) -> (
255        [storage::Slots<'d, Target, INDEX_BITS, GENERATION_BITS>; GROUPS],
256        Invariant<'d>,
257    ) {
258        let Self {
259            prepared,
260            driver,
261            tags: marker::PhantomData,
262        } = self;
263        let slots = prepared.groups();
264        (slots, (driver, marker::PhantomData))
265    }
266}
267
268impl<'d, Tag: route::Tag> Prepared<'_, 'd, Tag> {
269    pub fn slots(self) -> Slots<'d, Tag> {
270        let ([slots], driver) = self.commit();
271        Slots::new(slots, driver)
272    }
273}
274
275impl<'d, A: route::Tag, B: route::Tag> Prepared<'_, 'd, (A, B), 2> {
276    pub fn slots(self) -> (Slots<'d, A>, Slots<'d, B>) {
277        let ([first, second], driver) = self.commit();
278        (Slots::new(first, driver), Slots::new(second, driver))
279    }
280}
281
282impl<'d, A: route::Tag, B: route::Tag, C: route::Tag> Prepared<'_, 'd, (A, B, C), 3> {
283    pub fn slots(self) -> (Slots<'d, A>, Slots<'d, B>, Slots<'d, C>) {
284        let ([first, second, third], driver) = self.commit();
285        (
286            Slots::new(first, driver),
287            Slots::new(second, driver),
288            Slots::new(third, driver),
289        )
290    }
291}
292
293impl<'d, Tag: route::Tag, C: kind::Class> Vacant<'_, 'd, Tag, C> {
294    pub(crate) fn reserve(self) -> Reserved<'d, C> {
295        Reserved {
296            reservation: self.vacancy.reserve(self.target),
297            driver: self.driver,
298            class: marker::PhantomData,
299        }
300    }
301}
302
303impl<'d, C: kind::Class> Reserved<'d, C> {
304    pub(crate) fn key(&self) -> raw::Echo {
305        raw::Echo::from_inner(self.reservation.echo())
306    }
307
308    pub(crate) fn commit(self) -> Flight<'d, C> {
309        Flight {
310            flight: self.reservation.commit(),
311            driver: self.driver,
312            class: marker::PhantomData,
313        }
314    }
315}
316
317impl<'q, 'd> Drain<'q, 'd> {
318    pub(crate) fn new(arena: &'q Arena, driver: driver::Reference<'d>) -> Self {
319        Self {
320            drain: arena.0.drain(),
321            driver,
322        }
323    }
324}
325
326impl<'q, 'd> host::Drain for Drain<'q, 'd> {
327    type Driver = driver::Reference<'d>;
328
329    fn driver(&self) -> Self::Driver {
330        self.driver
331    }
332
333    type Key = raw::Echo;
334    type Returned = retire::Returned;
335    type Flight = Complete<'q, 'd>;
336    type Echo = retire::Echo<'d>;
337    type Class = handles::Retirement;
338
339    fn bind(&self, key: raw::Echo) -> Option<Complete<'q, 'd>> {
340        self.drain.bind(key.into_inner()).map(|bound| Complete {
341            completion: bound,
342            driver: self.driver,
343            class: marker::PhantomData,
344        })
345    }
346
347    fn retired(&self, returned: Self::Returned) -> host::Closed<Self::Echo, Self::Class> {
348        use host::Closed;
349        match self.driver.descriptors().retirement().bind(returned) {
350            retire::Bind::Ready(echo) => Closed::Ready(echo),
351            retire::Bind::Class {
352                echo,
353                expected,
354                observed,
355            } => Closed::Class {
356                echo,
357                expected,
358                observed,
359            },
360            retire::Bind::Missing => Closed::Missing,
361        }
362    }
363}
364
365impl<'d, C: kind::Class> Flight<'d, C> {
366    pub(crate) fn is_pending(&self) -> bool {
367        self.flight.is_pending()
368    }
369
370    pub(crate) fn key(&self) -> raw::Echo {
371        raw::Echo::from_inner(self.flight.echo())
372    }
373
374    pub fn target(&self) -> route::Erased<'d, C> {
375        self.flight.value().bind(self.driver.0)
376    }
377
378    pub fn matches(&self, target: route::Erased<'d, C>) -> bool {
379        self.target().matches(target)
380    }
381
382    pub(in crate::driver) fn finish(mut self, proof: &mut finish::Finish<'_, 'd>) {
383        self.driver.0 = proof.brand();
384    }
385}
386
387const _: () = {
388    assert!(mem::size_of::<Arena>() == 4 * mem::size_of::<usize>());
389    assert!(mem::align_of::<Arena>() == mem::align_of::<usize>());
390    assert!(mem::size_of::<Target>() == mem::size_of::<route::Token>());
391    assert!(mem::align_of::<Target>() == mem::align_of::<route::Token>());
392    assert!(mem::size_of::<raw::Echo>() == mem::size_of::<usize>());
393    assert!(mem::size_of::<Flight<'static>>() == mem::size_of::<usize>());
394    assert!(mem::size_of::<Option<Flight<'static>>>() == mem::size_of::<usize>());
395    assert!(mem::size_of::<Reserved<'static>>() == mem::size_of::<usize>());
396    assert!(
397        mem::size_of::<Vacant<'static, 'static, route::KeyTag<1>>>()
398            == mem::size_of::<storage::Vacant<'static, 'static, Target, INDEX_BITS, GENERATION_BITS>>(
399            ) + mem::size_of::<route::Token>()
400    );
401    assert!(mem::size_of::<Drain<'static, 'static>>() == 2 * mem::size_of::<usize>());
402    assert!(mem::size_of::<Complete<'static, 'static>>() == 2 * mem::size_of::<usize>());
403    assert!(mem::size_of::<Slots<'static, route::KeyTag<1>>>() == mem::size_of::<usize>());
404};
405
406pub(crate) struct Mismatch<'q, 'd> {
407    pub(crate) bound: Complete<'q, 'd>,
408    pub(crate) expected: kind::Native,
409    pub(crate) observed: kind::Native,
410}
411
412impl<'d, C: kind::Class> Flight<'d, C> {
413    /// Submits cancellation for this exact flight without releasing its owners.
414    pub fn try_cancel(
415        &mut self,
416        driver: &mut driver::Context<'_, 'd>,
417    ) -> Result<Cancelled, cancel::Error> {
418        driver.native().try_cancel(self)
419    }
420}
421
422impl<'d, C: kind::Class> Flight<'d, C> {
423    /// Cancellation reserves no new flight, so capacity refusal is queue fullness.
424    pub fn try_stop(
425        &mut self,
426        driver: &mut driver::Context<'_, 'd>,
427    ) -> Result<cancel::Outcome, cancel::Failure> {
428        let status = match self.try_cancel(driver) {
429            Ok(status) => status,
430            Err(cancel::Error::Full(_)) => {
431                return Ok(cancel::Outcome::Deferred);
432            }
433            Err(cancel::Error::Rejected(cause)) => return Err(cause),
434        };
435        Ok(match status {
436            Cancelled::Submitted => cancel::Outcome::Submitted,
437            Cancelled::Queued => cancel::Outcome::Queued,
438            Cancelled::Completed => cancel::Outcome::Completed,
439        })
440    }
441}