diff foosdk/sdk/foobar2000/helpers/readWriteLock.h @ 1:20d02a178406 default tip

*: check in everything else yay
author Paper <paper@tflc.us>
date Mon, 05 Jan 2026 02:15:46 -0500
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/foosdk/sdk/foobar2000/helpers/readWriteLock.h	Mon Jan 05 02:15:46 2026 -0500
@@ -0,0 +1,77 @@
+#pragma once
+
+
+namespace fb2k {
+	//! fb2k::readWriteLock: abortable readWriteLock, allowing multiple concurrent readers while not writing, or one writer while not reading. \n
+	//! Safe to release locks in different threads than obtained, contrary to system object such as SRW locks.
+	class readWriteLock {
+		pfc::mutex m_guard;
+		size_t m_readers = 0, m_writers = 0;
+		typedef std::shared_ptr < pfc::event> eventRef_t;
+		eventRef_t m_currentEvent;
+	public:
+
+		void shutdown() {
+			for (;;) {
+				eventRef_t waitFor;
+				{
+					PFC_INSYNC(m_guard);
+					if (m_readers == 0 && m_writers == 0) return;
+					PFC_ASSERT(m_currentEvent);
+					waitFor = m_currentEvent;
+				}
+				waitFor->wait_for(-1);
+			}
+		}
+
+		service_ptr beginRead(abort_callback& a) {
+			for (;;) {
+				a.check();
+				eventRef_t waitFor;
+				{
+					PFC_INSYNC(m_guard);
+					if (m_writers == 0) {
+						if (!m_currentEvent) m_currentEvent = std::make_shared<pfc::event>();
+						++m_readers;
+						return fb2k::callOnRelease([this] {
+							PFC_INSYNC(m_guard);
+							PFC_ASSERT(m_currentEvent);
+							PFC_ASSERT(m_readers > 0 && m_writers == 0);
+							if (--m_readers == 0) {
+								m_currentEvent->set_state(true); m_currentEvent = nullptr;
+							}
+						});
+					}
+					PFC_ASSERT(m_currentEvent);
+					waitFor = m_currentEvent;
+				}
+				a.waitForEvent(*waitFor);
+			}
+		}
+		service_ptr beginWrite(abort_callback& a) {
+			for (;;) {
+				a.check();
+				eventRef_t waitFor;
+				{
+					PFC_INSYNC(m_guard);
+					if (m_readers == 0 && m_writers == 0) {
+						m_currentEvent = std::make_shared<pfc::event>();
+						++m_writers;
+						return fb2k::callOnRelease([this] {
+							PFC_INSYNC(m_guard);
+							PFC_ASSERT(m_currentEvent);
+							PFC_ASSERT(m_readers == 0 && m_writers > 0);
+							if (--m_writers == 0) {
+								m_currentEvent->set_state(true); m_currentEvent = nullptr;
+							}
+						});
+					}
+					PFC_ASSERT(m_currentEvent);
+					waitFor = m_currentEvent;
+				}
+				a.waitForEvent(*waitFor);
+			}
+		}
+
+	};
+}