From d71932a6ec3aabd2515e4eb94c0d88dc428a41f2 Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Mon, 4 Aug 2025 18:37:52 +0200 Subject: Don't set m_DispatchComplete in ParallelWork until after pending work countdown succeeds (#455) --- src/zenutil/parallelwork.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/zenutil/parallelwork.cpp') diff --git a/src/zenutil/parallelwork.cpp b/src/zenutil/parallelwork.cpp index aa806438b..1edca5050 100644 --- a/src/zenutil/parallelwork.cpp +++ b/src/zenutil/parallelwork.cpp @@ -33,6 +33,7 @@ ParallelWork::~ParallelWork() "ParallelWork disposed without explicit wait for completion, likely caused by an exception, waiting for dispatched threads " "to complete"); m_PendingWork.CountDown(); + m_DispatchComplete = true; } m_PendingWork.Wait(); ptrdiff_t RemainingWork = m_PendingWork.Remaining(); @@ -82,10 +83,9 @@ void ParallelWork::Wait(int32_t UpdateIntervalMS, UpdateCallback&& UpdateCallback) { ZEN_ASSERT(!m_DispatchComplete); - m_DispatchComplete = true; - ZEN_ASSERT(m_PendingWork.Remaining() > 0); m_PendingWork.CountDown(); + m_DispatchComplete = true; while (!m_PendingWork.Wait(UpdateIntervalMS)) { @@ -99,10 +99,10 @@ void ParallelWork::Wait() { ZEN_ASSERT(!m_DispatchComplete); - m_DispatchComplete = true; - ZEN_ASSERT(m_PendingWork.Remaining() > 0); m_PendingWork.CountDown(); + m_DispatchComplete = true; + m_PendingWork.Wait(); RethrowErrors(); -- cgit v1.2.3 From 3a2d008eb35ff3635c7336ac684873c0e315e5c2 Mon Sep 17 00:00:00 2001 From: Dan Engelbrecht Date: Wed, 6 Aug 2025 10:52:24 +0200 Subject: more details in parallel work when wait fails/destructor has inconsistent state (#457) --- src/zenutil/parallelwork.cpp | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) (limited to 'src/zenutil/parallelwork.cpp') diff --git a/src/zenutil/parallelwork.cpp b/src/zenutil/parallelwork.cpp index 1edca5050..a571d1d11 100644 --- a/src/zenutil/parallelwork.cpp +++ b/src/zenutil/parallelwork.cpp @@ -35,17 +35,19 @@ ParallelWork::~ParallelWork() m_PendingWork.CountDown(); m_DispatchComplete = true; } - m_PendingWork.Wait(); - ptrdiff_t RemainingWork = m_PendingWork.Remaining(); + const bool WaitSucceeded = m_PendingWork.Wait(); + const ptrdiff_t RemainingWork = m_PendingWork.Remaining(); + if (!WaitSucceeded) + { + ZEN_ERROR("ParallelWork::~ParallelWork(): waiting for latch failed, pending work count at {}", RemainingWork); + } if (RemainingWork != 0) { void* Frames[8]; uint32_t FrameCount = GetCallstack(2, 8, Frames); CallstackFrames* Callstack = CreateCallstack(FrameCount, Frames); - ZEN_ERROR("ParallelWork destructor waited for outstanding work but pending work count is {} instead of 0\n{}", - RemainingWork, - CallstackToString(Callstack, " ")); - FreeCallstack(Callstack); + auto _ = MakeGuard([Callstack]() { FreeCallstack(Callstack); }); + ZEN_WARN("ParallelWork::~ParallelWork(): waited for outstanding work but pending work count is {} instead of 0", RemainingWork); uint32_t WaitedMs = 0; while (m_PendingWork.Remaining() > 0 && WaitedMs < 2000) @@ -53,20 +55,27 @@ ParallelWork::~ParallelWork() Sleep(50); WaitedMs += 50; } - RemainingWork = m_PendingWork.Remaining(); - if (RemainingWork != 0) + ptrdiff_t RemainingWorkAfterSafetyWait = m_PendingWork.Remaining(); + if (RemainingWorkAfterSafetyWait != 0) { - ZEN_WARN("ParallelWork destructor safety wait failed, pending work count at {}", RemainingWork) + ZEN_ERROR("ParallelWork::~ParallelWork(): safety wait for {} tasks failed, pending work count at {} after {}\n{}", + RemainingWork, + RemainingWorkAfterSafetyWait, + NiceLatencyNs(WaitedMs * 1000000u), + CallstackToString(Callstack, " ")) } else { - ZEN_INFO("ParallelWork destructor safety wait succeeded"); + ZEN_ERROR("ParallelWork::~ParallelWork(): safety wait for {} tasks completed after {}\n{}", + RemainingWork, + NiceLatencyNs(WaitedMs * 1000000u), + CallstackToString(Callstack, " ")); } } } catch (const std::exception& Ex) { - ZEN_ERROR("Exception in ~ParallelWork: {}", Ex.what()); + ZEN_ERROR("Exception in ParallelWork::~ParallelWork(): {}", Ex.what()); } } @@ -103,7 +112,16 @@ ParallelWork::Wait() m_PendingWork.CountDown(); m_DispatchComplete = true; - m_PendingWork.Wait(); + const bool WaitSucceeded = m_PendingWork.Wait(); + const ptrdiff_t RemainingWork = m_PendingWork.Remaining(); + if (!WaitSucceeded) + { + ZEN_ERROR("ParallelWork::Wait(): waiting for latch failed, pending work count at {}", RemainingWork); + } + else if (RemainingWork != 0) + { + ZEN_ERROR("ParallelWork::Wait(): pending work count at {} after successful wait for latch", RemainingWork); + } RethrowErrors(); } -- cgit v1.2.3