From ea2ced6b9f9f5b084a3db8a3b3d1a6f62a3d14d3 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max.kellermann@gmail.com>
Date: Wed, 29 Jan 2025 18:18:42 +0100
Subject: [PATCH] event/UringManager: replace with new Uring::Manager class

From https://github.com/CM4all/libcommon - the new class is mostly
identical, and I want to maintain only one of them.
---
 src/event/Loop.cxx          |  2 +-
 src/event/UringManager.cxx  | 39 -----------------------
 src/event/UringManager.hxx  | 29 -----------------
 src/event/meson.build       |  2 +-
 src/event/uring/Manager.cxx | 62 +++++++++++++++++++++++++++++++++++++
 src/event/uring/Manager.hxx | 53 +++++++++++++++++++++++++++++++
 6 files changed, 117 insertions(+), 70 deletions(-)
 delete mode 100644 src/event/UringManager.cxx
 delete mode 100644 src/event/UringManager.hxx
 create mode 100644 src/event/uring/Manager.cxx
 create mode 100644 src/event/uring/Manager.hxx

diff --git a/src/event/Loop.cxx b/src/event/Loop.cxx
index 6d3cf7c2b..e89da24f4 100644
--- a/src/event/Loop.cxx
+++ b/src/event/Loop.cxx
@@ -12,7 +12,7 @@
 #endif
 
 #ifdef HAVE_URING
-#include "UringManager.hxx"
+#include "uring/Manager.hxx"
 #include "util/PrintException.hxx"
 #include <stdio.h>
 #endif
diff --git a/src/event/UringManager.cxx b/src/event/UringManager.cxx
deleted file mode 100644
index 1baaf500e..000000000
--- a/src/event/UringManager.cxx
+++ /dev/null
@@ -1,39 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-// Copyright The Music Player Daemon Project
-
-#include "UringManager.hxx"
-#include "util/PrintException.hxx"
-
-namespace Uring {
-
-Manager::Manager(EventLoop &event_loop,
-		 unsigned entries, unsigned flags)
-	:Queue(entries, flags),
-	 event(event_loop, BIND_THIS_METHOD(OnSocketReady),
-	       GetFileDescriptor()),
-	 idle_event(event_loop, BIND_THIS_METHOD(OnIdle))
-{
-	event.ScheduleRead();
-}
-
-void
-Manager::OnSocketReady(unsigned) noexcept
-{
-	try {
-		DispatchCompletions();
-	} catch (...) {
-		PrintException(std::current_exception());
-	}
-}
-
-void
-Manager::OnIdle() noexcept
-{
-	try {
-		Queue::Submit();
-	} catch (...) {
-		PrintException(std::current_exception());
-	}
-}
-
-} // namespace Uring
diff --git a/src/event/UringManager.hxx b/src/event/UringManager.hxx
deleted file mode 100644
index 4c4fc20bb..000000000
--- a/src/event/UringManager.hxx
+++ /dev/null
@@ -1,29 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-// Copyright The Music Player Daemon Project
-
-#pragma once
-
-#include "PipeEvent.hxx"
-#include "IdleEvent.hxx"
-#include "io/uring/Queue.hxx"
-
-namespace Uring {
-
-class Manager final : public Queue {
-	PipeEvent event;
-	IdleEvent idle_event;
-
-public:
-	explicit Manager(EventLoop &event_loop,
-			 unsigned entries=1024, unsigned flags=0);
-
-	void Submit() override {
-		idle_event.Schedule();
-	}
-
-private:
-	void OnSocketReady(unsigned flags) noexcept;
-	void OnIdle() noexcept;
-};
-
-} // namespace Uring
diff --git a/src/event/meson.build b/src/event/meson.build
index b4d20f864..dc96289fe 100644
--- a/src/event/meson.build
+++ b/src/event/meson.build
@@ -8,7 +8,7 @@ configure_file(output: 'Features.h', configuration: event_features)
 event_sources = []
 
 if uring_dep.found()
-  event_sources += 'UringManager.cxx'
+  event_sources += 'uring/Manager.cxx'
 endif
 
 if is_windows
diff --git a/src/event/uring/Manager.cxx b/src/event/uring/Manager.cxx
new file mode 100644
index 000000000..9f6353140
--- /dev/null
+++ b/src/event/uring/Manager.cxx
@@ -0,0 +1,62 @@
+// SPDX-License-Identifier: BSD-2-Clause
+// Copyright CM4all GmbH
+// author: Max Kellermann <mk@cm4all.com>
+
+#include "Manager.hxx"
+#include "util/PrintException.hxx"
+
+namespace Uring {
+
+Manager::Manager(EventLoop &event_loop,
+		 unsigned entries, unsigned flags)
+	:Queue(entries, flags),
+	 event(event_loop, BIND_THIS_METHOD(OnReady), GetFileDescriptor())
+{
+	event.ScheduleRead();
+}
+
+Manager::Manager(EventLoop &event_loop,
+		 unsigned entries, struct io_uring_params &params)
+	:Queue(entries, params),
+	 event(event_loop, BIND_THIS_METHOD(OnReady), GetFileDescriptor())
+{
+	event.ScheduleRead();
+}
+
+void
+Manager::Submit()
+{
+	/* defer in "idle" mode to allow accumulation of more
+	   events */
+	defer_submit_event.ScheduleIdle();
+}
+
+void
+Manager::DispatchCompletions() noexcept
+{
+	try {
+		Queue::DispatchCompletions();
+	} catch (...) {
+		PrintException(std::current_exception());
+	}
+
+	CheckVolatileEvent();
+}
+
+inline void
+Manager::OnReady(unsigned) noexcept
+{
+	DispatchCompletions();
+}
+
+void
+Manager::DeferredSubmit() noexcept
+{
+	try {
+		Queue::Submit();
+	} catch (...) {
+		PrintException(std::current_exception());
+	}
+}
+
+} // namespace Uring
diff --git a/src/event/uring/Manager.hxx b/src/event/uring/Manager.hxx
new file mode 100644
index 000000000..b03eafa30
--- /dev/null
+++ b/src/event/uring/Manager.hxx
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: BSD-2-Clause
+// Copyright CM4all GmbH
+// author: Max Kellermann <mk@cm4all.com>
+
+#pragma once
+
+#include "io/uring/Queue.hxx"
+#include "event/DeferEvent.hxx"
+#include "event/PipeEvent.hxx"
+
+namespace Uring {
+
+class Manager final : public Queue {
+	PipeEvent event;
+
+	/**
+	 * Responsible for invoking Queue::Submit() only once per
+	 * #EventLoop iteration.
+	 */
+	DeferEvent defer_submit_event{GetEventLoop(), BIND_THIS_METHOD(DeferredSubmit)};
+
+	bool volatile_event = false;
+
+public:
+	explicit Manager(EventLoop &event_loop,
+			 unsigned entries=1024, unsigned flags=0);
+	explicit Manager(EventLoop &event_loop,
+			 unsigned entries, struct io_uring_params &params);
+
+	EventLoop &GetEventLoop() const noexcept {
+		return event.GetEventLoop();
+	}
+
+	void SetVolatile() noexcept {
+		volatile_event = true;
+		CheckVolatileEvent();
+	}
+
+	// virtual methods from class Uring::Queue
+	void Submit() override;
+
+private:
+	void CheckVolatileEvent() noexcept {
+		if (volatile_event && !HasPending())
+			event.Cancel();
+	}
+
+	void DispatchCompletions() noexcept;
+	void OnReady(unsigned events) noexcept;
+	void DeferredSubmit() noexcept;
+};
+
+} // namespace Uring