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