Skip to main content

dope_core/io/
mod.rs

1pub mod datagram;
2pub mod event;
3pub mod fd;
4pub mod fs;
5pub mod recv;
6pub mod socket;
7pub mod transfer;
8
9use std::{io, process};
10
11use self::{
12    event::{accept, creation, open, receiving},
13    fd::handles,
14};
15use crate::{
16    backend,
17    driver::{
18        self,
19        route::{self, kind},
20    },
21    platform,
22};
23
24type Buffer = <backend::Backend as platform::Buffer>::Token;
25
26#[must_use = "completion may own a resource that must be delivered or reclaimed"]
27pub(crate) struct Completion(CompletionKind);
28
29enum CompletionKind {
30    Shutdown,
31    AcceptSuccess {
32        token: route::Token,
33        accepted: handles::Accepted,
34        more: bool,
35    },
36    AcceptFailure {
37        token: route::Token,
38        errno: i32,
39        more: bool,
40    },
41    RecvData {
42        token: route::Token,
43        len: u32,
44        more: bool,
45        buffer: Buffer,
46    },
47    RecvExhausted {
48        token: route::Token,
49        more: bool,
50    },
51    Operation {
52        token: route::Token,
53        result: i32,
54        more: bool,
55    },
56    Opened {
57        token: route::Token,
58        opened: open::Opened,
59    },
60    OpenFailed {
61        token: route::Token,
62        error: open::Error,
63    },
64    SocketCreated {
65        token: route::Token,
66        slot: handles::FixedSlot,
67    },
68    SocketFailed {
69        token: route::Token,
70        errno: i32,
71    },
72}
73
74pub(crate) enum Reclaim<'d> {
75    Accepted(handles::Accepted),
76    Close(driver::Close<'d>),
77    Slots(driver::RetiredSlots<'d>),
78    Buffer(Buffer),
79    None,
80}
81
82impl Completion {
83    pub(crate) fn accepted(token: route::Token, accepted: handles::Accepted, more: bool) -> Self {
84        Self(CompletionKind::AcceptSuccess {
85            token,
86            accepted,
87            more,
88        })
89    }
90
91    pub(crate) fn accept_failed(token: route::Token, errno: i32, more: bool) -> Self {
92        Self(CompletionKind::AcceptFailure { token, errno, more })
93    }
94
95    pub(crate) fn shutdown() -> Self {
96        Self(CompletionKind::Shutdown)
97    }
98
99    pub(crate) fn operation(token: route::Token, result: i32, more: bool) -> Self {
100        Self(CompletionKind::Operation {
101            token,
102            result,
103            more,
104        })
105    }
106
107    pub(crate) fn opened(token: route::Token, opened: open::Opened) -> Self {
108        Self(CompletionKind::Opened { token, opened })
109    }
110
111    pub(crate) fn open_failed(token: route::Token, error: open::Error) -> Self {
112        Self(CompletionKind::OpenFailed { token, error })
113    }
114
115    pub(crate) fn socket_created(token: route::Token, slot: handles::FixedSlot) -> Self {
116        Self(CompletionKind::SocketCreated { token, slot })
117    }
118
119    pub(crate) fn socket_failure(token: route::Token, errno: i32) -> Self {
120        Self(CompletionKind::SocketFailed { token, errno })
121    }
122
123    pub(crate) fn received(token: route::Token, len: u32, more: bool, buffer: Buffer) -> Self {
124        debug_assert_eq!(token.kind(), kind::RECV);
125        Self(CompletionKind::RecvData {
126            token,
127            len,
128            more,
129            buffer,
130        })
131    }
132
133    pub(crate) fn recv_exhausted(token: route::Token, more: bool) -> Self {
134        debug_assert_eq!(token.kind(), kind::RECV);
135        Self(CompletionKind::RecvExhausted { token, more })
136    }
137
138    pub(crate) fn into_reclaim<'d>(self, reference: driver::Reference<'d>) -> Reclaim<'d> {
139        match self.0 {
140            CompletionKind::AcceptSuccess { accepted, .. } => Reclaim::Accepted(accepted),
141            CompletionKind::SocketCreated { slot, .. } => {
142                match reference.outbound().complete_outbound_create_success(slot) {
143                    driver::CreateSuccess::Deliver(key) => {
144                        match reference.outbound().begin_outbound_close(key, slot) {
145                            driver::CloseDisposition::Submit(close) => Reclaim::Close(close),
146                            driver::CloseDisposition::NoSubmit(Some(slots)) => {
147                                Reclaim::Slots(slots)
148                            }
149                            driver::CloseDisposition::NoSubmit(None) => Reclaim::None,
150                        }
151                    }
152                    driver::CreateSuccess::Close(close) => Reclaim::Close(close),
153                }
154            }
155            CompletionKind::RecvData { buffer, .. } => Reclaim::Buffer(buffer),
156            CompletionKind::Opened { opened, .. } => {
157                drop(opened);
158                Reclaim::None
159            }
160            CompletionKind::Shutdown
161            | CompletionKind::AcceptFailure { .. }
162            | CompletionKind::RecvExhausted { .. }
163            | CompletionKind::Operation { .. }
164            | CompletionKind::OpenFailed { .. }
165            | CompletionKind::SocketFailed { .. } => Reclaim::None,
166        }
167    }
168}
169
170pub enum RecvEvent<'d> {
171    Data(recv::Lease<'d>),
172    Eof,
173    Cancelled,
174    BufferExhausted,
175    Starved,
176    Failed(i32),
177}
178
179impl RecvEvent<'_> {
180    fn from_errno(result: i32) -> Self {
181        match -result {
182            libc::ECANCELED => Self::Cancelled,
183            libc::ENOBUFS | libc::EAGAIN | libc::EINTR => Self::Starved,
184            errno => Self::Failed(errno),
185        }
186    }
187}
188
189#[derive(Clone, Copy)]
190pub enum SendEvent {
191    Sent(u32),
192    Failed(i32),
193}
194
195#[derive(Clone, Copy)]
196pub enum ReadEvent {
197    Read(u32),
198    Eof,
199    Failed(i32),
200}
201
202#[derive(Clone, Copy)]
203pub enum WriteEvent {
204    Written(u32),
205    Failed(i32),
206}
207
208impl WriteEvent {
209    fn from_result(result: i32) -> Self {
210        if result >= 0 {
211            Self::Written(result as u32)
212        } else {
213            Self::Failed(-result)
214        }
215    }
216}
217
218impl ReadEvent {
219    fn from_result(result: i32) -> Self {
220        match result {
221            n if n > 0 => Self::Read(n as u32),
222            0 => Self::Eof,
223            n => Self::Failed(-n),
224        }
225    }
226}
227
228#[derive(Clone, Copy)]
229pub enum StatEvent {
230    Done,
231    Failed(i32),
232}
233
234#[derive(Clone, Copy)]
235pub enum Sync {
236    Done,
237    Failed(i32),
238}
239
240pub enum AcceptEvent<'d> {
241    Accepted(handles::AcceptedSlot<'d>),
242    Failed(i32),
243}
244
245pub enum SocketEvent<'d> {
246    Created(handles::CreatedSlot<'d>),
247    Failed(io::Error),
248}
249
250/// A completion emitted by the driver.
251///
252/// Its payload is inspectable through [`Event::kind`] or consumable through
253/// [`Event::into_kind`], but safe code outside the driver cannot mint the
254/// completion authority itself.
255///
256/// ```compile_fail
257/// use dope_core::io::{Event, event};
258///
259/// let _ = Event(event::Kind::Shutdown);
260/// ```
261///
262/// ```compile_fail
263/// use dope_core::{driver::route, io};
264///
265/// let _ = io::event::send::Completion::new(route::SHUTDOWN, io::SendEvent::Sent(0));
266/// ```
267#[repr(transparent)]
268pub struct Event<'d>(event::Kind<'d>);
269
270const _: () =
271    assert!(std::mem::size_of::<Event<'static>>() == std::mem::size_of::<event::Kind<'static>>());
272
273impl<'d> Event<'d> {
274    pub(crate) fn from_completion(
275        completion: Completion,
276        reference: driver::Reference<'d>,
277        region: impl FnOnce(u32, &mut Buffer) -> recv::raw::Region,
278    ) -> Self {
279        use std::io::Error;
280
281        match completion.0 {
282            CompletionKind::Shutdown => Event(event::Kind::Shutdown),
283            CompletionKind::AcceptSuccess {
284                token,
285                accepted,
286                more,
287            } => {
288                let event = match accepted.bind(reference) {
289                    Some(accepted) => AcceptEvent::Accepted(accepted),
290                    None => AcceptEvent::Failed(libc::ECANCELED),
291                };
292                Event(event::Kind::Accept(
293                    token,
294                    accept::Completion::new(more, event),
295                ))
296            }
297            CompletionKind::AcceptFailure { token, errno, more } => Event(event::Kind::Accept(
298                token,
299                accept::Completion::new(more, AcceptEvent::Failed(errno)),
300            )),
301            CompletionKind::RecvData {
302                token,
303                len,
304                more,
305                mut buffer,
306            } => {
307                use crate::io::recv::Lease;
308
309                let region = region(len, &mut buffer);
310                let lease = Lease::from_completion(reference, buffer, region);
311                Event(event::Kind::Recv(receiving::Completion::new(
312                    token,
313                    more,
314                    RecvEvent::Data(lease),
315                )))
316            }
317            CompletionKind::RecvExhausted { token, more } => Event(event::Kind::Recv(
318                receiving::Completion::new(token, more, RecvEvent::BufferExhausted),
319            )),
320            CompletionKind::Operation {
321                token,
322                result,
323                more,
324            } => Self::from_operation(token, result, more),
325            CompletionKind::Opened { token, opened } => Event(event::Kind::Open(
326                open::Completion::new(token, open::Outcome::Opened(opened)),
327            )),
328            CompletionKind::OpenFailed { token, error } => Event(event::Kind::Open(
329                open::Completion::new(token, open::Outcome::Failed(error.get())),
330            )),
331            CompletionKind::SocketCreated { token, slot } => {
332                Event(event::Kind::Socket(creation::Completion::new(
333                    token,
334                    match handles::Created::from_live(slot).bind(reference) {
335                        Some(created) => SocketEvent::Created(created),
336                        None => SocketEvent::Failed(Error::from_raw_os_error(libc::ECANCELED)),
337                    },
338                )))
339            }
340            CompletionKind::SocketFailed { token, errno } => {
341                Event(event::Kind::Socket(creation::Completion::new(
342                    token,
343                    SocketEvent::Failed(Error::from_raw_os_error(errno)),
344                )))
345            }
346        }
347    }
348
349    fn from_operation(token: route::Token, result: i32, more: bool) -> Self {
350        use std::io::Error;
351
352        match token.kind() {
353            kind::RECV => {
354                let event = if result == 0 {
355                    RecvEvent::Eof
356                } else {
357                    RecvEvent::from_errno(result)
358                };
359                Self(event::Kind::Recv(receiving::Completion::new(
360                    token, more, event,
361                )))
362            }
363            kind::SEND => {
364                use crate::io::event::send;
365
366                Self(event::Kind::Send(send::Completion::new(
367                    token,
368                    if result >= 0 {
369                        SendEvent::Sent(result as u32)
370                    } else {
371                        SendEvent::Failed(-result)
372                    },
373                )))
374            }
375            kind::READ => Self(event::Kind::Read(token, ReadEvent::from_result(result))),
376            kind::WRITE => Self(event::Kind::Write(token, WriteEvent::from_result(result))),
377            kind::STAT => Self(event::Kind::Stat(
378                token,
379                if result >= 0 {
380                    StatEvent::Done
381                } else {
382                    StatEvent::Failed(-result)
383                },
384            )),
385            kind::SYNC => Self(event::Kind::Sync(
386                token,
387                if result >= 0 {
388                    Sync::Done
389                } else {
390                    Sync::Failed(-result)
391                },
392            )),
393            kind::TUNING => {
394                use crate::io::event::tuning;
395
396                Self(event::Kind::Tuning(tuning::Completion::new(
397                    token,
398                    if result >= 0 {
399                        tuning::Outcome::Applied
400                    } else {
401                        tuning::Outcome::Failed(Error::from_raw_os_error(-result))
402                    },
403                )))
404            }
405            kind::CONNECT => {
406                use crate::io::event::connect;
407
408                Self(event::Kind::Connect(connect::Completion::new(
409                    token,
410                    if result >= 0 {
411                        connect::Outcome::Connected
412                    } else {
413                        connect::Outcome::Failed(Error::from_raw_os_error(-result))
414                    },
415                )))
416            }
417            _ => process::abort(),
418        }
419    }
420
421    pub const fn is_shutdown(&self) -> bool {
422        matches!(self.0, event::Kind::Shutdown)
423    }
424
425    pub const fn kind(&self) -> &event::Kind<'d> {
426        &self.0
427    }
428
429    pub fn into_kind(self) -> event::Kind<'d> {
430        self.0
431    }
432
433    pub const fn token(&self) -> Option<route::Token> {
434        match &self.0 {
435            event::Kind::Accept(token, ..)
436            | event::Kind::Read(token, _)
437            | event::Kind::Write(token, _)
438            | event::Kind::Stat(token, _)
439            | event::Kind::Sync(token, _) => Some(*token),
440            event::Kind::Recv(completion) => Some(completion.token()),
441            event::Kind::Send(completion) => Some(completion.token()),
442            event::Kind::Socket(completion) => Some(completion.token()),
443            event::Kind::Tuning(completion) => Some(completion.token()),
444            event::Kind::Connect(completion) => Some(completion.token()),
445            event::Kind::Open(completion) => Some(completion.token()),
446            event::Kind::Shutdown => None,
447        }
448    }
449
450    pub fn route(&self) -> u8 {
451        match &self.0 {
452            event::Kind::Accept(token, ..) => token.route(),
453            event::Kind::Recv(completion) => completion.token().route(),
454            event::Kind::Send(completion) => completion.token().route(),
455            event::Kind::Socket(completion) => completion.token().route(),
456            event::Kind::Tuning(completion) => completion.token().route(),
457            event::Kind::Connect(completion) => completion.token().route(),
458            event::Kind::Open(completion) => completion.token().route(),
459            event::Kind::Read(t, _) => t.route(),
460            event::Kind::Write(t, _) => t.route(),
461            event::Kind::Stat(t, _) => t.route(),
462            event::Kind::Sync(t, _) => t.route(),
463            event::Kind::Shutdown => route::SHUTDOWN.route(),
464        }
465    }
466}
467
468impl<'d> From<receiving::Completion<'d>> for Event<'d> {
469    fn from(completion: receiving::Completion<'d>) -> Self {
470        Self(event::Kind::Recv(completion))
471    }
472}