Skip to main content

compio_driver/sys/extra/
mod.rs

1cfg_if::cfg_if! {
2    if #[cfg(windows)] {
3        mod iocp;
4        use iocp as sys;
5    } else if #[cfg(fusion)] {
6        mod fusion;
7        mod poll;
8        mod iour;
9        use fusion as sys;
10    } else if #[cfg(io_uring)] {
11        mod iour;
12        use iour as sys;
13    } else if #[cfg(polling)] {
14        mod poll;
15        use poll as sys;
16    } else if #[cfg(stub)] {
17        mod stub;
18        use stub as sys;
19    }
20}
21
22use std::{fmt::Debug, io};
23
24#[allow(unused_imports)]
25pub use sys::*;
26
27/// Platform-specific extra data associated with a driver instance.
28///
29/// It can be used to set options for or get extra data from I/O operations.
30#[repr(transparent)]
31pub struct Extra(pub(super) sys::Extra);
32
33impl Debug for Extra {
34    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35        Debug::fmt(&self.0, f)
36    }
37}
38
39impl<I: Into<sys::Extra>> From<I> for Extra {
40    fn from(inner: I) -> Self {
41        Self(inner.into())
42    }
43}
44
45impl Extra {
46    pub(crate) fn new(driver: &Driver) -> Self {
47        driver.default_extra().into()
48    }
49}
50
51impl Extra {
52    iour_only! {
53        /// Checks whether this completion reports a notification (2nd CQE returned for a zerocopy op).
54        ///
55        /// # Behaviour
56        ///
57        /// This is only supported on `io_uring` drivers, in which the driver will
58        /// check whether the `IORING_CQE_F_NOTIF` flag was set by the kernel for
59        /// the CQE. On other platforms, this will always return the
60        /// [`Unsupported`] error.
61        ///
62        /// [`Unsupported`]: io::ErrorKind::Unsupported
63        get fn is_notification(&self) -> io::Result<bool> = |extra| Ok(extra.is_notification());
64
65        /// Try to get the buffer ID associated with this operation.
66        ///
67        /// # Behavior
68        ///
69        /// This is only supported on `io_uring` drivers, in which the driver will
70        /// try to extract `buffer_id` returned by the kernel as a part of `flags`.
71        /// If the id cannot be extracted from the flag, an [`InvalidInput`]
72        /// [`io::Error`] will be returned. On other platforms, this will always
73        /// return [`Unsupported`] error.
74        ///
75        /// [`InvalidInput`]: io::ErrorKind::InvalidInput
76        /// [`Unsupported`]: io::ErrorKind::Unsupported
77        get fn buffer_id(&self) -> io::Result<u16> =
78            |extra| extra
79                .buffer_id()
80                .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Buffer id was not set"));
81
82
83        /// Get the personality for this operation.
84        ///
85        /// # Behavior
86        ///
87        /// - If the driver is not `io_uring`, return [`Unsupported`] error,
88        /// - If the personality was not set with [`set_personality`], return `Ok(None)`
89        /// - Otherwise, return `Ok(Some(personality))`
90        ///
91        /// [`Unsupported`]: io::ErrorKind::Unsupported
92        /// [`set_personality`]: Extra::set_personality
93        get fn get_personality(&self) -> io::Result<Option<u16>> = |extra| Ok(extra.get_personality());
94
95        /// Checks whether the underlying socket has more data to be read.
96        ///
97        /// # Behaviour
98        ///
99        /// This method must be used only on the flags for any of the `receive`
100        /// variants supported by `IO_URING`. The driver will try to check whether
101        /// the `IORING_CQE_F_SOCK_NONEMPTY` flag was set by the kernel for the CQE.
102        /// On other platforms, this will always return the [`Unsupported`] error.
103        ///
104        /// [`Unsupported`]: io::ErrorKind::Unsupported
105        get fn sock_nonempty(&self) -> io::Result<bool> = |extra| Ok(extra.sock_nonempty());
106
107        /// Set the `IOSQE_IO_DRAIN` flag for this operation.
108        ///
109        /// This ensures that this operation won't start until all previously submitted operations complete.
110        ///
111        /// See [`io_uring_sqe_set_flags(3)`] for more details.
112        ///
113        /// [`io_uring_sqe_set_flags(3)`]: https://man7.org/linux/man-pages/man3/io_uring_sqe_set_flags.3.html
114        set fn drain(&mut self) = |extra| extra.set_drain();
115
116        /// Set the `IOSQE_IO_LINK` flag for this operation.
117        ///
118        /// This links this operation with the next one. The next operation will not start until this operation
119        /// completed successfully.
120        ///
121        /// See [`io_uring_sqe_set_flags(3)`] for more details.
122        ///
123        /// [`io_uring_sqe_set_flags(3)`]: https://man7.org/linux/man-pages/man3/io_uring_sqe_set_flags.3.html
124        set fn link(&mut self) = |extra| extra.set_link();
125
126        /// Set the `IOSQE_IO_HARDLINK` flag for this operation.
127        ///
128        /// Like link, but the next operation will execute regardless of this operation's result.
129        ///
130        /// See [`io_uring_sqe_set_flags(3)`] for more details.
131        ///
132        /// [`io_uring_sqe_set_flags(3)`]: https://man7.org/linux/man-pages/man3/io_uring_sqe_set_flags.3.html
133        set fn hardlink(&mut self) = |extra| extra.set_hardlink();
134
135        /// Set the personality for this operation.
136        ///
137        /// A personality represents a set of credentials (uid, gid, etc.) that will be used for this operation.
138        ///
139        /// The personality can be retrieved with [`Proactor::register_personality`].
140        ///
141        /// [`Proactor::register_personality`]: crate::Proactor::register_personality
142        set fn personality(&mut self, personality: u16) = |extra| extra.set_personality(personality);
143    }
144}
145
146macro_rules! iour_only {
147    {} => {};
148    {
149        $(#[$doc:meta])*
150        get fn $fn:ident(&$this:ident) -> io::Result<$ret:ty> = |$extra:ident| $body:expr;
151        $($rest:tt)*
152    } => {
153        $(#[$doc])*
154        pub fn $fn (&$this) -> io::Result<$ret> {
155            const UNSUPPORTED: &str = concat!(stringify!($fn), " is only supported on the io_uring driver");
156            #[cfg(io_uring)]
157            if let Some($extra) = $this.try_as_iour() {
158                $body
159            } else {
160                Err(io::Error::new(io::ErrorKind::Unsupported, UNSUPPORTED))
161            }
162            #[cfg(not(io_uring))]
163            Err(io::Error::new(io::ErrorKind::Unsupported, UNSUPPORTED))
164        }
165        iour_only!($($rest)*);
166    };
167    {
168        $(#[$doc:meta])*
169        set fn $val:ident(&mut $this:ident $(, $arg:ident: $arg_ty:ty)*) = |$extra:ident| $body:expr;
170        $($rest:tt)*
171    } => {
172        paste::paste! {
173            $(#[$doc])*
174            #[doc = " This is a no-op when not using `io_uring` driver."]
175            pub fn [<set_ $val>] (&mut $this $(, $arg: $arg_ty)*) {
176                #[cfg(io_uring)]
177                if let Some($extra) = $this.try_as_iour_mut() {
178                    $body
179                }
180                #[cfg(not(io_uring))]
181                {$(let _ = $arg;)*}
182            }
183
184            #[doc = concat!("Call [`set_", stringify!($val), "`] and return the modified `Extra`.")]
185            #[doc = ""]
186            #[doc = concat!("[`set_", stringify!($val), "`]: Self::set_", stringify!($val))]
187            pub fn [<with_ $val>] (mut $this $(, $arg: $arg_ty)*) -> Self {
188                $this.[<set_ $val>]($($arg),*);
189                $this
190            }
191        }
192        iour_only!($($rest)*);
193    };
194}
195
196use iour_only;
197
198use crate::Driver;