From f4cdd7d3fe004d1315bd367fefbc189aa92511de Mon Sep 17 00:00:00 2001 From: Kefu Chai Date: Mon, 15 Jun 2026 20:06:14 +0800 Subject: [PATCH] man: document that send/recv can see -EAGAIN without MSG_DONTWAIT The send/recv prep man pages imply -EAGAIN is only expected when the application sets MSG_DONTWAIT. In practice io_uring can also complete a request that did not set MSG_DONTWAIT with -EAGAIN: when it cannot make progress, it stops retrying rather than waiting indefinitely (see kernel commit c16bda37594f "io_uring/poll: allow some retries for poll triggering spuriously", which bounds the retry attempts). Applications submitting blocking-style socket sends/recvs (no MSG_DONTWAIT) can therefore observe -EAGAIN under load and must treat it as transient and reissue. Note this in the ERRORS section of the send, sendmsg, recv and recvmsg prep pages. Signed-off-by: Kefu Chai --- man/io_uring_prep_recv.3 | 17 ++++++++++++++++- man/io_uring_prep_recvmsg.3 | 19 ++++++++++++++++++- man/io_uring_prep_send.3 | 17 ++++++++++++++++- man/io_uring_prep_sendmsg.3 | 16 ++++++++++++++++ 4 files changed, 66 insertions(+), 3 deletions(-) diff --git a/man/io_uring_prep_recv.3 b/man/io_uring_prep_recv.3 index 509b35523..c718ae425 100644 --- a/man/io_uring_prep_recv.3 +++ b/man/io_uring_prep_recv.3 @@ -135,7 +135,22 @@ Instead it returns the negated .I errno directly in the CQE .I res -field. +field. Some common error cases are: +.TP +.B -EAGAIN +The operation would have blocked. io_uring normally arms internal poll and +retries the request once the socket is ready, so this result is the expected +outcome when +.B MSG_DONTWAIT +was set in the +.I flags +argument. It can also occur without +.B MSG_DONTWAIT +when the request cannot make progress and io_uring stops retrying rather than +waiting indefinitely. Handle +.B -EAGAIN +as a transient condition and reissue the request. +.P .SH NOTES Despite accepting a size_t number of bytes, these functions can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface). diff --git a/man/io_uring_prep_recvmsg.3 b/man/io_uring_prep_recvmsg.3 index 74a0c9ef3..9f048beb8 100644 --- a/man/io_uring_prep_recvmsg.3 +++ b/man/io_uring_prep_recvmsg.3 @@ -107,7 +107,24 @@ Instead it returns the negated .I errno directly in the CQE .I res -field. +field. Some common error cases are: +.TP +.B -EAGAIN +The operation would have blocked. io_uring normally arms internal poll and +retries the request once the socket is ready, so this result is the expected +outcome when +.B MSG_DONTWAIT +was set in the +.I msg_flags +of the +.I msghdr +argument. It can also occur without +.B MSG_DONTWAIT +when the request cannot make progress and io_uring stops retrying rather than +waiting indefinitely. Handle +.B -EAGAIN +as a transient condition and reissue the request. +.P .SH NOTES As with any request that passes in data in a struct, that data must remain valid until the request has been successfully submitted. It need not remain diff --git a/man/io_uring_prep_send.3 b/man/io_uring_prep_send.3 index f4470528e..794671258 100644 --- a/man/io_uring_prep_send.3 +++ b/man/io_uring_prep_send.3 @@ -184,7 +184,22 @@ Instead it returns the negated .I errno directly in the CQE .I res -field. +field. Some common error cases are: +.TP +.B -EAGAIN +The operation would have blocked. io_uring normally arms internal poll and +retries the request once the socket is ready, so this result is the expected +outcome when +.B MSG_DONTWAIT +was set in the +.I flags +argument. It can also occur without +.B MSG_DONTWAIT +when the request cannot make progress and io_uring stops retrying rather than +waiting indefinitely. Handle +.B -EAGAIN +as a transient condition and reissue the request. +.P .SH NOTES Despite accepting a size_t number of bytes, these functions can transfer at most INT_MAX bytes per call (the maximum for the underlying syscall interface). diff --git a/man/io_uring_prep_sendmsg.3 b/man/io_uring_prep_sendmsg.3 index 7bb7a5341..51d6ec17b 100644 --- a/man/io_uring_prep_sendmsg.3 +++ b/man/io_uring_prep_sendmsg.3 @@ -105,6 +105,22 @@ directly in the CQE .I res field. Some common error cases are: .TP +.B -EAGAIN +The operation would have blocked. io_uring normally arms internal poll and +retries the request once the socket is ready, so this result is the expected +outcome when +.B MSG_DONTWAIT +was set in the +.I msg_flags +of the +.I msghdr +argument. It can also occur without +.B MSG_DONTWAIT +when the request cannot make progress and io_uring stops retrying rather than +waiting indefinitely. Handle +.B -EAGAIN +as a transient condition and reissue the request. +.TP .B -ENOMEM The .BR ulimit (1)