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;