io_uring_prep_recv(3)
β¨ io_uring_prep_recv β¨
okay bestie, gather round, we're doing liburing today π this one's io_uring_prep_recv β the prep helper from liburing that gets your async receive requests all cute and queued up.
πΈ SYNOPSIS πΈ
#include <liburing.h>
void io_uring_prep_recv(struct io_uring_sqe *sqe,
int sockfd,
void *buf,
size_t len,
int flags);
void io_uring_prep_recv_multishot(struct io_uring_sqe *sqe,
int sockfd,
void *buf,
size_t len,
int flags);
π DESCRIPTION π
So io_uring_prep_recv(3) literally prepares a recv request. That's it, that's the job. It sets up the submission queue entry sqe so it'll use the file descriptor sockfd to start receiving data into the destination buffer buf (size len, obviously) with the modifier flags flags. slay.
This is preparing an async recv(2) request β so if you want the deets on what all those arguments actually mean, go read that man page, because this helper is just the glow-up wrapper around it. β¨
π¦ the multishot version π¦
io_uring_prep_recv_multishot is the main character version: your app issues one single receive request and it keeps posting a CQE whenever data shows up. Iconic. But there are rules, no cap:
- the length must be 0 (
0, zero, nada) - the
IOSQE_BUFFER_SELECTflag must be set - the
MSG_WAITALLflag must not be set
Because of that, every single CQE grabs a buffer out of a provided buffer pool for the receive. And listen β you should check the flags on each CQE, no matter what its result is. If a posted CQE doesn't have the IORING_CQE_F_MORE flag set, that means the multishot receive is done, and if you still wanna receive data from that socket you have to issue a brand new request. Fr fr. Multishot variants are available since kernel 6.0. π
π₯ internal modifier flags π₯
After you call this function, io_uring might set extra internal modifier flags in the SQE ioprio field. These are the supported ones:
IORING_RECVSEND_POLL_FIRSTβ if this is set, io_uring will assume the socket is currently empty and that trying to receive data will fail. In that case, io_uring arms internal poll and triggers a receive of the data once the socket actually has data to be read. The initial receive attempt is kinda wasteful when you already expect the socket to be empty, so setting this flag skips that first attempt and goes straight to arming poll. And if poll does say data is ready to be received, the operation proceeds. You can use this with the CQEIORING_CQE_F_SOCK_NONEMPTYflag, which io_uring sets on CQEs after arecv(2)orrecvmsg(2)operation. If that's set, the socket still had data to be read after the operation finished. Both these flags are available since 5.19. πIORING_RECVSEND_BUNDLEβ if this is set and provided buffers are used withIOSQE_BUFFER_SELECT, the receive operation will try to fill multiple buffers instead of just picking one single buffer to fill. To receive multiple buffers in one receive, the buffer group ID set in the SQE must be of the ring provided type. If it's set, the CQEresfield tells you the total number of bytes received, and the buffer ID returned in the CQE flags field indicates the first buffer in the receive operation. Your app has to process the indicated initial buffer ID and keep going until allresbytes have been seen, so you know which one is the last buffer in the receive. The buffers consumed are contiguous from the initial buffer, in the order they appear in the buffer ring. Now β the CQE struct does not contain the position of the buffer in the buffer ring, so to identify the buffers contained in the bundle, it's advised to maintain the cached head index per buffer ring. Thatuint16_tindex is the position of the next buffer to be consumed within the ring, and when a receive operation completes, the cached head index should be incremented accordingly. Receiving in bundles can improve performance when more than one chunk of data is available to receive, because it eliminates redundant round trips through the networking stack. π Receive bundles can be used by both single shot and multishot receive operations. Note that internally, bundles rely on the networking stack passing back how much data is left in the socket after the initial receive β which means the initial receive may contain fewer buffers than what's available, with the followup receive(s) containing more buffers. Available since 6.10. π«Ά
π RETURN VALUE π
None. That's it. Nothing. Zip. Nada. void energy. π
π ERRORS π
The CQE res field will contain the result of the operation. Go check the related man page for the possible values, bestie.
not me explaining errno again β where synchronous system calls return-1on failure and seterrnoto the actual error value, io_uring never useserrno. Instead it returns the negated errno directly in the CQEresfield. Write that down. π
π SEE ALSO π
that's the whole page babes, you ate it π go forth and receive your data asynchronously, the vibes are immaculate β¨π
signing off from liburing-2.2, dated March 12, 2022 β stay slaying, bestie ππ¦
π¦ where this page comes from
- alpine 3.23: liburing-doc 2.12-r0 Β· LGPL-2.1-or-later OR MIT
- alpine 3.24: liburing-doc 2.14-r0 Β· LGPL-2.1-or-later OR MIT
- centos-stream 10: liburing-devel 2.12-1.el10 Β· (GPLv2 with exceptions and LGPLv2+) or MIT
- centos-stream 9: liburing-devel 2.12-1.el9 Β· (GPLv2 with exceptions and LGPLv2+) or MIT
- centos-stream 9: liburing-devel 2.12-1.el9 Β· (GPLv2 with exceptions and LGPLv2+) or MIT
- fedora 44: liburing-devel 2.13-2.fc44 Β· (GPL-2.0-only WITH Linux-syscall-note OR MIT) AND (LGPL-2.0-or-later OR MIT)
- fedora 44: liburing-devel 2.13-2.fc44 Β· (GPL-2.0-only WITH Linux-syscall-note OR MIT) AND (LGPL-2.0-or-later OR MIT)
- nixpkgs unstable: liburing 2.14
- ubuntu resolute: liburing-dev 2.14-1
- π the page's license: LGPL-2.0-or-later
- Copyright (C) 2022 Jens Axboe <axboe@kernel.dk>
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms