Skip to content

Commit b01e8d7

Browse files
committed
Add bitflags! with CompletionFlags for better UX.
1 parent f297f5b commit b01e8d7

File tree

4 files changed

+91
-34
lines changed

4 files changed

+91
-34
lines changed

io-uring-test/src/tests/net.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,7 @@ pub fn test_tcp_buffer_select<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
941941
match bid {
942942
0 => assert_eq!(&buf0[..256], &input[1024..]),
943943
1 => assert_eq!(&buf1[..256], &input[1024..]),
944-
_ => panic!("{}", cqe.flags()),
944+
_ => panic!("{}", cqe.flags().bits()),
945945
}
946946

947947
// remove one remaining buf
@@ -1496,7 +1496,7 @@ pub fn test_socket<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
14961496
assert!(cqes[0].result() >= 0);
14971497
let io_uring_socket = unsafe { Socket::from_raw_fd(cqes[0].result()) };
14981498
assert!(io_uring_socket.as_raw_fd() != plain_fd);
1499-
assert_eq!(cqes[0].flags(), 0);
1499+
assert_eq!(cqes[0].flags(), cqueue::CompletionFlags::empty());
15001500

15011501
// Try a setsockopt.
15021502
{
@@ -1534,7 +1534,7 @@ pub fn test_socket<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
15341534
assert_eq!(cqes.len(), 1);
15351535
assert_eq!(cqes[0].user_data(), 1234);
15361536
assert_eq!(cqes[0].result(), 0);
1537-
assert_eq!(cqes[0].flags(), 0);
1537+
assert_eq!(cqes[0].flags(), cqueue::CompletionFlags::empty());
15381538

15391539
// Check value actually set.
15401540
optval = 0;
@@ -1582,7 +1582,7 @@ pub fn test_socket<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
15821582
assert_eq!(cqes.len(), 1);
15831583
assert_eq!(cqes[0].user_data(), 55);
15841584
assert_eq!(cqes[0].result(), 0);
1585-
assert_eq!(cqes[0].flags(), 0);
1585+
assert_eq!(cqes[0].flags(), cqueue::CompletionFlags::empty());
15861586

15871587
// If the fixed-socket operation worked properly, this must not fail.
15881588
ring.submitter().unregister_files().unwrap();
@@ -1628,7 +1628,7 @@ pub fn test_socket_bind_listen<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
16281628
assert!(cqes[0].result() >= 0);
16291629
let io_uring_socket = unsafe { Socket::from_raw_fd(cqes[0].result()) };
16301630
assert!(io_uring_socket.as_raw_fd() != plain_fd);
1631-
assert_eq!(cqes[0].flags(), 0);
1631+
assert_eq!(cqes[0].flags(), cqueue::CompletionFlags::empty());
16321632

16331633
// Try to bind.
16341634
{
@@ -1649,7 +1649,7 @@ pub fn test_socket_bind_listen<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
16491649
assert_eq!(cqes.len(), 1);
16501650
assert_eq!(cqes[0].user_data(), 2345);
16511651
assert_eq!(cqes[0].result(), 0);
1652-
assert_eq!(cqes[0].flags(), 0);
1652+
assert_eq!(cqes[0].flags(), cqueue::CompletionFlags::empty());
16531653

16541654
assert_eq!(
16551655
io_uring_socket
@@ -1676,7 +1676,7 @@ pub fn test_socket_bind_listen<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
16761676
assert_eq!(cqes.len(), 1);
16771677
assert_eq!(cqes[0].user_data(), 3456);
16781678
assert_eq!(cqes[0].result(), 0);
1679-
assert_eq!(cqes[0].flags(), 0);
1679+
assert_eq!(cqes[0].flags(), cqueue::CompletionFlags::empty());
16801680

16811681
// Ensure the socket is actually in the listening state.
16821682
_ = TcpStream::connect(
@@ -1719,7 +1719,7 @@ pub fn test_socket_bind_listen<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
17191719
assert_eq!(cqes.len(), 1);
17201720
assert_eq!(cqes[0].user_data(), 55);
17211721
assert_eq!(cqes[0].result(), 0);
1722-
assert_eq!(cqes[0].flags(), 0);
1722+
assert_eq!(cqes[0].flags(), cqueue::CompletionFlags::empty());
17231723

17241724
// If the fixed-socket operation worked properly, this must not fail.
17251725
ring.submitter().unregister_files().unwrap();
@@ -1768,7 +1768,7 @@ pub fn test_udp_recvmsg_multishot<S: squeue::EntryMarker, C: cqueue::EntryMarker
17681768
assert_eq!(cqes.len(), 1);
17691769
assert_eq!(cqes[0].user_data(), 11);
17701770
assert_eq!(cqes[0].result(), 0);
1771-
assert_eq!(cqes[0].flags(), 0);
1771+
assert_eq!(cqes[0].flags(), cqueue::CompletionFlags::empty());
17721772
}
17731773

17741774
// This structure is actually only used for input arguments to the kernel
@@ -1922,7 +1922,7 @@ pub fn test_udp_recvmsg_multishot_trunc<S: squeue::EntryMarker, C: cqueue::Entry
19221922
assert_eq!(cqes.len(), 1);
19231923
assert_eq!(cqes[0].user_data(), 11);
19241924
assert_eq!(cqes[0].result(), 0);
1925-
assert_eq!(cqes[0].flags(), 0);
1925+
assert_eq!(cqes[0].flags(), cqueue::CompletionFlags::empty());
19261926
}
19271927

19281928
// This structure is actually only used for input arguments to the kernel
@@ -2133,7 +2133,7 @@ pub fn test_udp_sendzc_with_dest<S: squeue::EntryMarker, C: cqueue::EntryMarker>
21332133
assert_eq!(cqes.len(), 1);
21342134
assert_eq!(cqes[0].user_data(), 11);
21352135
assert_eq!(cqes[0].result(), 0);
2136-
assert_eq!(cqes[0].flags(), 0);
2136+
assert_eq!(cqes[0].flags(), cqueue::CompletionFlags::empty());
21372137
}
21382138

21392139
let recvmsg_e = opcode::RecvMulti::new(Fd(server_socket.as_raw_fd()), BUF_GROUP)

io-uring-test/src/tests/queue.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -187,13 +187,13 @@ pub fn test_msg_ring_data<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
187187
assert_eq!(source_cqes.len(), 1);
188188
assert_eq!(source_cqes[0].user_data(), 0);
189189
assert_eq!(source_cqes[0].result(), 0);
190-
assert_eq!(source_cqes[0].flags(), 0);
190+
assert_eq!(source_cqes[0].flags(), cqueue::CompletionFlags::empty());
191191

192192
let dest_cqes: Vec<cqueue::Entry> = dest_ring.completion().map(Into::into).collect();
193193
assert_eq!(dest_cqes.len(), 1);
194194
assert_eq!(dest_cqes[0].user_data(), user_data);
195195
assert_eq!(dest_cqes[0].result(), result);
196-
assert_eq!(dest_cqes[0].flags(), 0);
196+
assert_eq!(dest_cqes[0].flags(), cqueue::CompletionFlags::empty());
197197

198198
Ok(())
199199
}
@@ -254,13 +254,13 @@ pub fn test_msg_ring_send_fd<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
254254
assert_eq!(source_cqes.len(), 1);
255255
assert_eq!(source_cqes[0].user_data(), 0);
256256
assert_eq!(source_cqes[0].result(), 0);
257-
assert_eq!(source_cqes[0].flags(), 0);
257+
assert_eq!(source_cqes[0].flags(), cqueue::CompletionFlags::empty());
258258

259259
let dest_cqes: Vec<cqueue::Entry> = temp_ring.completion().map(Into::into).collect();
260260
assert_eq!(dest_cqes.len(), 1);
261261
assert_eq!(dest_cqes[0].user_data(), 22);
262262
assert_eq!(dest_cqes[0].result(), 0);
263-
assert_eq!(dest_cqes[0].flags(), 0);
263+
assert_eq!(dest_cqes[0].flags(), cqueue::CompletionFlags::empty());
264264
}
265265

266266
// Unregister the fixed files from the source ring, then reserve some empty slots
@@ -285,13 +285,13 @@ pub fn test_msg_ring_send_fd<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
285285
assert_eq!(source_cqes.len(), 1);
286286
assert_eq!(source_cqes[0].user_data(), 0);
287287
assert_eq!(source_cqes[0].result(), 0);
288-
assert_eq!(source_cqes[0].flags(), 0);
288+
assert_eq!(source_cqes[0].flags(), cqueue::CompletionFlags::empty());
289289

290290
let dest_cqes: Vec<cqueue::Entry> = ring.completion().map(Into::into).collect();
291291
assert_eq!(dest_cqes.len(), 1);
292292
assert_eq!(dest_cqes[0].user_data(), 44);
293293
assert_eq!(dest_cqes[0].result(), 0);
294-
assert_eq!(dest_cqes[0].flags(), 0);
294+
assert_eq!(dest_cqes[0].flags(), cqueue::CompletionFlags::empty());
295295
}
296296

297297
// Unregister the fixed files from both rings, then repeat again to

io-uring-test/src/tests/register_buf_ring.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,12 @@ impl InnerBufRing {
264264

265265
// Returns the buffer the uring interface picked from the buf_ring for the completion result
266266
// represented by the res and flags.
267-
fn get_buf(&self, buf_ring: FixedSizeBufRing, res: u32, flags: u32) -> io::Result<GBuf> {
267+
fn get_buf(
268+
&self,
269+
buf_ring: FixedSizeBufRing,
270+
res: u32,
271+
flags: cqueue::CompletionFlags,
272+
) -> io::Result<GBuf> {
268273
// This fn does the odd thing of having self as the BufRing and taking an argument that is
269274
// the same BufRing but wrapped in Rc<_> so the wrapped buf_ring can be passed to the
270275
// outgoing GBuf.
@@ -279,7 +284,12 @@ impl InnerBufRing {
279284
}
280285

281286
// Returns vector of buffers for completion results that can return a bundle
282-
pub(crate) fn get_bufs(&self, buf_ring: &FixedSizeBufRing, res: u32, flags: u32) -> Vec<GBuf> {
287+
pub(crate) fn get_bufs(
288+
&self,
289+
buf_ring: &FixedSizeBufRing,
290+
res: u32,
291+
flags: cqueue::CompletionFlags,
292+
) -> Vec<GBuf> {
283293
let mut bid = io_uring::cqueue::buffer_select(flags).unwrap();
284294
let mut len = res as usize;
285295
let mut output = Vec::with_capacity(len / self.buf_len);

src/cqueue.rs

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Completion Queue
22
3+
use bitflags::bitflags;
34
use std::fmt::{self, Debug};
45
use std::mem;
56
use std::mem::MaybeUninit;
@@ -212,8 +213,10 @@ impl Entry {
212213
/// - Storing the selected buffer ID, if one was selected. See
213214
/// [`BUFFER_SELECT`](crate::squeue::Flags::BUFFER_SELECT) for more info.
214215
#[inline]
215-
pub fn flags(&self) -> u32 {
216-
self.0.flags
216+
pub fn flags(&self) -> CompletionFlags {
217+
// Use retain as the upper 16 bits store buffer ID if BUFFER_SELECT opt
218+
// is enabled.
219+
CompletionFlags::from_bits_retain(self.0.flags)
217220
}
218221
}
219222

@@ -261,8 +264,10 @@ impl Entry32 {
261264
/// - Storing the selected buffer ID, if one was selected. See
262265
/// [`BUFFER_SELECT`](crate::squeue::Flags::BUFFER_SELECT) for more info.
263266
#[inline]
264-
pub fn flags(&self) -> u32 {
265-
self.0 .0.flags
267+
pub fn flags(&self) -> CompletionFlags {
268+
// Use retain as the upper 16 bits store buffer ID if BUFFER_SELECT opt
269+
// is enabled.
270+
CompletionFlags::from_bits_retain(self.0 .0.flags)
266271
}
267272

268273
/// Additional data available in 32-byte completion queue entries (CQEs).
@@ -295,24 +300,66 @@ impl Debug for Entry32 {
295300
}
296301
}
297302

303+
bitflags!(
304+
/// Request specific information carried in CQE flags field.
305+
/// See man page for complete description:
306+
/// https://man7.org/linux/man-pages/man7/io_uring.7.html
307+
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
308+
pub struct CompletionFlags: u32 {
309+
/// If set, the upper 16 bits of the flags field carries the
310+
/// buffer ID that was chosen for this request. The request
311+
/// must have been issued with IOSQE_BUFFER_SELECT set, and
312+
/// used with a request type that supports buffer selection.
313+
/// Additionally, buffers must have been provided upfront
314+
/// either via the IORING_OP_PROVIDE_BUFFERS or the
315+
/// IORING_REGISTER_PBUF_RING methods.
316+
const BUFFER = sys::IORING_CQE_F_BUFFER;
317+
318+
/// If set, the application should expect more completions from
319+
/// the request. This is used for requests that can generate
320+
/// multiple completions, such as multi-shot requests, receive,
321+
/// or accept.
322+
const MORE = sys::IORING_CQE_F_MORE;
323+
324+
/// If set, upon receiving the data from the socket in the
325+
/// current request, the socket still had data left on
326+
/// completion of this request.
327+
const SOCK_NONEMPTY = sys::IORING_CQE_F_SOCK_NONEMPTY;
328+
329+
/// Set for notification CQEs, as seen with the zero-copy
330+
/// networking send and receive support.
331+
const NOTIF = sys::IORING_CQE_F_NOTIF;
332+
333+
/// If set, the buffer ID set in the completion will get more
334+
/// completions. This means that the provided buffer has been
335+
/// partially consumed and there's more buffer space left, and
336+
/// hence the application should expect more completions with
337+
/// this buffer ID. Each completion will continue where the
338+
/// previous one left off. This can only happen if the provided
339+
/// buffer ring has been setup with IOU_PBUF_RING_INC to allow
340+
/// for incremental / partial consumption of buffers.
341+
const BUF_MORE = sys::IORING_CQE_F_BUF_MORE;
342+
}
343+
);
344+
298345
/// Return whether the buffer will be reused by future CQE completions
299346
///
300347
/// This corresponds to the `IORING_CQE_BUF_MORE` flag, and it signals to
301348
/// the consumer that it should expect further completions involging the
302349
/// related buffer ID when the registered buffer ring was setup with
303350
/// the `IOU_PBUF_RING_INC` flag.
304-
pub fn buffer_more(flags: u32) -> bool {
305-
flags & sys::IORING_CQE_F_BUF_MORE != 0
351+
pub fn buffer_more(flags: CompletionFlags) -> bool {
352+
flags.contains(CompletionFlags::BUF_MORE)
306353
}
307354

308355
/// Return which dynamic buffer was used by this operation.
309356
///
310357
/// This corresponds to the `IORING_CQE_F_BUFFER` flag (and related bit-shifting),
311358
/// and it signals to the consumer which provided contains the result of this
312359
/// operation.
313-
pub fn buffer_select(flags: u32) -> Option<u16> {
314-
if flags & sys::IORING_CQE_F_BUFFER != 0 {
315-
let id = flags >> sys::IORING_CQE_BUFFER_SHIFT;
360+
pub fn buffer_select(flags: CompletionFlags) -> Option<u16> {
361+
if flags.contains(CompletionFlags::BUFFER) {
362+
let id = flags.bits() >> sys::IORING_CQE_BUFFER_SHIFT;
316363

317364
// FIXME
318365
//
@@ -329,8 +376,8 @@ pub fn buffer_select(flags: u32) -> Option<u16> {
329376
/// This corresponds to the `IORING_CQE_F_MORE` flag, and it signals to
330377
/// the consumer that it should expect further CQE entries after this one,
331378
/// still from the same original SQE request (e.g. for multishot operations).
332-
pub fn more(flags: u32) -> bool {
333-
flags & sys::IORING_CQE_F_MORE != 0
379+
pub fn more(flags: CompletionFlags) -> bool {
380+
flags.contains(CompletionFlags::MORE)
334381
}
335382

336383
/// Return whether socket has more data ready to read.
@@ -340,14 +387,14 @@ pub fn more(flags: u32) -> bool {
340387
///
341388
/// The io_uring documentation says recv, recv-multishot, recvmsg, and recvmsg-multishot
342389
/// can provide this bit in their respective CQE.
343-
pub fn sock_nonempty(flags: u32) -> bool {
344-
flags & sys::IORING_CQE_F_SOCK_NONEMPTY != 0
390+
pub fn sock_nonempty(flags: CompletionFlags) -> bool {
391+
flags.contains(CompletionFlags::SOCK_NONEMPTY)
345392
}
346393

347394
/// Returns whether this completion event is a notification.
348395
///
349396
/// This corresponds to the `IORING_CQE_F_NOTIF` flag,
350397
/// currently used by the [SendZc](crate::opcode::SendZc) operation.
351-
pub fn notif(flags: u32) -> bool {
352-
flags & sys::IORING_CQE_F_NOTIF != 0
398+
pub fn notif(flags: CompletionFlags) -> bool {
399+
flags.contains(CompletionFlags::NOTIF)
353400
}

0 commit comments

Comments
 (0)