Skip to main content

compio_driver/sys/extra/
mod.rs

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