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 /// `errno` reads that thread's slot before another syscall.
90 pub unsafe fn try_zero<E: From<Errno>>(self, errno: impl FnOnce() -> Errno) -> Result<(), E> {
91 // SAFETY: -1..=0 is Exact<0>'s domain; errno keeps the caller's contract.
92 unsafe { Exact::<0>(self.0).try_admit(errno) }
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 pub fn try_value<E: From<Errno>>(
107 self,
108 errno: impl FnOnce() -> Errno,
109 ) -> Result<kernel::Value, E> {
110 if self.0 == -1 {
111 Err(E::from(errno()))
112 } else {
113 Ok(kernel::Value(self.0))
114 }
115 }
116
117 /// Decodes one count-returning operation against the exact extent it was given.
118 ///
119 /// # Safety
120 /// `errno` reads that thread's slot before another syscall.
121 pub unsafe fn try_count<E: From<Errno>>(
122 self,
123 errno: impl FnOnce() -> Errno,
124 ) -> Result<Count, E> {
125 Ok(Count::new(self.try_value(errno)?))
126 }
127
128 /// Tightens this scalar to one operation's exact `-1`-or-`VALUE` return.
129 ///
130 /// # Safety
131 /// That operation reports exactly `VALUE` or -1 for these arguments.
132 pub const unsafe fn admit_exact<const VALUE: libc::c_int>(self) -> Exact<VALUE> {
133 Exact(self.0)
134 }
135}
136
137/// One native return whose producer reports exactly -1 or its one success value,
138/// so the ABI's exactness proof is discharged once at admission and the decoder
139/// below is total without a second range check.
140#[derive(Clone, Copy, Debug)]
141#[repr(transparent)]
142pub struct Exact<const VALUE: libc::c_int>(libc::c_int);
143
144impl<const VALUE: libc::c_int> Exact<VALUE> {
145 /// Decodes the admitted success value without re-deriving its domain.
146 ///
147 /// # Safety
148 /// `errno` reads that thread's slot before another syscall.
149 pub unsafe fn try_admit<E: From<Errno>>(self, errno: impl FnOnce() -> Errno) -> Result<(), E> {
150 if self.0 == VALUE {
151 Ok(())
152 } else {
153 Err(E::from(errno()))
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}