From e52ac0b187bc822eb45d5589e1d9637a348e7a54 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Sat, 5 Mar 2016 18:49:42 +0100
Subject: [PATCH] event/MaskMonitor: new class to replace code in GlobalEvents
 and Idle

---
 Makefile.am               |  1 +
 src/GlobalEvents.cxx      | 18 +++++--------
 src/event/MaskMonitor.cxx | 36 ++++++++++++++++++++++++++
 src/event/MaskMonitor.hxx | 53 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 96 insertions(+), 12 deletions(-)
 create mode 100644 src/event/MaskMonitor.cxx
 create mode 100644 src/event/MaskMonitor.hxx

diff --git a/Makefile.am b/Makefile.am
index 3d393b5bf..77b631f40 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -490,6 +490,7 @@ libevent_a_SOURCES = \
 	src/event/TimeoutMonitor.hxx src/event/TimeoutMonitor.cxx \
 	src/event/IdleMonitor.hxx src/event/IdleMonitor.cxx \
 	src/event/DeferredMonitor.hxx src/event/DeferredMonitor.cxx \
+	src/event/MaskMonitor.hxx src/event/MaskMonitor.cxx \
 	src/event/SocketMonitor.cxx src/event/SocketMonitor.hxx \
 	src/event/BufferedSocket.cxx src/event/BufferedSocket.hxx \
 	src/event/FullyBufferedSocket.cxx src/event/FullyBufferedSocket.hxx \
diff --git a/src/GlobalEvents.cxx b/src/GlobalEvents.cxx
index 5d6c7b992..3cdafdd29 100644
--- a/src/GlobalEvents.cxx
+++ b/src/GlobalEvents.cxx
@@ -20,24 +20,21 @@
 #include "config.h"
 #include "GlobalEvents.hxx"
 #include "util/Manual.hxx"
-#include "event/DeferredMonitor.hxx"
-
-#include <atomic>
+#include "event/MaskMonitor.hxx"
 
 #include <assert.h>
 
 namespace GlobalEvents {
-	class Monitor final : public DeferredMonitor {
+	class Monitor final : public MaskMonitor {
 	public:
-		Monitor(EventLoop &_loop):DeferredMonitor(_loop) {}
+		explicit Monitor(EventLoop &_loop):MaskMonitor(_loop) {}
 
 	protected:
-		virtual void RunDeferred() override;
+		virtual void HandleMask(unsigned mask) override;
 	};
 
 	static Manual<Monitor> monitor;
 
-	static std::atomic_uint flags;
 	static Handler handlers[MAX];
 }
 
@@ -54,10 +51,8 @@ InvokeGlobalEvent(GlobalEvents::Event event)
 }
 
 void
-GlobalEvents::Monitor::RunDeferred()
+GlobalEvents::Monitor::HandleMask(unsigned f)
 {
-	const unsigned f = flags.exchange(0);
-
 	for (unsigned i = 0; i < MAX; ++i)
 		if (f & (1u << i))
 			/* invoke the event handler */
@@ -91,6 +86,5 @@ GlobalEvents::Emit(Event event)
 	assert((unsigned)event < MAX);
 
 	const unsigned mask = 1u << unsigned(event);
-	if (GlobalEvents::flags.fetch_or(mask) == 0)
-		monitor->Schedule();
+	monitor->OrMask(mask);
 }
diff --git a/src/event/MaskMonitor.cxx b/src/event/MaskMonitor.cxx
new file mode 100644
index 000000000..ff9cb9d47
--- /dev/null
+++ b/src/event/MaskMonitor.cxx
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003-2016 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+#include "MaskMonitor.hxx"
+
+void
+MaskMonitor::OrMask(unsigned new_mask)
+{
+	if (pending_mask.fetch_or(new_mask) == 0)
+		DeferredMonitor::Schedule();
+}
+
+void
+MaskMonitor::RunDeferred()
+{
+	const unsigned mask = pending_mask.exchange(0);
+	if (mask != 0)
+		HandleMask(mask);
+}
diff --git a/src/event/MaskMonitor.hxx b/src/event/MaskMonitor.hxx
new file mode 100644
index 000000000..db6803bbf
--- /dev/null
+++ b/src/event/MaskMonitor.hxx
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2003-2016 The Music Player Daemon Project
+ * http://www.musicpd.org
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef MPD_EVENT_MASK_MONITOR_HXX
+#define MPD_EVENT_MASK_MONITOR_HXX
+
+#include "check.h"
+#include "DeferredMonitor.hxx"
+
+#include <atomic>
+
+/**
+ * Manage a bit mask of events that have occurred.  Every time the
+ * mask becomes non-zero, OnMask() is called in #EventLoop's thread.
+ *
+ * This class is thread-safe.
+ */
+class MaskMonitor : DeferredMonitor {
+	std::atomic_uint pending_mask;
+
+public:
+	explicit MaskMonitor(EventLoop &_loop)
+		:DeferredMonitor(_loop), pending_mask(0) {}
+
+	using DeferredMonitor::GetEventLoop;
+	using DeferredMonitor::Cancel;
+
+	void OrMask(unsigned new_mask);
+
+protected:
+	virtual void HandleMask(unsigned mask) = 0;
+
+	/* virtual methode from class DeferredMonitor */
+	void RunDeferred() override;
+};
+
+#endif
-- 
2.24.1