diff options
| author | Stefan Boberg <[email protected]> | 2025-10-29 09:35:25 +0100 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2025-10-29 09:35:25 +0100 |
| commit | 2e293bbbf17639471d6d570212a09d097801da66 (patch) | |
| tree | 1eb3d7e53952aee2ec8b3a2a43b839f3594de392 /src | |
| parent | fix --zentrace=no compile errors (#616) (diff) | |
| download | zen-2e293bbbf17639471d6d570212a09d097801da66.tar.xz zen-2e293bbbf17639471d6d570212a09d097801da66.zip | |
fix for Latch race (#617)
Because the counter is decreased in `CountDown()` and subsequently checked against zero to determine if the completion event should be set:
`Latch::Wait` checks the counter against zero on entry and would exit early, before waiting on the completion event. This could then lead to the `Latch` instance being torn down before the `CountDown()` does a `Set()` which could then lead to unexpected and unwanted things happening.
Diffstat (limited to 'src')
| -rw-r--r-- | src/zencore/include/zencore/thread.h | 32 | ||||
| -rw-r--r-- | src/zencore/thread.cpp | 16 |
2 files changed, 19 insertions, 29 deletions
diff --git a/src/zencore/include/zencore/thread.h b/src/zencore/include/zencore/thread.h index 11ef01a35..9fe6dfb9b 100644 --- a/src/zencore/include/zencore/thread.h +++ b/src/zencore/include/zencore/thread.h @@ -103,16 +103,12 @@ public: ZENCORE_API Event(); ZENCORE_API ~Event(); - Event(Event&& Rhs) noexcept : m_EventHandle(Rhs.m_EventHandle) { Rhs.m_EventHandle = nullptr; } + Event(Event&& Rhs) noexcept : m_EventHandle(Rhs.m_EventHandle.load()) { Rhs.m_EventHandle = nullptr; } Event(const Event& Rhs) = delete; Event& operator=(const Event& Rhs) = delete; - inline Event& operator=(Event&& Rhs) noexcept - { - std::swap(m_EventHandle, Rhs.m_EventHandle); - return *this; - } + Event& operator=(Event&& Rhs) = delete; ZENCORE_API void Set(); ZENCORE_API void Reset(); @@ -126,7 +122,7 @@ public: protected: explicit Event(void* EventHandle) : m_EventHandle(EventHandle) {} - void* m_EventHandle = nullptr; + std::atomic<void*> m_EventHandle{nullptr}; }; /** Basic abstraction of an IPC mechanism (aka 'binary semaphore') @@ -141,16 +137,18 @@ public: ZENCORE_API std::error_code Set(); ZENCORE_API bool Wait(int TimeoutMs = -1); - NamedEvent(NamedEvent&& Rhs) noexcept : m_EventHandle(Rhs.m_EventHandle) { Rhs.m_EventHandle = nullptr; } + NamedEvent(NamedEvent&& Rhs) noexcept : m_EventHandle(Rhs.m_EventHandle.load()) { Rhs.m_EventHandle = nullptr; } - inline NamedEvent& operator=(NamedEvent&& Rhs) noexcept + NamedEvent& operator=(NamedEvent&& Rhs) { - std::swap(m_EventHandle, Rhs.m_EventHandle); + Close(); + m_EventHandle = Rhs.m_EventHandle.load(); + Rhs.m_EventHandle = nullptr; return *this; - } + }; protected: - void* m_EventHandle = nullptr; + std::atomic<void*> m_EventHandle{nullptr}; private: NamedEvent(const NamedEvent& Rhs) = delete; @@ -201,15 +199,7 @@ public: ZEN_ASSERT(Old > 0); } - bool Wait(int TimeoutMs = -1) - { - std::ptrdiff_t Old = Counter.load(); - if (Old == 0) - { - return true; - } - return Complete.Wait(TimeoutMs); - } + bool Wait(int TimeoutMs = -1) { return Complete.Wait(TimeoutMs); } private: std::atomic_ptrdiff_t Counter; diff --git a/src/zencore/thread.cpp b/src/zencore/thread.cpp index 7bd21a229..9e3486e49 100644 --- a/src/zencore/thread.cpp +++ b/src/zencore/thread.cpp @@ -200,7 +200,7 @@ Event::Set() SetEvent(m_EventHandle); #else std::atomic_thread_fence(std::memory_order_acquire); - auto* Inner = (EventInner*)m_EventHandle; + auto* Inner = (EventInner*)m_EventHandle.load(); { std::unique_lock Lock(Inner->Mutex); Inner->bSet.store(true); @@ -216,7 +216,7 @@ Event::Reset() ResetEvent(m_EventHandle); #else std::atomic_thread_fence(std::memory_order_acquire); - auto* Inner = (EventInner*)m_EventHandle; + auto* Inner = (EventInner*)m_EventHandle.load(); { std::unique_lock Lock(Inner->Mutex); Inner->bSet.store(false); @@ -232,7 +232,7 @@ Event::Close() m_EventHandle = nullptr; #else std::atomic_thread_fence(std::memory_order_acquire); - auto* Inner = (EventInner*)m_EventHandle; + auto* Inner = (EventInner*)m_EventHandle.load(); { std::unique_lock Lock(Inner->Mutex); Inner->bSet.store(true); @@ -260,7 +260,7 @@ Event::Wait(int TimeoutMs) return (Result == WAIT_OBJECT_0); #else std::atomic_thread_fence(std::memory_order_acquire); - auto* Inner = reinterpret_cast<EventInner*>(m_EventHandle); + auto* Inner = reinterpret_cast<EventInner*>(m_EventHandle.load()); if (Inner->bSet.load()) { @@ -372,7 +372,7 @@ NamedEvent::Close() #if ZEN_PLATFORM_WINDOWS CloseHandle(m_EventHandle); #elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC - int Fd = int(intptr_t(m_EventHandle) & 0xffff'ffff); + int Fd = int(intptr_t(m_EventHandle.load()) & 0xffff'ffff); if (flock(Fd, LOCK_EX | LOCK_NB) == 0) { @@ -390,7 +390,7 @@ NamedEvent::Close() flock(Fd, LOCK_UN | LOCK_NB); close(Fd); - int Sem = int(intptr_t(m_EventHandle) >> 32); + int Sem = int(intptr_t(m_EventHandle.load()) >> 32); semctl(Sem, 0, IPC_RMID); } #endif @@ -408,7 +408,7 @@ NamedEvent::Set() return MakeErrorCodeFromLastError(); } #elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC - int Sem = int(intptr_t(m_EventHandle) >> 32); + int Sem = int(intptr_t(m_EventHandle.load()) >> 32); if (semctl(Sem, 0, SETVAL, 0) == -1) { return MakeErrorCodeFromLastError(); @@ -434,7 +434,7 @@ NamedEvent::Wait(int TimeoutMs) return (Result == WAIT_OBJECT_0); #elif ZEN_PLATFORM_LINUX || ZEN_PLATFORM_MAC - int Sem = int(intptr_t(m_EventHandle) >> 32); + int Sem = int(intptr_t(m_EventHandle.load()) >> 32); int Result; struct sembuf SemOp = {}; |