rustix_uring/lib.rs
1//! The `io_uring` library for Rust.
2//!
3//! The crate only provides a summary of the parameters.
4//! For more detailed documentation, see manpage.
5#![no_std]
6
7#[macro_use]
8mod util;
9pub mod cqueue;
10pub mod opcode;
11pub mod register;
12pub mod squeue;
13mod submit;
14use rustix::io_uring as sys;
15pub mod types;
16pub use rustix::io::{Errno, Result};
17
18use core::marker::PhantomData;
19use core::mem::ManuallyDrop;
20use core::{cmp, mem};
21
22use rustix::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, OwnedFd, RawFd};
23
24pub use cqueue::CompletionQueue;
25pub use register::Probe;
26pub use squeue::SubmissionQueue;
27pub use submit::Submitter;
28use util::Mmap;
29
30/// IoUring instance
31///
32/// - `S`: The ring's submission queue entry (SQE) type, either [`squeue::Entry`] or
33/// [`squeue::Entry128`];
34/// - `C`: The ring's completion queue entry (CQE) type, either [`cqueue::Entry`] or
35/// [`cqueue::Entry32`].
36pub struct IoUring<S = squeue::Entry, C = cqueue::Entry>
37where
38 S: squeue::EntryMarker,
39 C: cqueue::EntryMarker,
40{
41 sq: squeue::Inner<S>,
42 cq: cqueue::Inner<C>,
43 fd: OwnedFd,
44 params: Parameters,
45 memory: ManuallyDrop<MemoryMap>,
46}
47
48struct MemoryMap {
49 sq_mmap: Mmap,
50 sqe_mmap: Mmap,
51 cq_mmap: Option<Mmap>,
52}
53
54/// IoUring build params
55#[derive(Clone, Default)]
56pub struct Builder<S = squeue::Entry, C = cqueue::Entry>
57where
58 S: squeue::EntryMarker,
59 C: cqueue::EntryMarker,
60{
61 dontfork: bool,
62 params: sys::io_uring_params,
63 phantom: PhantomData<(S, C)>,
64}
65
66/// The parameters that were used to construct an [`IoUring`].
67///
68/// This type is a transparent wrapper over the system structure `io_uring_params`. A value can be
69/// (unsafely) created from any properly laid-out and initialized memory representation.
70#[derive(Clone)]
71#[repr(transparent)]
72pub struct Parameters(sys::io_uring_params);
73
74unsafe impl<S: squeue::EntryMarker, C: cqueue::EntryMarker> Send for IoUring<S, C> {}
75unsafe impl<S: squeue::EntryMarker, C: cqueue::EntryMarker> Sync for IoUring<S, C> {}
76
77impl IoUring<squeue::Entry, cqueue::Entry> {
78 /// Create a new `IoUring` instance with default configuration parameters. See [`Builder`] to
79 /// customize it further.
80 ///
81 /// The `entries` sets the size of queue,
82 /// and its value should be the power of two.
83 pub fn new(entries: u32) -> Result<Self> {
84 Self::builder().build(entries)
85 }
86
87 /// Create an `IoUring` instance from a pre-opened file descriptor.
88 ///
89 /// # Safety
90 ///
91 /// The caller must uphold that the file descriptor is owned and refers to a uring. The
92 /// `params` argument must be equivalent to the those previously filled in by the kernel when
93 /// the provided ring was created.
94 pub unsafe fn from_fd(fd: RawFd, params: Parameters) -> Result<Self> {
95 Self::with_fd_and_params(OwnedFd::from_raw_fd(fd), params.0)
96 }
97}
98
99impl<S: squeue::EntryMarker, C: cqueue::EntryMarker> IoUring<S, C> {
100 /// Create a [`Builder`] for an `IoUring` instance.
101 ///
102 /// This allows for further customization than [`new`](Self::new).
103 ///
104 /// Unlike [`IoUring::new`], this function is available for any combination of submission
105 /// queue entry (SQE) and completion queue entry (CQE) types.
106 #[must_use]
107 pub fn builder() -> Builder<S, C> {
108 let mut params = sys::io_uring_params::default();
109 params.flags = S::BUILD_FLAGS | C::BUILD_FLAGS;
110 Builder {
111 dontfork: false,
112 params,
113 phantom: PhantomData,
114 }
115 }
116
117 unsafe fn with_params(entries: u32, mut p: sys::io_uring_params) -> Result<Self> {
118 let fd = unsafe { sys::io_uring_setup(entries, &mut p)? };
119 unsafe { Self::with_fd_and_params(fd, p) }
120 }
121
122 unsafe fn with_fd_and_params(fd: OwnedFd, p: sys::io_uring_params) -> Result<Self> {
123 // NOTE: The `SubmissionQueue` and `CompletionQueue` are references,
124 // and their lifetime can never exceed `MemoryMap`.
125 //
126 // The memory mapped regions of `MemoryMap` never move,
127 // so `SubmissionQueue` and `CompletionQueue` are `Unpin`.
128 //
129 // I really hope that Rust can safely use self-reference types.
130 #[inline]
131 unsafe fn setup_queue<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
132 fd: &OwnedFd,
133 p: &sys::io_uring_params,
134 ) -> Result<(MemoryMap, squeue::Inner<S>, cqueue::Inner<C>)> {
135 let sq_len = p.sq_off.array as usize + p.sq_entries as usize * mem::size_of::<u32>();
136 let cq_len = p.cq_off.cqes as usize + p.cq_entries as usize * mem::size_of::<C>();
137 let sqe_len = p.sq_entries as usize * mem::size_of::<S>();
138 let sqe_mmap = Mmap::new(fd, sys::IORING_OFF_SQES as _, sqe_len)?;
139
140 if p.features.contains(sys::IoringFeatureFlags::SINGLE_MMAP) {
141 let scq_mmap =
142 Mmap::new(fd, sys::IORING_OFF_SQ_RING as _, cmp::max(sq_len, cq_len))?;
143
144 let sq = squeue::Inner::new(&scq_mmap, &sqe_mmap, p);
145 let cq = cqueue::Inner::new(&scq_mmap, p);
146 let mm = MemoryMap {
147 sq_mmap: scq_mmap,
148 cq_mmap: None,
149 sqe_mmap,
150 };
151
152 Ok((mm, sq, cq))
153 } else {
154 let sq_mmap = Mmap::new(fd, sys::IORING_OFF_SQ_RING as _, sq_len)?;
155 let cq_mmap = Mmap::new(fd, sys::IORING_OFF_CQ_RING as _, cq_len)?;
156
157 let sq = squeue::Inner::new(&sq_mmap, &sqe_mmap, p);
158 let cq = cqueue::Inner::new(&cq_mmap, p);
159 let mm = MemoryMap {
160 cq_mmap: Some(cq_mmap),
161 sq_mmap,
162 sqe_mmap,
163 };
164
165 Ok((mm, sq, cq))
166 }
167 }
168
169 let (mm, sq, cq) = setup_queue(&fd, &p)?;
170
171 Ok(IoUring {
172 sq,
173 cq,
174 fd,
175 params: Parameters(p),
176 memory: ManuallyDrop::new(mm),
177 })
178 }
179
180 /// Get the submitter of this io_uring instance, which can be used to submit submission queue
181 /// events to the kernel for execution and to register files or buffers with it.
182 #[inline]
183 pub fn submitter(&self) -> Submitter<'_> {
184 Submitter::new(
185 &self.fd,
186 &self.params,
187 self.sq.head,
188 self.sq.tail,
189 self.sq.flags,
190 )
191 }
192
193 /// Get the parameters that were used to construct this instance.
194 #[inline]
195 pub fn params(&self) -> &Parameters {
196 &self.params
197 }
198
199 /// Initiate asynchronous I/O. See [`Submitter::submit`] for more details.
200 #[inline]
201 pub fn submit(&self) -> Result<usize> {
202 self.submitter().submit()
203 }
204
205 /// Initiate and/or complete asynchronous I/O. See [`Submitter::submit_and_wait`] for more
206 /// details.
207 #[inline]
208 pub fn submit_and_wait(&self, want: usize) -> Result<usize> {
209 self.submitter().submit_and_wait(want)
210 }
211
212 /// Get the submitter, submission queue and completion queue of the io_uring instance. This can
213 /// be used to operate on the different parts of the io_uring instance independently.
214 ///
215 /// If you use this method to obtain `sq` and `cq`,
216 /// please note that you need to `drop` or `sync` the queue before and after submit,
217 /// otherwise the queue will not be updated.
218 #[inline]
219 pub fn split(
220 &mut self,
221 ) -> (
222 Submitter<'_>,
223 SubmissionQueue<'_, S>,
224 CompletionQueue<'_, C>,
225 ) {
226 let submit = Submitter::new(
227 &self.fd,
228 &self.params,
229 self.sq.head,
230 self.sq.tail,
231 self.sq.flags,
232 );
233 (submit, self.sq.borrow(), self.cq.borrow())
234 }
235
236 /// Get the submission queue of the io_uring instance. This is used to send I/O requests to the
237 /// kernel.
238 #[inline]
239 pub fn submission(&mut self) -> SubmissionQueue<'_, S> {
240 self.sq.borrow()
241 }
242
243 /// Get the submission queue of the io_uring instance from a shared reference.
244 ///
245 /// # Safety
246 ///
247 /// No other [`SubmissionQueue`]s may exist when calling this function.
248 #[inline]
249 pub unsafe fn submission_shared(&self) -> SubmissionQueue<'_, S> {
250 self.sq.borrow_shared()
251 }
252
253 /// Get completion queue of the io_uring instance. This is used to receive I/O completion
254 /// events from the kernel.
255 #[inline]
256 pub fn completion(&mut self) -> CompletionQueue<'_, C> {
257 self.cq.borrow()
258 }
259
260 /// Get the completion queue of the io_uring instance from a shared reference.
261 ///
262 /// # Safety
263 ///
264 /// No other [`CompletionQueue`]s may exist when calling this function.
265 #[inline]
266 pub unsafe fn completion_shared(&self) -> CompletionQueue<'_, C> {
267 self.cq.borrow_shared()
268 }
269}
270
271impl<S: squeue::EntryMarker, C: cqueue::EntryMarker> Drop for IoUring<S, C> {
272 fn drop(&mut self) {
273 // Ensure that `MemoryMap` is released before `fd`.
274 unsafe {
275 ManuallyDrop::drop(&mut self.memory);
276 }
277 }
278}
279
280impl<S: squeue::EntryMarker, C: cqueue::EntryMarker> Builder<S, C> {
281 /// Do not make this io_uring instance accessible by child processes after a fork.
282 pub fn dontfork(&mut self) -> &mut Self {
283 self.dontfork = true;
284 self
285 }
286
287 /// Perform busy-waiting for I/O completion events, as opposed to getting notifications via an
288 /// asynchronous IRQ (Interrupt Request). This will reduce latency, but increases CPU usage.
289 ///
290 /// This is only usable on file systems that support polling and files opened with `O_DIRECT`.
291 pub fn setup_iopoll(&mut self) -> &mut Self {
292 self.params.flags |= sys::IoringSetupFlags::IOPOLL;
293 self
294 }
295
296 /// Use a kernel thread to perform submission queue polling. This allows your application to
297 /// issue I/O without ever context switching into the kernel, however it does use up a lot more
298 /// CPU. You should use it when you are expecting very large amounts of I/O.
299 ///
300 /// After `idle` milliseconds, the kernel thread will go to sleep and you will have to wake it up
301 /// again with a system call (this is handled by [`Submitter::submit`] and
302 /// [`Submitter::submit_and_wait`] automatically).
303 ///
304 /// Before version 5.11 of the Linux kernel, to successfully use this feature, the application
305 /// must register a set of files to be used for IO through io_uring_register(2) using the
306 /// IORING_REGISTER_FILES opcode. Failure to do so will result in submitted IO being errored
307 /// with EBADF. The presence of this feature can be detected by the IORING_FEAT_SQPOLL_NONFIXED
308 /// feature flag. In version 5.11 and later, it is no longer necessary to register files to use
309 /// this feature. 5.11 also allows using this as non-root, if the user has the CAP_SYS_NICE
310 /// capability. In 5.13 this requirement was also relaxed, and no special privileges are needed
311 /// for SQPOLL in newer kernels. Certain stable kernels older than 5.13 may also support
312 /// unprivileged SQPOLL.
313 pub fn setup_sqpoll(&mut self, idle: u32) -> &mut Self {
314 self.params.flags |= sys::IoringSetupFlags::SQPOLL;
315 self.params.sq_thread_idle = idle;
316 self
317 }
318
319 /// Bind the kernel's poll thread to the specified cpu. This flag is only meaningful when
320 /// [`Builder::setup_sqpoll`] is enabled.
321 pub fn setup_sqpoll_cpu(&mut self, cpu: u32) -> &mut Self {
322 self.params.flags |= sys::IoringSetupFlags::SQ_AFF;
323 self.params.sq_thread_cpu = cpu;
324 self
325 }
326
327 /// Create the completion queue with the specified number of entries. The value must be greater
328 /// than `entries`, and may be rounded up to the next power-of-two.
329 pub fn setup_cqsize(&mut self, entries: u32) -> &mut Self {
330 self.params.flags |= sys::IoringSetupFlags::CQSIZE;
331 self.params.cq_entries = entries;
332 self
333 }
334
335 /// Clamp the sizes of the submission queue and completion queue at their maximum values instead
336 /// of returning an error when you attempt to resize them beyond their maximum values.
337 pub fn setup_clamp(&mut self) -> &mut Self {
338 self.params.flags |= sys::IoringSetupFlags::CLAMP;
339 self
340 }
341
342 /// Share the asynchronous worker thread backend of this io_uring with the specified io_uring
343 /// file descriptor instead of creating a new thread pool.
344 ///
345 /// # Safety
346 ///
347 /// `fd` must be an open file descriptor.
348 pub unsafe fn setup_attach_wq(&mut self, fd: RawFd) -> &mut Self {
349 self.params.flags |= sys::IoringSetupFlags::ATTACH_WQ;
350 self.params.wq_fd = fd as _;
351 self
352 }
353
354 /// Start the io_uring instance with all its rings disabled. This allows you to register
355 /// restrictions, buffers and files before the kernel starts processing submission queue
356 /// events. You are only able to [register restrictions](Submitter::register_restrictions) when
357 /// the rings are disabled due to concurrency issues. You can enable the rings with
358 /// [`Submitter::register_enable_rings`]. Available since 5.10.
359 pub fn setup_r_disabled(&mut self) -> &mut Self {
360 self.params.flags |= sys::IoringSetupFlags::R_DISABLED;
361 self
362 }
363
364 /// Normally io_uring stops submitting a batch of request, if one of these requests results in
365 /// an error. This can cause submission of less than what is expected, if a request ends in
366 /// error while being submitted. If the ring is created with this flag, io_uring_enter(2) will
367 /// continue submitting requests even if it encounters an error submitting a request. CQEs are
368 /// still posted for errored request regardless of whether or not this flag is set at ring
369 /// creation time, the only difference is if the submit sequence is halted or continued when an
370 /// error is observed. Available since 5.18.
371 pub fn setup_submit_all(&mut self) -> &mut Self {
372 self.params.flags |= sys::IoringSetupFlags::SUBMIT_ALL;
373 self
374 }
375
376 /// By default, io_uring will interrupt a task running in userspace when a completion event
377 /// comes in. This is to ensure that completions run in a timely manner. For a lot of use
378 /// cases, this is overkill and can cause reduced performance from both the inter-processor
379 /// interrupt used to do this, the kernel/user transition, the needless interruption of the
380 /// tasks userspace activities, and reduced batching if completions come in at a rapid rate.
381 /// Most applications don't need the forceful interruption, as the events are processed at any
382 /// kernel/user transition. The exception are setups where the application uses multiple
383 /// threads operating on the same ring, where the application waiting on completions isn't the
384 /// one that submitted them. For most other use cases, setting this flag will improve
385 /// performance. Available since 5.19.
386 pub fn setup_coop_taskrun(&mut self) -> &mut Self {
387 self.params.flags |= sys::IoringSetupFlags::COOP_TASKRUN;
388 self
389 }
390
391 /// Used in conjunction with IORING_SETUP_COOP_TASKRUN, this provides a flag,
392 /// IORING_SQ_TASKRUN, which is set in the SQ ring flags whenever completions are pending that
393 /// should be processed. As an example, liburing will check for this flag even when doing
394 /// io_uring_peek_cqe(3) and enter the kernel to process them, and applications can do the
395 /// same. This makes IORING_SETUP_TASKRUN_FLAG safe to use even when applications rely on a
396 /// peek style operation on the CQ ring to see if anything might be pending to reap. Available
397 /// since 5.19.
398 pub fn setup_taskrun_flag(&mut self) -> &mut Self {
399 self.params.flags |= sys::IoringSetupFlags::TASKRUN_FLAG;
400 self
401 }
402
403 /// By default, io_uring will process all outstanding work at the end of any system call or
404 /// thread interrupt. This can delay the application from making other progress. Setting this
405 /// flag will hint to io_uring that it should defer work until an io_uring_enter(2) call with
406 /// the IORING_ENTER_GETEVENTS flag set. This allows the application to request work to run
407 /// just just before it wants to process completions. This flag requires the
408 /// IORING_SETUP_SINGLE_ISSUER flag to be set, and also enforces that the call to
409 /// io_uring_enter(2) is called from the same thread that submitted requests. Note that if this
410 /// flag is set then it is the application's responsibility to periodically trigger work (for
411 /// example via any of the CQE waiting functions) or else completions may not be delivered.
412 /// Available since 6.1.
413 pub fn setup_defer_taskrun(&mut self) -> &mut Self {
414 self.params.flags |= sys::IoringSetupFlags::DEFER_TASKRUN;
415 self
416 }
417
418 /// Hint the kernel that a single task will submit requests. Used for optimizations. This is
419 /// enforced by the kernel, and request that don't respect that will fail with -EEXIST.
420 /// If [`Builder::setup_sqpoll`] is enabled, the polling task is doing the submissions and multiple
421 /// userspace tasks can call [`Submitter::enter`] and higher level APIs. Available since 6.0.
422 pub fn setup_single_issuer(&mut self) -> &mut Self {
423 self.params.flags |= sys::IoringSetupFlags::SINGLE_ISSUER;
424 self
425 }
426
427 /// Build an [IoUring], with the specified number of entries in the submission queue and
428 /// completion queue unless [`setup_cqsize`](Self::setup_cqsize) has been called.
429 pub fn build(&self, entries: u32) -> Result<IoUring<S, C>> {
430 let ring = unsafe { IoUring::with_params(entries, self.params)? };
431
432 if self.dontfork {
433 ring.memory.sq_mmap.dontfork()?;
434 ring.memory.sqe_mmap.dontfork()?;
435 if let Some(cq_mmap) = ring.memory.cq_mmap.as_ref() {
436 cq_mmap.dontfork()?;
437 }
438 }
439
440 Ok(ring)
441 }
442}
443
444impl Parameters {
445 /// Whether a kernel thread is performing queue polling. Enabled with [`Builder::setup_sqpoll`].
446 pub fn is_setup_sqpoll(&self) -> bool {
447 self.0.flags.contains(sys::IoringSetupFlags::SQPOLL)
448 }
449
450 /// Whether waiting for completion events is done with a busy loop instead of using IRQs.
451 /// Enabled with [`Builder::setup_iopoll`].
452 pub fn is_setup_iopoll(&self) -> bool {
453 self.0.flags.contains(sys::IoringSetupFlags::IOPOLL)
454 }
455
456 /// Whether the single issuer hint is enabled. Enabled with [`Builder::setup_single_issuer`].
457 pub fn is_setup_single_issuer(&self) -> bool {
458 self.0.flags.contains(sys::IoringSetupFlags::SINGLE_ISSUER)
459 }
460
461 /// If this flag is set, the SQ and CQ rings were mapped with a single `mmap(2)` call. This
462 /// means that only two syscalls were used instead of three.
463 pub fn is_feature_single_mmap(&self) -> bool {
464 self.0
465 .features
466 .contains(sys::IoringFeatureFlags::SINGLE_MMAP)
467 }
468
469 /// If this flag is set, io_uring supports never dropping completion events. If a completion
470 /// event occurs and the CQ ring is full, the kernel stores the event internally until such a
471 /// time that the CQ ring has room for more entries.
472 pub fn is_feature_nodrop(&self) -> bool {
473 self.0.features.contains(sys::IoringFeatureFlags::NODROP)
474 }
475
476 /// If this flag is set, applications can be certain that any data for async offload has been
477 /// consumed when the kernel has consumed the SQE.
478 pub fn is_feature_submit_stable(&self) -> bool {
479 self.0
480 .features
481 .contains(sys::IoringFeatureFlags::SUBMIT_STABLE)
482 }
483
484 /// If this flag is set, applications can specify offset == -1 with [`Readv`](opcode::Readv),
485 /// [`Writev`](opcode::Writev), [`ReadFixed`](opcode::ReadFixed),
486 /// [`WriteFixed`](opcode::WriteFixed), [`Read`](opcode::Read) and [`Write`](opcode::Write),
487 /// which behaves exactly like setting offset == -1 in `preadv2(2)` and `pwritev2(2)`: it’ll use
488 /// (and update) the current file position.
489 ///
490 /// This obviously comes with the caveat that if the application has multiple reads or writes in flight,
491 /// then the end result will not be as expected.
492 /// This is similar to threads sharing a file descriptor and doing IO using the current file position.
493 pub fn is_feature_rw_cur_pos(&self) -> bool {
494 self.0
495 .features
496 .contains(sys::IoringFeatureFlags::RW_CUR_POS)
497 }
498
499 /// If this flag is set, then io_uring guarantees that both sync and async execution of
500 /// a request assumes the credentials of the task that called [`Submitter::enter`] to queue the requests.
501 /// If this flag isn’t set, then requests are issued with the credentials of the task that originally registered the io_uring.
502 /// If only one task is using a ring, then this flag doesn’t matter as the credentials will always be the same.
503 ///
504 /// Note that this is the default behavior, tasks can still register different personalities
505 /// through [`Submitter::register_personality`].
506 pub fn is_feature_cur_personality(&self) -> bool {
507 self.0
508 .features
509 .contains(sys::IoringFeatureFlags::CUR_PERSONALITY)
510 }
511
512 /// Whether async pollable I/O is fast.
513 ///
514 /// See [the commit message that introduced
515 /// it](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=d7718a9d25a61442da8ee8aeeff6a0097f0ccfd6)
516 /// for more details.
517 ///
518 /// If this flag is set, then io_uring supports using an internal poll mechanism to drive
519 /// data/space readiness. This means that requests that cannot read or write data to a file no
520 /// longer need to be punted to an async thread for handling, instead they will begin operation
521 /// when the file is ready. This is similar to doing poll + read/write in userspace, but
522 /// eliminates the need to do so. If this flag is set, requests waiting on space/data consume a
523 /// lot less resources doing so as they are not blocking a thread. Available since kernel 5.7.
524 pub fn is_feature_fast_poll(&self) -> bool {
525 self.0.features.contains(sys::IoringFeatureFlags::FAST_POLL)
526 }
527
528 /// Whether poll events are stored using 32 bits instead of 16. This allows the user to use
529 /// `EPOLLEXCLUSIVE`.
530 ///
531 /// If this flag is set, the IORING_OP_POLL_ADD command accepts the full 32-bit range of epoll
532 /// based flags. Most notably EPOLLEXCLUSIVE which allows exclusive (waking single waiters)
533 /// behavior. Available since kernel 5.9.
534 pub fn is_feature_poll_32bits(&self) -> bool {
535 self.0
536 .features
537 .contains(sys::IoringFeatureFlags::POLL_32BITS)
538 }
539
540 /// If this flag is set, the IORING_SETUP_SQPOLL feature no longer requires the use of fixed
541 /// files. Any normal file descriptor can be used for IO commands without needing registration.
542 /// Available since kernel 5.11.
543 pub fn is_feature_sqpoll_nonfixed(&self) -> bool {
544 self.0
545 .features
546 .contains(sys::IoringFeatureFlags::SQPOLL_NONFIXED)
547 }
548
549 /// If this flag is set, then the io_uring_enter(2) system call supports passing in an extended
550 /// argument instead of just the sigset_t of earlier kernels. This extended argument is of type
551 /// struct io_uring_getevents_arg and allows the caller to pass in both a sigset_t and a
552 /// timeout argument for waiting on events. The struct layout is as follows:
553 ///
554 /// // struct io_uring_getevents_arg {
555 /// // __u64 sigmask;
556 /// // __u32 sigmask_sz;
557 /// // __u32 pad;
558 /// // __u64 ts;
559 /// // };
560 ///
561 /// and a pointer to this struct must be passed in if IORING_ENTER_EXT_ARG is set in the flags
562 /// for the enter system call. Available since kernel 5.11.
563 pub fn is_feature_ext_arg(&self) -> bool {
564 self.0.features.contains(sys::IoringFeatureFlags::EXT_ARG)
565 }
566
567 /// If this flag is set, io_uring is using native workers for its async helpers. Previous
568 /// kernels used kernel threads that assumed the identity of the original io_uring owning task,
569 /// but later kernels will actively create what looks more like regular process threads
570 /// instead. Available since kernel 5.12.
571 pub fn is_feature_native_workers(&self) -> bool {
572 self.0
573 .features
574 .contains(sys::IoringFeatureFlags::NATIVE_WORKERS)
575 }
576
577 /// Whether the kernel supports tagging resources.
578 ///
579 /// If this flag is set, then io_uring supports a variety of features related to fixed files
580 /// and buffers. In particular, it indicates that registered buffers can be updated in-place,
581 /// whereas before the full set would have to be unregistered first. Available since kernel
582 /// 5.13.
583 pub fn is_feature_resource_tagging(&self) -> bool {
584 self.0.features.contains(sys::IoringFeatureFlags::RSRC_TAGS)
585 }
586
587 /// Whether the kernel supports `IOSQE_CQE_SKIP_SUCCESS`.
588 ///
589 /// This feature allows skipping the generation of a CQE if a SQE executes normally. Available
590 /// since kernel 5.17.
591 pub fn is_feature_skip_cqe_on_success(&self) -> bool {
592 self.0.features.contains(sys::IoringFeatureFlags::CQE_SKIP)
593 }
594
595 /// Whether the kernel supports deferred file assignment.
596 ///
597 /// If this flag is set, then io_uring supports sane assignment of files for SQEs that have
598 /// dependencies. For example, if a chain of SQEs are submitted with IOSQE_IO_LINK, then
599 /// kernels without this flag will prepare the file for each link upfront. If a previous link
600 /// opens a file with a known index, eg if direct descriptors are used with open or accept,
601 /// then file assignment needs to happen post execution of that SQE. If this flag is set, then
602 /// the kernel will defer file assignment until execution of a given request is started.
603 /// Available since kernel 5.17.
604 pub fn is_feature_linked_file(&self) -> bool {
605 self.0
606 .features
607 .contains(sys::IoringFeatureFlags::LINKED_FILE)
608 }
609
610 /// Whether the kernel supports `IORING_RECVSEND_BUNDLE`.
611 ///
612 /// This feature allows sending and recieving multiple buffers as a single bundle. Available
613 /// since kernel 6.10.
614 pub fn is_feature_recvsend_bundle(&self) -> bool {
615 self.0
616 .features
617 .contains(sys::IoringFeatureFlags::RECVSEND_BUNDLE)
618 }
619
620 /// The number of submission queue entries allocated.
621 pub fn sq_entries(&self) -> u32 {
622 self.0.sq_entries
623 }
624
625 /// The number of completion queue entries allocated.
626 pub fn cq_entries(&self) -> u32 {
627 self.0.cq_entries
628 }
629}
630
631impl core::fmt::Debug for Parameters {
632 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
633 f.debug_struct("Parameters")
634 .field("is_setup_sqpoll", &self.is_setup_sqpoll())
635 .field("is_setup_iopoll", &self.is_setup_iopoll())
636 .field("is_setup_single_issuer", &self.is_setup_single_issuer())
637 .field("is_feature_single_mmap", &self.is_feature_single_mmap())
638 .field("is_feature_nodrop", &self.is_feature_nodrop())
639 .field("is_feature_submit_stable", &self.is_feature_submit_stable())
640 .field("is_feature_rw_cur_pos", &self.is_feature_rw_cur_pos())
641 .field(
642 "is_feature_cur_personality",
643 &self.is_feature_cur_personality(),
644 )
645 .field("is_feature_poll_32bits", &self.is_feature_poll_32bits())
646 .field("sq_entries", &self.0.sq_entries)
647 .field("cq_entries", &self.0.cq_entries)
648 .finish()
649 }
650}
651
652impl<S: squeue::EntryMarker, C: cqueue::EntryMarker> AsRawFd for IoUring<S, C> {
653 fn as_raw_fd(&self) -> RawFd {
654 self.fd.as_raw_fd()
655 }
656}
657
658impl<S: squeue::EntryMarker, C: cqueue::EntryMarker> AsFd for IoUring<S, C> {
659 fn as_fd(&self) -> BorrowedFd<'_> {
660 self.fd.as_fd()
661 }
662}
663
664// Test the readme code
665// From: https://github.com/rust-lang/cargo/issues/383#issuecomment-720873790
666#[cfg(doctest)]
667mod test_readme {
668 macro_rules! external_doc_test {
669 ($x:expr) => {
670 #[doc = $x]
671 extern "C" {}
672 };
673 }
674
675 external_doc_test!(include_str!("../README.md"));
676}