Skip to main content

dope_runtime/
shutdown.rs

1use std::{marker, os::fd};
2
3use dope_core::{
4    Errno,
5    driver::{life::creation, settings},
6};
7use o3::base::marker::ThreadBound;
8
9use crate::{
10    executor::{self, create},
11    process::{
12        failure::bus,
13        lifecycle::{self, Main},
14    },
15};
16
17pub use crate::process::Shutdown as ReadySource;
18
19#[derive(Clone, Copy, Debug, PartialEq, Eq)]
20pub enum CreateError {
21    Pair(bus::Create),
22    Duplicate(Errno),
23}
24
25#[derive(Debug)]
26pub struct FireError {
27    pub trigger: Trigger,
28    pub cause: Errno,
29}
30
31#[must_use]
32pub struct Pair {
33    source: Source,
34    trigger: Trigger,
35}
36
37#[must_use]
38pub struct Source {
39    pub(crate) event: (fd::OwnedFd, Main),
40}
41
42impl fd::AsFd for Source {
43    fn as_fd(&self) -> fd::BorrowedFd<'_> {
44        fd::AsFd::as_fd(&self.event.0)
45    }
46}
47
48#[must_use]
49#[derive(Debug)]
50pub struct Trigger(Main);
51
52type Invariant<Q> = marker::PhantomData<(fn(Q) -> Q, ThreadBound)>;
53
54#[must_use]
55pub struct Requested<Q = Source>(Invariant<Q>);
56
57impl Pair {
58    pub fn new() -> Result<Self, CreateError> {
59        let (main, event) = lifecycle::pair().map_err(CreateError::Pair)?;
60        let guard = main.duplicate().map_err(CreateError::Duplicate)?;
61        Ok(Self {
62            source: Source {
63                event: (event, guard),
64            },
65            trigger: Trigger(main),
66        })
67    }
68
69    pub fn split(self) -> (Source, Trigger) {
70        (self.source, self.trigger)
71    }
72
73    pub fn run<R>(self, execute: impl FnOnce(Source) -> R) -> R {
74        execute(self.source)
75    }
76}
77
78impl executor::Build for Source {
79    type Shutdown = Source;
80
81    fn try_build(
82        self,
83        attempt: &mut creation::Attempt,
84        config: settings::Config,
85    ) -> Result<executor::Executor<(), Self::Shutdown>, create::Error<'_>> {
86        executor::Executor::new(attempt, config)?
87            .shutdown(self)
88            .map_err(create::Error::from)
89    }
90}
91
92impl<'run> executor::Build for ReadySource<'run> {
93    type Shutdown = Self;
94
95    fn try_build(
96        self,
97        attempt: &mut creation::Attempt,
98        config: settings::Config,
99    ) -> Result<executor::Executor<(), Self::Shutdown>, create::Error<'_>> {
100        executor::Executor::new(attempt, config)?
101            .shutdown(self)
102            .map_err(create::Error::from)
103    }
104}
105
106impl executor::Startup for Source {
107    fn installed(&self) -> Result<(), executor::InstallError> {
108        Ok(())
109    }
110}
111
112impl Trigger {
113    pub fn fire(self) -> Result<(), FireError> {
114        match self.0.request() {
115            Ok(()) => Ok(()),
116            Err(cause) => Err(FireError {
117                trigger: self,
118                cause,
119            }),
120        }
121    }
122}
123
124impl<Q> Requested<Q> {
125    pub(crate) const fn new() -> Self {
126        Self(marker::PhantomData)
127    }
128}
129
130const _: () = assert!(std::mem::size_of::<Requested>() == 0);