Skip to main content

dope_core/driver/receive/
mod.rs

1//! Provided-buffer exhaustion contracts.
2
3use std::{marker, task::Poll};
4
5pub use attempt::Attempt;
6use dope_sys::{
7    engine,
8    memory::buffer,
9    table::{permit, permit::Queue},
10};
11use o3::base::num::bounded;
12
13use crate::{
14    Backend, Engine, driver,
15    driver::{schedule::ready, settings},
16};
17
18pub(crate) mod access;
19mod attempt;
20pub mod credit;
21mod raw;
22pub(crate) mod tokens;
23
24/// Receive-message frame capacity retained by a failed driver probe.
25#[derive(Clone, Copy, PartialEq, Eq, Debug)]
26#[repr(transparent)]
27pub struct Capacity(bounded::U64<0, { u64::MAX }>);
28
29/// Exact receive-message frame length retained by a failed driver probe.
30#[derive(Clone, Copy, PartialEq, Eq, Debug)]
31#[repr(transparent)]
32pub struct Length(bounded::U64<0, { u64::MAX }>);
33
34impl From<bounded::U64<0, { u64::MAX }>> for Capacity {
35    fn from(value: bounded::U64<0, { u64::MAX }>) -> Self {
36        Self(value)
37    }
38}
39
40impl From<bounded::U64<0, { u64::MAX }>> for Length {
41    fn from(value: bounded::U64<0, { u64::MAX }>) -> Self {
42        Self(value)
43    }
44}
45
46/// Exact out-of-range provided-buffer selection observed from a backend.
47#[derive(Clone, Copy, PartialEq, Eq, Debug)]
48#[repr(transparent)]
49pub struct Selection(<Backend as buffer::Selection<settings::Buffers>>::Error);
50
51impl Selection {
52    pub(crate) fn from_native<E>(value: E) -> Self
53    where
54        Backend: buffer::Selection<settings::Buffers, Error = E>,
55    {
56        Self(value)
57    }
58}
59
60/// Exact ready key owned by provided-buffer receive authority.
61#[repr(transparent)]
62pub(crate) struct Proof(ready::Stored);
63
64impl Proof {
65    pub(in crate::driver) const fn new(key: ready::Stored) -> Self {
66        Self(key)
67    }
68
69    pub(in crate::driver) const fn key(&self) -> ready::Stored {
70        self.0
71    }
72
73    pub(crate) fn release(
74        permit: &<crate::Permits as Queue>::Capability,
75        store: &crate::Permits,
76        driver: driver::Reference<'_>,
77    ) {
78        while let Some((index, key)) = store.grant_one(permit) {
79            let stale = match driver.ready().arena().try_receive(Self::new(key)) {
80                Ok(()) => continue,
81                Err(stale) => stale.key(),
82            };
83            // grant_one parked this exact key; try_receive invokes no callback
84            // and cannot mutate the permit store before its matching removal.
85            let _ = store.take(permit, index, stale);
86        }
87    }
88}
89
90/// Driver-branded proof of one terminal provided-buffer exhaustion.
91/// Retains the driver's invariant lifetime and thread confinement without storage.
92#[repr(transparent)]
93pub struct Exhausted<'d> {
94    driver: marker::PhantomData<driver::Reference<'d>>,
95}
96
97/// Exact ready-target registration for provided-buffer exhaustion.
98#[must_use = "a receive registration must be polled, cancelled, or retired"]
99#[repr(transparent)]
100pub struct Registration<'d> {
101    target: ready::Target<'d>,
102    permit: <crate::Permits as Queue>::Capability,
103}
104
105/// A registration no longer names the live receive target that created it.
106#[derive(Clone, Copy, Debug, PartialEq, Eq)]
107pub struct Stale;
108
109/// The selected backend does not provide receive registrations.
110#[derive(Clone, Copy, Debug, PartialEq, Eq)]
111pub struct Absent;
112
113impl<'d> Exhausted<'d> {
114    pub(crate) const fn from_driver(_driver: driver::Reference<'d>) -> Self {
115        Self {
116            driver: marker::PhantomData,
117        }
118    }
119
120    /// Consumes terminal exhaustion for this generative driver scope.
121    pub(in crate::driver) fn retire(self) -> dope_sys::Errno {
122        dope_sys::Errno::NO_BUFFER_SPACE
123    }
124}
125
126impl<'d, P> Registration<'d>
127where
128    crate::Permits: Queue<Capability = P>,
129{
130    /// Acquires provided-buffer receive authority for this target.
131    pub fn try_acquire(target: ready::Target<'d>) -> Result<Self, Absent> {
132        let permit = crate::Permits::try_acquire().map_err(|permit::Absent| Absent)?;
133        Ok(Self { target, permit })
134    }
135
136    /// Retires a registration when the selected backend provides one.
137    pub fn clear(target: ready::Target<'d>) {
138        let reg = match Self::try_acquire(target) {
139            Ok(reg) => reg,
140            Err(Absent) => return,
141        };
142        reg.retire();
143    }
144
145    /// Registers exhaustion before permitting one optimistic retry.
146    pub fn exhausted(
147        self,
148        proof: Exhausted<'d>,
149    ) -> Result<Poll<Attempt<'d>>, (Exhausted<'d>, Stale)> {
150        let Self { target, permit } = self;
151        let (driver, key) = target.receive();
152        if !Self::is_live(driver, key) {
153            return Err((proof, Stale));
154        }
155        let store = driver.receive().exhausted();
156        match store.try_arm(&permit, Index::from_key(key), key) {
157            Ok(()) => Ok(Poll::Ready(Attempt::new(permit, driver))),
158            Err(key) => Self::take(permit, store, driver, key).map_err(|stale| (proof, stale)),
159        }
160    }
161
162    /// Observes the exact central registration after its target was woken.
163    /// Stale targets discard any leftover grant before reporting staleness.
164    pub fn resume(self) -> Result<Poll<Attempt<'d>>, Stale> {
165        let Self { target, permit } = self;
166        let (driver, key) = target.receive();
167        let store = driver.receive().exhausted();
168        if !Self::is_live(driver, key) {
169            return match Self::cancel_inner(&permit, store, key) {
170                Ok(()) | Err(Stale) => Err(Stale),
171            };
172        }
173        Self::take(permit, store, driver, key)
174    }
175
176    /// Cancels this exact registration and discards an unconsumed grant.
177    pub fn cancel(self) -> Result<(), Stale> {
178        let Self { target, permit } = self;
179        let (driver, key) = target.receive();
180        Self::cancel_inner(&permit, driver.receive().exhausted(), key)
181    }
182
183    /// Retires this registration, discarding a matching unconsumed grant.
184    /// A stale registration has no matching grant to retire.
185    pub fn retire(self) {
186        match self.cancel() {
187            Ok(()) | Err(Stale) => {}
188        }
189    }
190
191    fn is_live(driver: driver::Reference<'_>, key: ready::Stored) -> bool {
192        driver.ready().arena().is_dispatch(Proof::new(key))
193    }
194
195    fn take(
196        permit: P,
197        store: &'d crate::Permits,
198        driver: driver::Reference<'d>,
199        key: ready::Stored,
200    ) -> Result<Poll<Attempt<'d>>, Stale> {
201        match store.take(&permit, Index::from_key(key), key) {
202            permit::State::Waiting => Ok(Poll::Pending),
203            permit::State::Granted(_) => Ok(Poll::Ready(Attempt::new(permit, driver))),
204            permit::State::Gone | permit::State::Stale => Err(Stale),
205        }
206    }
207
208    fn cancel_inner(permit: &P, store: &crate::Permits, key: ready::Stored) -> Result<(), Stale> {
209        match store.cancel(permit, Index::from_key(key), key) {
210            permit::State::Gone | permit::State::Waiting | permit::State::Granted(_) => Ok(()),
211            permit::State::Stale => Err(Stale),
212        }
213    }
214}
215
216const _: () = {
217    assert!(
218        std::mem::size_of::<Selection>()
219            == std::mem::size_of::<<Engine as engine::Buffer>::Selection>()
220    );
221    assert!(
222        std::mem::align_of::<Selection>()
223            == std::mem::align_of::<<Engine as engine::Buffer>::Selection>()
224    );
225    assert!(std::mem::size_of::<Proof>() == std::mem::size_of::<ready::Stored>());
226    assert!(std::mem::align_of::<Proof>() == std::mem::align_of::<ready::Stored>());
227    assert!(std::mem::size_of::<Exhausted<'static>>() == 0);
228    assert!(std::mem::align_of::<Exhausted<'static>>() == 1);
229    assert!(std::mem::size_of::<<crate::Permits as Queue>::Capability>() == 0);
230    assert!(std::mem::size_of::<permit::Absent>() == 0);
231    assert!(std::mem::size_of::<Absent>() == 0);
232    assert!(std::mem::size_of::<Registration<'static>>() == 2 * std::mem::size_of::<usize>());
233    assert!(
234        std::mem::size_of::<Registration<'static>>()
235            == std::mem::size_of::<ready::Target<'static>>()
236    );
237    assert!(
238        std::mem::align_of::<Registration<'static>>()
239            == std::mem::align_of::<ready::Target<'static>>()
240    );
241};
242
243/// Compact receive-permit position retaining its ready-arena domain.
244#[derive(Clone, Copy)]
245#[repr(transparent)]
246pub struct Index(ready::DynamicIndex);
247
248impl Index {
249    const fn from_key(key: ready::Stored) -> Self {
250        Self(key.dense())
251    }
252}