From e014d319724d398048d0de38e558c2aca74c7a70 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max.kellermann@ionos.com>
Date: Sat, 1 Feb 2025 20:50:14 +0100
Subject: [PATCH] io/uring/Ring: add io_uring_submit_and_wait_timeout() wrapper

---
 src/io/uring/Queue.cxx | 11 +++++++++++
 src/io/uring/Queue.hxx |  2 ++
 src/io/uring/Ring.cxx  | 15 +++++++++++++++
 src/io/uring/Ring.hxx  | 10 ++++++++++
 4 files changed, 38 insertions(+)

diff --git a/src/io/uring/Queue.cxx b/src/io/uring/Queue.cxx
index 066797354..9b4cd050d 100644
--- a/src/io/uring/Queue.cxx
+++ b/src/io/uring/Queue.cxx
@@ -90,4 +90,15 @@ Queue::WaitDispatchOneCompletion()
 	return true;
 }
 
+bool
+Queue::SubmitAndWaitDispatchOneCompletion(struct __kernel_timespec &timeout)
+{
+	auto *cqe = ring.SubmitAndWaitCompletion(timeout);
+	if (cqe == nullptr)
+		return false;
+
+	DispatchOneCompletion(*cqe);
+	return true;
+}
+
 } // namespace Uring
diff --git a/src/io/uring/Queue.hxx b/src/io/uring/Queue.hxx
index 6f88ee516..02d4fbdff 100644
--- a/src/io/uring/Queue.hxx
+++ b/src/io/uring/Queue.hxx
@@ -101,6 +101,8 @@ public:
 		while (WaitDispatchOneCompletion()) {}
 	}
 
+	bool SubmitAndWaitDispatchOneCompletion(struct __kernel_timespec &timeout);
+
 private:
 	void DispatchOneCompletion(struct io_uring_cqe &cqe) noexcept;
 };
diff --git a/src/io/uring/Ring.cxx b/src/io/uring/Ring.cxx
index 222b24363..cd7c7721d 100644
--- a/src/io/uring/Ring.cxx
+++ b/src/io/uring/Ring.cxx
@@ -60,6 +60,21 @@ Ring::WaitCompletion()
 	return cqe;
 }
 
+struct io_uring_cqe *
+Ring::SubmitAndWaitCompletion(struct __kernel_timespec &timeout)
+{
+	struct io_uring_cqe *cqe;
+	if (int error = io_uring_submit_and_wait_timeout(&ring, &cqe, 1, &timeout, nullptr);
+	    error < 0) {
+		if (error == -ETIME || error == -EAGAIN)
+			return nullptr;
+
+		throw MakeErrno(-error, "io_uring_submit_and_wait_timeout() failed");
+	}
+
+	return cqe;
+}
+
 struct io_uring_cqe *
 Ring::PeekCompletion()
 {
diff --git a/src/io/uring/Ring.hxx b/src/io/uring/Ring.hxx
index 8c1128995..987c9fffd 100644
--- a/src/io/uring/Ring.hxx
+++ b/src/io/uring/Ring.hxx
@@ -101,6 +101,16 @@ public:
 	 */
 	struct io_uring_cqe *WaitCompletion();
 
+	/**
+	 * Submit requests and wait for one completion (or a timeout).
+	 * Wrapper for io_uring_submit_and_wait_timeout().
+	 *
+	 * Throws on error.
+	 *
+	 * @return a completion queue entry or nullptr on EAGAIN/ETIME
+	 */
+	struct io_uring_cqe *SubmitAndWaitCompletion(struct __kernel_timespec &timeout);
+
 	/**
 	 * Peek one completion (non-blocking).
 	 *