io_uring/cqueue.rs
1//! Completion Queue
2
3use std::fmt::{self, Debug};
4use std::mem;
5use std::mem::MaybeUninit;
6use std::sync::atomic;
7
8use crate::sys;
9use crate::util::{private, unsync_load, Mmap};
10
11pub(crate) struct Inner<E: EntryMarker> {
12 head: *const atomic::AtomicU32,
13 tail: *const atomic::AtomicU32,
14 ring_mask: u32,
15 ring_entries: u32,
16
17 overflow: *const atomic::AtomicU32,
18
19 cqes: *const E,
20
21 #[allow(dead_code)]
22 flags: *const atomic::AtomicU32,
23}
24
25/// An io_uring instance's completion queue. This stores all the I/O operations that have completed.
26pub struct CompletionQueue<'a, E: EntryMarker = Entry> {
27 head: u32,
28 tail: u32,
29 queue: &'a Inner<E>,
30}
31
32/// A read-only view of whether the completion queue has entries pending.
33///
34/// Obtained from [`CompletionQueue::status`]. Unlike the queue itself this
35/// borrows nothing, so it can be captured once at startup and consulted from
36/// anywhere afterwards. The check costs two loads, with no system call, no
37/// locking, and no access to the ring — which is what a thread-per-core runtime
38/// needs on its preemption check, where reaching the queue would cost more than
39/// the comparison does.
40///
41/// # Staleness
42///
43/// The answer is stale as soon as it is returned: the kernel may post a
44/// completion immediately after the load. This is inherent — any check that
45/// does not enter the kernel is a snapshot — and it makes this suitable for
46/// hints such as "should I stop what I am doing and poll?", where being one
47/// iteration late costs nothing. It is not a synchronization primitive, and
48/// [`CompletionQueue::is_empty`] carries exactly the same caveat.
49pub struct CompletionStatus {
50 head: *const atomic::AtomicU32,
51 tail: *const atomic::AtomicU32,
52}
53
54impl CompletionStatus {
55 /// Returns `true` if the kernel has posted no completions beyond those
56 /// already consumed.
57 ///
58 /// See the note on staleness in the type documentation.
59 #[inline]
60 pub fn is_empty(&self) -> bool {
61 // SAFETY: both pointers are valid for the life of the ring, per the
62 // contract on `CompletionQueue::status`, and are only read here. The
63 // head is advanced solely by this library from the owning thread, so a
64 // non-atomic load is sound; the tail is written by the kernel, so it
65 // needs `Acquire` to order against the entries it publishes.
66 unsafe { unsync_load(self.head) == (*self.tail).load(atomic::Ordering::Acquire) }
67 }
68}
69
70impl Debug for CompletionStatus {
71 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72 f.debug_struct("CompletionStatus")
73 .field("is_empty", &self.is_empty())
74 .finish()
75 }
76}
77
78/// A completion queue entry (CQE), representing a complete I/O operation.
79///
80/// This is implemented for [`Entry`] and [`Entry32`].
81pub trait EntryMarker: Clone + Debug + Into<Entry> + private::Sealed {
82 const BUILD_FLAGS: u32;
83
84 /// Get the application-supplied user data.
85 fn user_data(&self) -> u64;
86
87 /// Replace the application-supplied user data.
88 fn set_user_data(&mut self, user_data: u64);
89}
90
91/// A 16-byte completion queue entry (CQE), representing a complete I/O operation.
92#[repr(C)]
93pub struct Entry(pub(crate) sys::io_uring_cqe);
94
95/// A 32-byte completion queue entry (CQE), representing a complete I/O operation.
96#[repr(C)]
97#[derive(Clone)]
98pub struct Entry32(pub(crate) Entry, pub(crate) [u64; 2]);
99
100#[test]
101fn test_entry_sizes() {
102 assert_eq!(mem::size_of::<Entry>(), 16);
103 assert_eq!(mem::size_of::<Entry32>(), 32);
104}
105
106#[test]
107fn test_user_data() {
108 fn cqe(user_data: u64) -> Entry {
109 Entry(sys::io_uring_cqe {
110 user_data,
111 res: 0,
112 flags: 0,
113 big_cqe: sys::__IncompleteArrayField::new(),
114 })
115 }
116
117 fn replace<E: EntryMarker>(entry: &mut E, user_data: u64) -> u64 {
118 let previous = entry.user_data();
119 entry.set_user_data(user_data);
120 previous
121 }
122
123 let mut entry = cqe(1);
124 assert_eq!(replace(&mut entry, 2), 1);
125 assert_eq!(entry.user_data(), 2);
126
127 let mut entry = Entry32(cqe(3), [0; 2]);
128 assert_eq!(replace(&mut entry, 4), 3);
129 assert_eq!(entry.user_data(), 4);
130}
131
132impl<E: EntryMarker> Inner<E> {
133 #[rustfmt::skip]
134 pub(crate) unsafe fn new(cq_mmap: &Mmap, p: &sys::io_uring_params) -> Self {
135 let head = cq_mmap.offset(p.cq_off.head ) as *const atomic::AtomicU32;
136 let tail = cq_mmap.offset(p.cq_off.tail ) as *const atomic::AtomicU32;
137 let ring_mask = cq_mmap.offset(p.cq_off.ring_mask ).cast::<u32>().read();
138 let ring_entries = cq_mmap.offset(p.cq_off.ring_entries ).cast::<u32>().read();
139 let overflow = cq_mmap.offset(p.cq_off.overflow ) as *const atomic::AtomicU32;
140 let cqes = cq_mmap.offset(p.cq_off.cqes ) as *const E;
141 let flags = cq_mmap.offset(p.cq_off.flags ) as *const atomic::AtomicU32;
142
143 Self {
144 head,
145 tail,
146 ring_mask,
147 ring_entries,
148 overflow,
149 cqes,
150 flags,
151 }
152 }
153
154 #[inline]
155 pub(crate) unsafe fn borrow_shared(&self) -> CompletionQueue<'_, E> {
156 CompletionQueue {
157 head: unsync_load(self.head),
158 tail: (*self.tail).load(atomic::Ordering::Acquire),
159 queue: self,
160 }
161 }
162
163 #[inline]
164 pub(crate) fn borrow(&mut self) -> CompletionQueue<'_, E> {
165 unsafe { self.borrow_shared() }
166 }
167}
168
169impl<E: EntryMarker> CompletionQueue<'_, E> {
170 /// Returns a [`CompletionStatus`], with which a caller can observe that the
171 /// kernel has posted completions without borrowing this queue.
172 ///
173 /// # Safety
174 ///
175 /// The returned value borrows nothing, and so must not outlive the
176 /// [`IoUring`](crate::IoUring) this queue came from.
177 #[inline]
178 pub unsafe fn status(&self) -> CompletionStatus {
179 CompletionStatus {
180 head: self.queue.head,
181 tail: self.queue.tail,
182 }
183 }
184
185 /// Synchronize this type with the real completion queue.
186 ///
187 /// This will flush any entries consumed in this iterator and will make available new entries
188 /// in the queue if the kernel has produced some entries in the meantime.
189 #[inline]
190 pub fn sync(&mut self) {
191 unsafe {
192 (*self.queue.head).store(self.head, atomic::Ordering::Release);
193 self.tail = (*self.queue.tail).load(atomic::Ordering::Acquire);
194 }
195 }
196
197 /// If queue is full and [`is_feature_nodrop`](crate::Parameters::is_feature_nodrop) is not set,
198 /// new events may be dropped. This records the number of dropped events.
199 pub fn overflow(&self) -> u32 {
200 unsafe { (*self.queue.overflow).load(atomic::Ordering::Acquire) }
201 }
202
203 /// Whether eventfd notifications are disabled when a request is completed
204 /// and queued to the CQ ring.
205 ///
206 /// Available since Linux 5.8.
207 pub fn eventfd_disabled(&self) -> bool {
208 unsafe {
209 (*self.queue.flags).load(atomic::Ordering::Acquire) & sys::IORING_CQ_EVENTFD_DISABLED
210 != 0
211 }
212 }
213
214 /// Disable eventfd notifications. While disabled, any eventfd registered
215 /// via [`Submitter::register_eventfd`] will not receive updates from the
216 /// kernel when new completion events are available to be processed.
217 ///
218 /// Available since Linux 5.8.
219 ///
220 /// [`Submitter::register_eventfd`]: crate::Submitter::register_eventfd
221 pub fn disable_eventfd(&self) {
222 unsafe {
223 (*self.queue.flags)
224 .fetch_or(sys::IORING_CQ_EVENTFD_DISABLED, atomic::Ordering::Release);
225 }
226 }
227
228 /// Enable eventfd notifications. While enabled, any eventfd registered via
229 /// [`Submitter::register_eventfd`] will receive updates from the kernel
230 /// when new completion events are available to be processed.
231 ///
232 /// Available since Linux 5.8.
233 ///
234 /// [`Submitter::register_eventfd`]: crate::Submitter::register_eventfd
235 pub fn enable_eventfd(&self) {
236 unsafe {
237 (*self.queue.flags)
238 .fetch_and(!sys::IORING_CQ_EVENTFD_DISABLED, atomic::Ordering::Release);
239 }
240 }
241
242 /// Get the total number of entries in the completion queue ring buffer.
243 #[inline]
244 pub fn capacity(&self) -> usize {
245 self.queue.ring_entries as usize
246 }
247
248 /// Returns `true` if there are no completion queue events to be processed.
249 #[inline]
250 pub fn is_empty(&self) -> bool {
251 self.len() == 0
252 }
253
254 /// Returns `true` if the completion queue is at maximum capacity. If
255 /// [`is_feature_nodrop`](crate::Parameters::is_feature_nodrop) is not set, this will cause any
256 /// new completion queue events to be dropped by the kernel.
257 #[inline]
258 pub fn is_full(&self) -> bool {
259 self.len() == self.capacity()
260 }
261
262 #[inline]
263 pub fn fill<'a>(&mut self, entries: &'a mut [MaybeUninit<E>]) -> &'a mut [E] {
264 let len = std::cmp::min(self.len(), entries.len());
265
266 for entry in &mut entries[..len] {
267 entry.write(unsafe { self.pop() });
268 }
269
270 unsafe { std::slice::from_raw_parts_mut(entries as *mut _ as *mut E, len) }
271 }
272
273 #[inline]
274 unsafe fn pop(&mut self) -> E {
275 let entry = &*self
276 .queue
277 .cqes
278 .add((self.head & self.queue.ring_mask) as usize);
279 self.head = self.head.wrapping_add(1);
280 entry.clone()
281 }
282}
283
284impl<E: EntryMarker> Drop for CompletionQueue<'_, E> {
285 #[inline]
286 fn drop(&mut self) {
287 unsafe { &*self.queue.head }.store(self.head, atomic::Ordering::Release);
288 }
289}
290
291impl<E: EntryMarker> Iterator for CompletionQueue<'_, E> {
292 type Item = E;
293
294 #[inline]
295 fn next(&mut self) -> Option<Self::Item> {
296 if self.head != self.tail {
297 Some(unsafe { self.pop() })
298 } else {
299 None
300 }
301 }
302
303 #[inline]
304 fn size_hint(&self) -> (usize, Option<usize>) {
305 (self.len(), Some(self.len()))
306 }
307}
308
309impl<E: EntryMarker> ExactSizeIterator for CompletionQueue<'_, E> {
310 #[inline]
311 fn len(&self) -> usize {
312 self.tail.wrapping_sub(self.head) as usize
313 }
314}
315
316impl Entry {
317 /// The operation-specific result code. For example, for a [`Read`](crate::opcode::Read)
318 /// operation this is equivalent to the return value of the `read(2)` system call.
319 #[inline]
320 pub fn result(&self) -> i32 {
321 self.0.res
322 }
323
324 /// The user data of the request, as set by
325 /// [`Entry::user_data`](crate::squeue::Entry::user_data) on the submission queue event.
326 #[inline]
327 pub fn user_data(&self) -> u64 {
328 self.0.user_data
329 }
330
331 /// Replace the application-supplied user data.
332 #[inline]
333 pub fn set_user_data(&mut self, user_data: u64) {
334 self.0.user_data = user_data;
335 }
336
337 /// Metadata related to the operation.
338 ///
339 /// This is currently used for:
340 /// - Storing the selected buffer ID, if one was selected. See
341 /// [`BUFFER_SELECT`](crate::squeue::Flags::BUFFER_SELECT) for more info.
342 #[inline]
343 pub fn flags(&self) -> u32 {
344 self.0.flags
345 }
346}
347
348impl private::Sealed for Entry {}
349
350impl EntryMarker for Entry {
351 const BUILD_FLAGS: u32 = 0;
352
353 #[inline]
354 fn user_data(&self) -> u64 {
355 Entry::user_data(self)
356 }
357
358 #[inline]
359 fn set_user_data(&mut self, user_data: u64) {
360 Entry::set_user_data(self, user_data);
361 }
362}
363
364impl Clone for Entry {
365 fn clone(&self) -> Entry {
366 // io_uring_cqe doesn't implement Clone due to the 'big_cqe' incomplete array field.
367 Entry(unsafe { mem::transmute_copy(&self.0) })
368 }
369}
370
371impl Debug for Entry {
372 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
373 f.debug_struct("Entry")
374 .field("result", &self.result())
375 .field("user_data", &self.user_data())
376 .field("flags", &self.flags())
377 .finish()
378 }
379}
380
381impl Entry32 {
382 /// The operation-specific result code. For example, for a [`Read`](crate::opcode::Read)
383 /// operation this is equivalent to the return value of the `read(2)` system call.
384 #[inline]
385 pub fn result(&self) -> i32 {
386 self.0 .0.res
387 }
388
389 /// The user data of the request, as set by
390 /// [`Entry::user_data`](crate::squeue::Entry::user_data) on the submission queue event.
391 #[inline]
392 pub fn user_data(&self) -> u64 {
393 self.0 .0.user_data
394 }
395
396 /// Replace the application-supplied user data.
397 #[inline]
398 pub fn set_user_data(&mut self, user_data: u64) {
399 self.0 .0.user_data = user_data;
400 }
401
402 /// Metadata related to the operation.
403 ///
404 /// This is currently used for:
405 /// - Storing the selected buffer ID, if one was selected. See
406 /// [`BUFFER_SELECT`](crate::squeue::Flags::BUFFER_SELECT) for more info.
407 #[inline]
408 pub fn flags(&self) -> u32 {
409 self.0 .0.flags
410 }
411
412 /// Additional data available in 32-byte completion queue entries (CQEs).
413 #[inline]
414 pub fn big_cqe(&self) -> &[u64; 2] {
415 &self.1
416 }
417}
418
419impl private::Sealed for Entry32 {}
420
421impl EntryMarker for Entry32 {
422 const BUILD_FLAGS: u32 = sys::IORING_SETUP_CQE32;
423
424 #[inline]
425 fn user_data(&self) -> u64 {
426 Entry32::user_data(self)
427 }
428
429 #[inline]
430 fn set_user_data(&mut self, user_data: u64) {
431 Entry32::set_user_data(self, user_data);
432 }
433}
434
435impl From<Entry32> for Entry {
436 fn from(entry32: Entry32) -> Self {
437 entry32.0
438 }
439}
440
441impl Debug for Entry32 {
442 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
443 f.debug_struct("Entry32")
444 .field("result", &self.result())
445 .field("user_data", &self.user_data())
446 .field("flags", &self.flags())
447 .field("big_cqe", &self.big_cqe())
448 .finish()
449 }
450}
451
452/// Return whether the buffer will be reused by future CQE completions
453///
454/// This corresponds to the `IORING_CQE_BUF_MORE` flag, and it signals to
455/// the consumer that it should expect further completions involging the
456/// related buffer ID when the registered buffer ring was setup with
457/// the `IOU_PBUF_RING_INC` flag.
458pub fn buffer_more(flags: u32) -> bool {
459 flags & sys::IORING_CQE_F_BUF_MORE != 0
460}
461
462/// Return which dynamic buffer was used by this operation.
463///
464/// This corresponds to the `IORING_CQE_F_BUFFER` flag (and related bit-shifting),
465/// and it signals to the consumer which provided contains the result of this
466/// operation.
467pub fn buffer_select(flags: u32) -> Option<u16> {
468 if flags & sys::IORING_CQE_F_BUFFER != 0 {
469 let id = flags >> sys::IORING_CQE_BUFFER_SHIFT;
470
471 // FIXME
472 //
473 // Should we return u16? maybe kernel will change value of `IORING_CQE_BUFFER_SHIFT` in future.
474 Some(id as u16)
475 } else {
476 None
477 }
478}
479
480/// Return whether further completion events will be submitted for
481/// this same operation.
482///
483/// This corresponds to the `IORING_CQE_F_MORE` flag, and it signals to
484/// the consumer that it should expect further CQE entries after this one,
485/// still from the same original SQE request (e.g. for multishot operations).
486pub fn more(flags: u32) -> bool {
487 flags & sys::IORING_CQE_F_MORE != 0
488}
489
490/// Return whether socket has more data ready to read.
491///
492/// This corresponds to the `IORING_CQE_F_SOCK_NONEMPTY` flag, and it signals to
493/// the consumer that the socket has more data that can be read immediately.
494///
495/// The io_uring documentation says recv, recv-multishot, recvmsg, and recvmsg-multishot
496/// can provide this bit in their respective CQE.
497pub fn sock_nonempty(flags: u32) -> bool {
498 flags & sys::IORING_CQE_F_SOCK_NONEMPTY != 0
499}
500
501/// Returns whether this completion event is a notification.
502///
503/// This corresponds to the `IORING_CQE_F_NOTIF` flag,
504/// currently used by the [SendZc](crate::opcode::SendZc) operation.
505pub fn notif(flags: u32) -> bool {
506 flags & sys::IORING_CQE_F_NOTIF != 0
507}