summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJordan Woyak <jordan.woyak@gmail.com>2025-11-17 02:51:26 -0600
committerJordan Woyak <jordan.woyak@gmail.com>2025-11-18 14:19:21 -0600
commitd25742fe8bb475b6bdf03e80cc09350e9c3d3b5a (patch)
tree7fe34239450c159f7de8140c19e3821dde104127
parent605cc579a436d6028cc5cbe4a3f720d0ad35e24f (diff)
Common: Introduce a OneShotEvent class. Unlike Common::Event, OneShotEvent is safe in situations when being immediately destructed.
-rw-r--r--Source/Core/Common/CMakeLists.txt1
-rw-r--r--Source/Core/Common/OneShotEvent.h55
-rw-r--r--Source/Core/DolphinLib.props1
3 files changed, 57 insertions, 0 deletions
diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt
index e833893a9d..2447d1ed40 100644
--- a/Source/Core/Common/CMakeLists.txt
+++ b/Source/Core/Common/CMakeLists.txt
@@ -118,6 +118,7 @@ add_library(common
NandPaths.h
Network.cpp
Network.h
+ OneShotEvent.h
PcapFile.cpp
PcapFile.h
Profiler.cpp
diff --git a/Source/Core/Common/OneShotEvent.h b/Source/Core/Common/OneShotEvent.h
new file mode 100644
index 0000000000..312848ed91
--- /dev/null
+++ b/Source/Core/Common/OneShotEvent.h
@@ -0,0 +1,55 @@
+// Copyright 2025 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <chrono>
+#include <memory>
+#include <semaphore>
+
+#include "Common/Functional.h"
+
+namespace Common
+{
+
+// A one-time-use single-producer single-consumer thread synchronization class.
+// Safe when `Set` will cause a `Wait`ing thread to immediately destruct the event itself.
+class OneShotEvent
+{
+public:
+ // One thread should call Set() exactly once.
+ void Set() { m_semaphore.release(1); }
+
+ // One thread may call Wait() once or WaitFor() until it returns true.
+
+ void Wait() { m_semaphore.acquire(); }
+
+ template <typename Rep, typename Period>
+ bool WaitFor(const std::chrono::duration<Rep, Period>& rel_time)
+ {
+ return m_semaphore.try_acquire_for(rel_time);
+ }
+
+private:
+ std::binary_semaphore m_semaphore{0};
+};
+
+// Invokes Set() on the given object upon destruction.
+template <typename EventType>
+class ScopedSetter
+{
+public:
+ ScopedSetter() = default;
+ explicit ScopedSetter(EventType* ptr) : m_ptr{ptr} {}
+
+ // Forgets the object without invoking Set().
+ void Dismiss() { m_ptr.release(); }
+
+private:
+ // Leveraging unique_ptr conveniently makes this class move-only.
+ // It does no actual deletion, just calls Set().
+ using NonOwningSetOnDeletePtr = std::unique_ptr<EventType, InvokerOf<&EventType::Set>>;
+ NonOwningSetOnDeletePtr m_ptr;
+};
+
+} // namespace Common
diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props
index 3cfac5838c..f4a9c04a92 100644
--- a/Source/Core/DolphinLib.props
+++ b/Source/Core/DolphinLib.props
@@ -149,6 +149,7 @@
<ClInclude Include="Common\Mutex.h" />
<ClInclude Include="Common\NandPaths.h" />
<ClInclude Include="Common\Network.h" />
+ <ClInclude Include="Common\OneShotEvent.h" />
<ClInclude Include="Common\PcapFile.h" />
<ClInclude Include="Common\Profiler.h" />
<ClInclude Include="Common\Projection.h" />