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