From d25742fe8bb475b6bdf03e80cc09350e9c3d3b5a Mon Sep 17 00:00:00 2001 From: Jordan Woyak Date: Mon, 17 Nov 2025 02:51:26 -0600 Subject: [PATCH] Common: Introduce a OneShotEvent class. Unlike Common::Event, OneShotEvent is safe in situations when being immediately destructed. --- Source/Core/Common/CMakeLists.txt | 1 + Source/Core/Common/OneShotEvent.h | 55 +++++++++++++++++++++++++++++++ Source/Core/DolphinLib.props | 1 + 3 files changed, 57 insertions(+) create mode 100644 Source/Core/Common/OneShotEvent.h diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index e833893a9de..2447d1ed401 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 00000000000..312848ed918 --- /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 +#include +#include + +#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 + bool WaitFor(const std::chrono::duration& 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 +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>; + NonOwningSetOnDeletePtr m_ptr; +}; + +} // namespace Common diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index 3cfac5838c4..f4a9c04a926 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -149,6 +149,7 @@ +