Skip to main content

dope_core/driver/result/
mod.rs

1pub mod poll;
2
3use std::mem;
4
5use dope_sys::{
6    io::reactor::{Full, complete},
7    kernel, probe,
8    ring::{layout, prepare::Feature},
9};
10use o3::{alloc, buffer::pool, depot::arena::slab::Vacancy};
11
12use crate::{
13    Engine,
14    driver::{
15        receive,
16        result::poll::fault,
17        route::{indices, table::bounds},
18        settings::errors,
19        storage,
20    },
21    io::{socket, transfer},
22};
23
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
25pub enum IoOperation {
26    Entropy,
27    ReactorCreate,
28    MapRing,
29    RegisterReactor,
30    CancelRegistrations,
31    RegisterOpcodes,
32    RegisterFileTable,
33    RegisterFileRange,
34    MapBuffers,
35    UnmapRing,
36    UnmapBuffers,
37    PopulateBuffers,
38    RegisterProvidedBuffers,
39    RegisterCanaryBuffers,
40    UnregisterCanaryBuffers,
41    InstallReceiveFile,
42    RemoveReceiveFile,
43    InstallReceiveMessageFile,
44    RemoveReceiveMessageFile,
45    Probe(Probe),
46}
47
48#[derive(Clone, Copy, Debug, PartialEq, Eq)]
49pub enum Cloexec {
50    Get(crate::Errno),
51    Set(crate::Errno),
52}
53
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55pub enum Capability {
56    Feature(Feature),
57    Opcode(Opcode),
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq)]
61#[repr(transparent)]
62pub struct Opcode(<crate::Backend as kernel::Source>::Code);
63
64impl<C> Opcode
65where
66    crate::Backend: kernel::Source<Code = C>,
67{
68    pub(crate) fn native<T: Into<C>>(code: T) -> Self {
69        Self(code.into())
70    }
71}
72
73#[derive(Clone, Copy, Debug, PartialEq, Eq)]
74#[repr(u8)]
75pub enum Probe {
76    Ring = 0,
77    DirectSocket = 1,
78    SocketOption = 2,
79    CloseDirectSocket = 3,
80    Receive = 4,
81    ReceiveMessage = 5,
82    DirectAccept = 6,
83    CloseDirectAccept = 7,
84    DirectAcceptMultishot = 8,
85    CloseDirectAcceptMultishot = 9,
86    RegisterAcceptListener = 10,
87    ReleaseAcceptListener = 11,
88}
89
90impl From<Probe> for u64 {
91    fn from(probe: Probe) -> Self {
92        probe as Self
93    }
94}
95
96#[derive(Clone, Copy, Debug, PartialEq, Eq)]
97pub struct ProbeError {
98    probe: Probe,
99    violation: Violation,
100}
101
102#[derive(Clone, Copy, Debug, PartialEq, Eq)]
103pub enum Violation {
104    MissingCompletion,
105    UnexpectedCompletion {
106        expected: Probe,
107        observed: fault::Observation,
108    },
109    Rejected(fault::Observation),
110    UnexpectedResult(fault::Observation),
111    Send(fault::Send),
112    InvalidFlags(fault::Observation),
113    MissingBuffer,
114    InvalidBuffer(receive::Selection),
115    BufferLength {
116        actual: transfer::Len,
117        capacity: transfer::NonZero,
118    },
119    EarlyTermination,
120    CorruptPayload,
121    FrameOverflow {
122        name: receive::Capacity,
123        control: receive::Capacity,
124    },
125    FrameShort {
126        actual: receive::Length,
127        required: receive::Length,
128    },
129    MissingFrameTruncation {
130        region: FrameRegion,
131        reported: receive::Length,
132        available: receive::Length,
133    },
134    TruncatedFrame,
135    InvalidAddress(socket::Error),
136    NonterminalCancellation(fault::Observation),
137    EscapedSlot(bounds::Slot),
138    ResidualWork {
139        submissions: fault::Pending,
140        completions: fault::Available,
141    },
142}
143
144#[derive(Clone, Copy, PartialEq, Eq, Debug)]
145pub enum FrameRegion {
146    Control,
147    Payload,
148}
149
150impl ProbeError {
151    pub(crate) fn decode(
152        failure: probe::Failure<Probe, <Engine as complete::Observe>::Observation>,
153    ) -> Self {
154        use dope_sys::probe::Check;
155        let (probe, check) = failure.into_parts();
156        let fault = match check {
157            Check::InvalidFlags(observed) => {
158                Violation::InvalidFlags(fault::Observation::new(observed))
159            }
160            Check::Rejected(observed) => Violation::Rejected(fault::Observation::new(observed)),
161            Check::Unexpected(observed) => {
162                Violation::UnexpectedResult(fault::Observation::new(observed))
163            }
164            Check::Nonterminal(observed) => {
165                Violation::NonterminalCancellation(fault::Observation::new(observed))
166            }
167        };
168        Self::new(probe, fault)
169    }
170
171    pub(crate) const fn new(probe: Probe, fault: Violation) -> Self {
172        Self {
173            probe,
174            violation: fault,
175        }
176    }
177
178    pub const fn into_parts(self) -> (Probe, Violation) {
179        (self.probe, self.violation)
180    }
181}
182
183#[derive(Clone, Copy, Debug, Eq, PartialEq)]
184#[repr(transparent)]
185pub struct SubmitError(SubmitCause);
186
187#[derive(Clone, Copy, Debug, Eq, PartialEq)]
188pub enum SubmitCause {
189    /// Queue or flight capacity can become available after existing work retires.
190    Full,
191    /// Every identity in the retained flight group has been permanently consumed.
192    IdentityExhausted,
193}
194
195impl SubmitError {
196    pub(crate) const fn queue(full: Full) -> Self {
197        let Full = full;
198        Self(SubmitCause::Full)
199    }
200
201    pub fn cause(self) -> SubmitCause {
202        self.0
203    }
204}
205
206impl From<Vacancy> for SubmitError {
207    fn from(error: Vacancy) -> Self {
208        Self(match error {
209            Vacancy::Full => SubmitCause::Full,
210            Vacancy::IdentityExhausted => SubmitCause::IdentityExhausted,
211        })
212    }
213}
214
215#[derive(Clone, Copy, Debug, PartialEq, Eq)]
216#[repr(transparent)]
217pub struct Kernel(KernelCause);
218
219impl Kernel {
220    /// Observes the exact operation and payload without exposing the native backend.
221    pub fn cause(self) -> KernelCause {
222        self.0
223    }
224
225    pub(crate) fn native<T: Into<KernelCause>>(cause: T) -> Self {
226        Self(cause.into())
227    }
228}
229
230const _: () = {
231    assert!(
232        mem::size_of::<Kernel>()
233            == mem::size_of::<<crate::Backend as kernel::Source>::Failure<indices::SlotIndex>>()
234    );
235    assert!(
236        mem::align_of::<Kernel>()
237            == mem::align_of::<<crate::Backend as kernel::Source>::Failure<indices::SlotIndex>>()
238    );
239};
240
241pub enum CreateError {
242    Plan(errors::Config),
243    Allocation(alloc::Error),
244    Queue(alloc::Error),
245    Buffer(pool::CreateError),
246    RingLayout(layout::Layout),
247    ReactorCloexec(Cloexec),
248    Kernel {
249        operation: IoOperation,
250        cause: Kernel,
251    },
252    Mapping(storage::Mapping),
253    Cleanup(storage::Cleanup),
254    Removal(storage::Removal),
255    Release(storage::Release),
256    Capability(Capability),
257    Probe(ProbeError),
258}
259
260/// Exact construction diagnostics borrowed without consuming cleanup authority.
261#[derive(Debug)]
262pub enum CreateKind<'a> {
263    Plan(&'a errors::Config),
264    Allocation(&'a alloc::Error),
265    Queue(&'a alloc::Error),
266    Buffer(&'a pool::CreateError),
267    RingLayout(&'a layout::Layout),
268    ReactorCloexec(&'a Cloexec),
269    Kernel {
270        operation: &'a IoOperation,
271        cause: &'a Kernel,
272    },
273    Mapping(&'a storage::Mapping),
274    Cleanup {
275        primary: storage::Failure,
276        cleanup: Option<storage::Failure>,
277    },
278    Removal(&'a storage::Removal),
279    Release {
280        primary: storage::Removal,
281        cleanup: Option<storage::Mapping>,
282    },
283    Capability(&'a Capability),
284    Probe(&'a ProbeError),
285}
286
287impl CreateError {
288    pub fn kind(&self) -> CreateKind<'_> {
289        match self {
290            Self::Plan(error) => CreateKind::Plan(error),
291            Self::Allocation(error) => CreateKind::Allocation(error),
292            Self::Queue(error) => CreateKind::Queue(error),
293            Self::Buffer(error) => CreateKind::Buffer(error),
294            Self::RingLayout(error) => CreateKind::RingLayout(error),
295            Self::ReactorCloexec(error) => CreateKind::ReactorCloexec(error),
296            Self::Kernel {
297                operation: op,
298                cause,
299            } => CreateKind::Kernel {
300                operation: op,
301                cause,
302            },
303            Self::Mapping(error) => CreateKind::Mapping(error),
304            Self::Cleanup(state) => CreateKind::Cleanup {
305                primary: state.primary(),
306                cleanup: state.cleanup(),
307            },
308            Self::Removal(error) => CreateKind::Removal(error),
309            Self::Release(state) => CreateKind::Release {
310                primary: state.primary(),
311                cleanup: state.cleanup(),
312            },
313            Self::Capability(error) => CreateKind::Capability(error),
314            Self::Probe(error) => CreateKind::Probe(error),
315        }
316    }
317
318    pub(crate) const fn kernel(op: IoOperation, cause: Kernel) -> Self {
319        Self::Kernel {
320            operation: op,
321            cause,
322        }
323    }
324}
325
326impl From<alloc::Error> for CreateError {
327    fn from(cause: alloc::Error) -> Self {
328        Self::Allocation(cause)
329    }
330}
331
332impl From<alloc::Overflow> for CreateError {
333    fn from(cause: alloc::Overflow) -> Self {
334        Self::Allocation(cause.into())
335    }
336}
337
338impl From<alloc::Exhausted> for CreateError {
339    fn from(cause: alloc::Exhausted) -> Self {
340        Self::Allocation(cause.into())
341    }
342}
343
344impl From<storage::Failure> for CreateError {
345    fn from(error: storage::Failure) -> Self {
346        match error {
347            storage::Failure::Kernel {
348                operation: op,
349                cause,
350            } => Self::Kernel {
351                operation: op,
352                cause,
353            },
354            storage::Failure::Mapping(error) => Self::Mapping(error),
355            storage::Failure::RingLayout(error) => Self::RingLayout(error),
356            storage::Failure::Capability(error) => Self::Capability(error),
357            storage::Failure::Probe(error) => Self::Probe(error),
358        }
359    }
360}
361
362/// Exact failure phase and payload from a rejected native kernel operation.
363pub type KernelCause = kernel::Diagnostic<indices::SlotIndex>;