aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStefan Boberg <[email protected]>2025-10-29 09:35:25 +0100
committerGitHub Enterprise <[email protected]>2025-10-29 09:35:25 +0100
commit2e293bbbf17639471d6d570212a09d097801da66 (patch)
tree1eb3d7e53952aee2ec8b3a2a43b839f3594de392 /src
parentfix --zentrace=no compile errors (#616) (diff)
downloadzen-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.h32
-rw-r--r--src/zencore/thread.cpp16
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 = {};