1#![cfg_attr(feature = "nightly", feature(async_iterator, cfg_sanitize))]
58
59#[cfg(not(any(
60 target_os = "android",
61 target_os = "dragonfly",
62 target_os = "freebsd",
63 target_os = "ios",
64 target_os = "linux",
65 target_os = "macos",
66 target_os = "netbsd",
67 target_os = "openbsd",
68 target_os = "tvos",
69 target_os = "visionos",
70 target_os = "watchos",
71)))]
72compile_error!("OS not supported");
73
74use std::time::Duration;
75
76pub mod fd;
78
79mod asan;
80mod config;
81mod msan;
82mod op;
83#[cfg(unix)]
84mod unix;
85
86pub mod extract;
87pub mod fs;
88pub mod io;
89pub mod mem;
90pub mod net;
91pub mod pipe;
92pub mod process;
93
94#[cfg(any(target_os = "android", target_os = "linux"))]
95mod io_uring;
96#[cfg(any(target_os = "android", target_os = "linux"))]
97use io_uring as sys;
98
99#[cfg(any(
100 target_os = "dragonfly",
101 target_os = "freebsd",
102 target_os = "ios",
103 target_os = "macos",
104 target_os = "netbsd",
105 target_os = "openbsd",
106 target_os = "tvos",
107 target_os = "visionos",
108 target_os = "watchos",
109))]
110mod kqueue;
111#[cfg(any(
112 target_os = "dragonfly",
113 target_os = "freebsd",
114 target_os = "ios",
115 target_os = "macos",
116 target_os = "netbsd",
117 target_os = "openbsd",
118 target_os = "tvos",
119 target_os = "visionos",
120 target_os = "watchos",
121))]
122use kqueue as sys;
123
124#[doc(inline)]
125pub use config::Config;
126#[doc(no_inline)]
127pub use extract::Extract;
128#[doc(no_inline)]
129pub use fd::AsyncFd;
130
131#[derive(Debug)]
138pub struct Ring {
139 cq: sys::Completions,
140 sq: sys::Submissions,
141}
142
143impl Ring {
144 pub const fn config<'r>() -> Config<'r> {
146 Config {
147 sys: crate::sys::Config::new(),
148 }
149 }
150
151 #[doc(alias = "io_uring_setup")]
155 #[doc(alias = "kqueue")]
156 pub fn new() -> io::Result<Ring> {
157 Ring::config().build()
158 }
159
160 pub fn sq(&self) -> SubmissionQueue {
164 SubmissionQueue(self.sq.clone())
165 }
166
167 #[doc(alias = "io_uring_enter")]
174 #[doc(alias = "kevent")]
175 pub fn poll(&mut self, timeout: Option<Duration>) -> io::Result<()> {
176 self.cq.poll(self.sq.shared(), timeout)
177 }
178}
179
180#[derive(Clone, Debug)]
188#[repr(transparent)]
189pub struct SubmissionQueue(sys::Submissions);
190
191impl SubmissionQueue {
192 pub fn wake(&self) {
201 if let Err(err) = self.0.wake() {
202 log::warn!("failed to wake a10::Ring: {err}");
203 }
204 }
205
206 pub(crate) fn submissions(&self) -> &sys::Submissions {
207 &self.0
208 }
209
210 pub(crate) const fn sq(&self) -> &SubmissionQueue {
215 self
216 }
217}
218
219macro_rules! syscall {
221 ($fn: ident ( $($arg: expr),* $(,)? ) ) => {{
222 #[allow(unused_unsafe)]
223 let res = unsafe { libc::$fn($( $arg, )*) };
224 if res == -1 {
225 ::std::result::Result::Err(::std::io::Error::last_os_error())
226 } else {
227 ::std::result::Result::Ok(res)
228 }
229 }};
230}
231
232#[rustfmt::skip]
234macro_rules! man_link {
235 ($syscall: tt ( $section: tt ) ) => {
236 concat!(
237 "\n\nAdditional documentation can be found in the ",
238 "[`", stringify!($syscall), "(", stringify!($section), ")`]",
239 "(https://man7.org/linux/man-pages/man", stringify!($section), "/", stringify!($syscall), ".", stringify!($section), ".html)",
240 " manual.\n"
241 )
242 };
243}
244
245macro_rules! new_flag {
246 (
247 $(
248 $(#[$type_meta:meta])*
249 $type_vis: vis struct $type_name: ident ( $type_repr: ty ) $( impl BitOr $( $type_or: ty )* )? {
250 $(
251 $(#[$value_meta:meta])*
252 $value_name: ident = $libc: ident :: $value_type: ident,
253 )*
254 }
255 )+
256 ) => {
257 $(
258 $(#[$type_meta])*
259 #[derive(Copy, Clone, Eq, PartialEq)]
260 $type_vis struct $type_name(pub(crate) $type_repr);
261
262 impl $type_name {
263 $(
264 $(#[$value_meta])*
265 #[allow(trivial_numeric_casts, clippy::cast_sign_loss)]
266 $type_vis const $value_name: $type_name = $type_name($libc::$value_type as $type_repr);
267 )*
268
269 #[allow(unused_doc_comments, dead_code)]
272 pub(crate) const ALL_VALUES: &[$type_name] = &[
273 $(
274 $(#[$value_meta])*
275 $type_name::$value_name,
276 )*
277 ];
278 }
279
280 $crate::debug_detail!(impl match for $type_name($type_repr), $( $(#[$value_meta])* $libc::$value_type ),*);
281
282 $(
283 impl std::ops::BitOr for $type_name {
284 type Output = Self;
285
286 fn bitor(self, rhs: Self) -> Self::Output {
287 $type_name(self.0 | rhs.0)
288 }
289 }
290
291 $(
292 impl std::ops::BitOr<$type_or> for $type_name {
293 type Output = Self;
294
295 #[allow(clippy::cast_sign_loss)]
296 fn bitor(self, rhs: $type_or) -> Self::Output {
297 $type_name(self.0 | rhs as $type_repr)
298 }
299 }
300 )*
301 )?
302 )+
303 };
304}
305
306macro_rules! debug_detail {
307 (
308 match $type: ident ($event_type: ty),
310 $( $( #[$meta: meta] )* $libc: ident :: $flag: ident ),+ $(,)?
311 ) => {
312 struct $type($event_type);
313
314 $crate::debug_detail!(impl match for $type($event_type), $( $(#[$meta])* $libc::$flag ),*);
315 };
316 (
317 impl match for $type: ident ($type_repr: ty),
319 $( $( #[$meta: meta] )* $libc: ident :: $flag: ident ),* $(,)?
320 ) => {
321 impl ::std::fmt::Debug for $type {
322 #[allow(trivial_numeric_casts, unreachable_patterns, unreachable_code, unused_doc_comments, clippy::bad_bit_mask)]
323 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
324 mod consts {
325 $(
326 $(#[$meta])*
327 pub(super) const $flag: $type_repr = $libc :: $flag as $type_repr;
328 )*
329 }
330
331 f.write_str(match self.0 {
332 $(
333 $(#[$meta])*
334 consts::$flag => stringify!($flag),
335 )*
336 value => return value.fmt(f),
337 })
338 }
339 }
340 };
341 (
342 bitset $type: ident ($event_type: ty),
344 $( $( #[$meta: meta] )* $libc: ident :: $flag: ident ),+ $(,)?
345 ) => {
346 struct $type($event_type);
347
348 $crate::debug_detail!(impl bitset for $type($event_type), $( $(#[$meta])* $libc::$flag ),*);
349 };
350 (
351 impl bitset for $type: ident ($event_type: ty),
353 $( $( #[$meta: meta] )* $libc: ident :: $flag: ident ),+ $(,)?
354 ) => {
355 impl ::std::fmt::Debug for $type {
356 fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
357 let mut written_one = false;
358 $(
359 $(#[$meta])*
360 #[allow(clippy::bad_bit_mask)] {
362 if self.0 & $libc :: $flag != 0 {
363 if !written_one {
364 write!(f, "{}", stringify!($flag))?;
365 written_one = true;
366 } else {
367 write!(f, "|{}", stringify!($flag))?;
368 }
369 }
370 }
371 )+
372 if !written_one {
373 write!(f, "(empty)")
374 } else {
375 Ok(())
376 }
377 }
378 }
379 };
380}
381
382use {debug_detail, man_link, new_flag, syscall};
383
384fn lock<'a, T>(mutex: &'a std::sync::Mutex<T>) -> std::sync::MutexGuard<'a, T> {
386 match mutex.lock() {
387 Ok(guard) => guard,
388 Err(err) => {
389 mutex.clear_poison();
390 err.into_inner()
391 }
392 }
393}
394
395#[cfg(any(target_os = "android", target_os = "linux"))]
397fn try_lock<'a, T>(mutex: &'a std::sync::Mutex<T>) -> Option<std::sync::MutexGuard<'a, T>> {
398 match mutex.try_lock() {
399 Ok(guard) => Some(guard),
400 Err(std::sync::TryLockError::Poisoned(err)) => {
401 mutex.clear_poison();
402 Some(err.into_inner())
403 }
404 Err(std::sync::TryLockError::WouldBlock) => None,
405 }
406}
407
408#[cfg(any(target_os = "android", target_os = "linux"))]
410fn get_mut<'a, T>(mutex: &'a mut std::sync::Mutex<T>) -> &'a mut T {
411 match mutex.get_mut() {
412 Ok(guard) => guard,
413 Err(err) => err.into_inner(),
414 }
415}
416
417#[allow(unused)]
421trait OpPollResult<T> {
422 fn from_ok(ok: T) -> Self;
423 fn from_err(err: io::Error) -> Self;
424 fn from_res(res: io::Result<T>) -> Self;
425 fn done() -> Self;
426}
427
428impl<T> OpPollResult<T> for io::Result<T> {
429 fn from_ok(ok: T) -> Self {
430 Ok(ok)
431 }
432
433 fn from_err(err: io::Error) -> Self {
434 Err(err)
435 }
436
437 fn from_res(res: io::Result<T>) -> Self {
438 res
439 }
440
441 fn done() -> Self {
442 unreachable!()
443 }
444}
445
446impl<T> OpPollResult<T> for Option<io::Result<T>> {
447 fn from_ok(ok: T) -> Self {
448 Some(Ok(ok))
449 }
450
451 fn from_err(err: io::Error) -> Self {
452 Some(Err(err))
453 }
454
455 fn from_res(res: io::Result<T>) -> Self {
456 Some(res)
457 }
458
459 fn done() -> Self {
460 None
461 }
462}