Skip to main content

dope_sys/kernel/
raw.rs

1use std::num;
2
3use o3::base::num::bounded;
4
5use crate::{Errno, kernel};
6
7/// Access to errno immediately after a native operation reports failure.
8/// # Safety
9/// `read` returns the unchanged native errno slot of the calling thread.
10pub unsafe trait Source {
11    /// Reads this thread's unchanged native errno slot.
12    fn read() -> i32;
13}
14
15/// A positive errno established by one native failure or completion field.
16#[derive(Clone, Copy, Debug)]
17#[repr(transparent)]
18pub struct Code(num::NonZero<i32>);
19
20impl Code {
21    /// Retains the positive error number established by one failed native call.
22    ///
23    /// # Safety
24    /// A failed native call left this thread's errno positive and unchanged.
25    pub unsafe fn last<S: Source + ?Sized>() -> Self {
26        // SAFETY: the caller retains the immediately preceding native failure's positive errno.
27        unsafe { Self::new(S::read()) }
28    }
29
30    /// Retains the positive domain established by the native producer.
31    ///
32    /// # Safety
33    /// `raw` is positive, as established by the unchanged native error field.
34    pub const unsafe fn new(raw: i32) -> Self {
35        // SAFETY: the caller retains the native producer's positive errno proof.
36        Self(unsafe { num::NonZero::new_unchecked(raw) })
37    }
38
39    /// Retains the errno one native completion field reports, if any.
40    ///
41    /// # Safety
42    /// `raw` is that completion's exact field: zero or a positive c_int.
43    pub unsafe fn from_native(raw: libc::intptr_t) -> Option<Self> {
44        num::NonZero::new(raw as i32).map(Self)
45    }
46}
47
48impl From<Code> for Errno {
49    fn from(code: Code) -> Self {
50        Self(code.0)
51    }
52}
53
54/// A native scalar retained with the exact domain its producer guarantees, so
55/// every decoder below is total: the producer's ABI proof is discharged once at
56/// construction and reused without a second range check.
57#[derive(Clone, Copy, Debug)]
58#[repr(transparent)]
59pub struct Status<const MIN: libc::c_int, const MAX: libc::c_int>(libc::c_int);
60
61impl<const MIN: libc::c_int, const MAX: libc::c_int> Status<MIN, MAX> {
62    /// Retains the return domain established by one native operation.
63    ///
64    /// # Safety
65    /// `raw` lies in `MIN..=MAX`, as guaranteed by the operation producing it.
66    pub const unsafe fn new(raw: libc::c_int) -> Self {
67        Self(raw)
68    }
69}
70
71/// Retries only interrupted native attempts, preserving each leaf's success domain.
72pub(crate) fn try_retry<T, E, const RETRY: bool>(
73    mut call: impl FnMut() -> Result<T, Errno>,
74    classify: impl FnOnce(Errno) -> E,
75) -> Result<T, E> {
76    loop {
77        match call() {
78            Ok(value) => return Ok(value),
79            Err(error) if RETRY && error.is_intr() => continue,
80            Err(error) => return Err(classify(error)),
81        }
82    }
83}
84
85impl Status<-1, 0> {
86    /// Decodes a native zero-or-minus-one operation without erasing errno.
87    ///
88    /// # Safety
89    /// On failure, `S` reads this call's positive, unchanged errno.
90    pub unsafe fn try_zero<S: Source + ?Sized, E: From<Errno>>(self) -> Result<(), E> {
91        // SAFETY: -1..=0 is Exact<0>'s domain; S keeps the caller's errno contract.
92        unsafe { Exact::<0>(self.0).try_admit::<S, E>() }
93    }
94}
95
96impl Status<-1, { i32::MAX }> {
97    /// Retains a native count whose exact syscall operand already bounds it.
98    ///
99    /// # Safety
100    /// `raw` is the unchanged return of that count-returning syscall: native -1 or `0..=i32::MAX`.
101    pub const unsafe fn from_count(raw: libc::ssize_t) -> Self {
102        Self(raw as libc::c_int)
103    }
104
105    /// Converts the retained native scalar domain without checking its range again.
106    ///
107    /// # Safety
108    /// On failure, `S` reads this call's positive, unchanged errno.
109    pub unsafe fn try_value<S: Source + ?Sized, E: From<Errno>>(self) -> Result<kernel::Value, E> {
110        if self.0 == -1 {
111            // SAFETY: the caller retains this failed call's positive, unchanged errno.
112            Err(E::from(unsafe { Code::last::<S>() }.into()))
113        } else {
114            Ok(kernel::Value(self.0))
115        }
116    }
117
118    /// Decodes one count-returning operation against the exact extent it was given.
119    ///
120    /// # Safety
121    /// On failure, `S` reads this call's positive, unchanged errno.
122    pub unsafe fn try_count<S: Source + ?Sized, E: From<Errno>>(self) -> Result<Count, E> {
123        // SAFETY: the caller retains this failed call's positive, unchanged errno.
124        Ok(Count::new(unsafe { self.try_value::<S, E>() }?))
125    }
126
127    /// Tightens this scalar to one operation's exact `-1`-or-`VALUE` return.
128    ///
129    /// # Safety
130    /// That operation reports exactly `VALUE` or -1 for these arguments.
131    pub const unsafe fn admit_exact<const VALUE: libc::c_int>(self) -> Exact<VALUE> {
132        Exact(self.0)
133    }
134}
135
136/// One native return whose producer reports exactly -1 or its one success value,
137/// so the ABI's exactness proof is discharged once at admission and the decoder
138/// below is total without a second range check.
139#[derive(Clone, Copy, Debug)]
140#[repr(transparent)]
141pub struct Exact<const VALUE: libc::c_int>(libc::c_int);
142
143impl<const VALUE: libc::c_int> Exact<VALUE> {
144    /// Decodes the admitted success value without re-deriving its domain.
145    ///
146    /// # Safety
147    /// On failure, `S` reads this call's positive, unchanged errno.
148    pub unsafe fn try_admit<S: Source + ?Sized, E: From<Errno>>(self) -> Result<(), E> {
149        if self.0 == VALUE {
150            Ok(())
151        } else {
152            // SAFETY: the caller retains this failed call's positive, unchanged errno.
153            Err(E::from(unsafe { Code::last::<S>() }.into()))
154        }
155    }
156}
157
158impl Status<0, { i32::MAX }> {
159    /// Decodes the error code returned directly by a pthread operation.
160    pub fn try_pthread(self) -> Result<(), Errno> {
161        if self.0 == 0 {
162            Ok(())
163        } else {
164            // SAFETY: pthread's retained return domain makes every failure positive.
165            Err(unsafe { Code::new(self.0) }.into())
166        }
167    }
168}
169
170/// One live descriptor whose native producer or retained owner establishes its
171/// nonnegative domain, so later uses do not check that range again.
172#[derive(Clone, Copy, Debug)]
173#[repr(transparent)]
174pub struct Descriptor(bounded::U32<0, { i32::MAX as u32 }>);
175
176impl Descriptor {
177    /// # Safety
178    /// `raw` is the unchanged live nonnegative descriptor produced by a successful
179    /// native operation or retained by its exclusive owner.
180    pub const unsafe fn new(raw: libc::c_int) -> Self {
181        // SAFETY: the native nonnegative c_int retains the exact 0..=i32::MAX bound.
182        Self(unsafe { bounded::raw::u32(raw as u32) })
183    }
184
185    pub const fn get(self) -> libc::c_int {
186        self.0.get() as libc::c_int
187    }
188}
189
190/// One completed native count retaining its admitted ABI bound.
191#[derive(Clone, Copy, Debug)]
192#[repr(transparent)]
193pub struct Count(bounded::U32<0, { i32::MAX as u32 }>);
194
195impl Count {
196    /// Retains the count one count-returning operation completed within its operand.
197    const fn new(value: kernel::Value) -> Self {
198        // SAFETY: Value admits exactly 0..=i32::MAX, the bound retained here.
199        Self(unsafe { bounded::raw::u32(value.get() as u32) })
200    }
201
202    pub const fn get(self) -> usize {
203        self.0.into_usize()
204    }
205
206    pub const fn bounded(self) -> bounded::U32<0, { i32::MAX as u32 }> {
207        self.0
208    }
209}