Add error log when adding/removign actors during rendering or when ConcurrentSystemLocker deadlocks

This commit is contained in:
Wojtek Figat
2025-07-15 12:34:40 +02:00
parent c882b547c8
commit 3e0c085bf3
3 changed files with 44 additions and 1 deletions

View File

@@ -7,9 +7,23 @@
#include "Engine/Graphics/RenderView.h" #include "Engine/Graphics/RenderView.h"
#include "Engine/Renderer/RenderList.h" #include "Engine/Renderer/RenderList.h"
#include "Engine/Threading/JobSystem.h" #include "Engine/Threading/JobSystem.h"
#include "Engine/Threading/Threading.h"
#include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Profiler/ProfilerCPU.h"
#include "Engine/Profiler/ProfilerMemory.h" #include "Engine/Profiler/ProfilerMemory.h"
#if !BUILD_RELEASE
#include "Engine/Graphics/GPUDevice.h"
#include "Engine/Core/Log.h"
#endif
#if BUILD_RELEASE
#define CHECK_SCENE_EDIT_ACCESS()
#else
#define CHECK_SCENE_EDIT_ACCESS() \
if (Locker.HasLock(false) && IsInMainThread() && GPUDevice::Instance && GPUDevice::Instance->IsRendering()) \
{ \
LOG(Error, "Adding/removing actors during rendering is not supported ({}, '{}').", a->ToString(), a->GetNamePath()); \
return; \
}
#endif
ISceneRenderingListener::~ISceneRenderingListener() ISceneRenderingListener::~ISceneRenderingListener()
{ {
@@ -148,6 +162,7 @@ void SceneRendering::AddActor(Actor* a, int32& key)
if (key != -1) if (key != -1)
return; return;
PROFILE_MEM(Graphics); PROFILE_MEM(Graphics);
CHECK_SCENE_EDIT_ACCESS();
const int32 category = a->_drawCategory; const int32 category = a->_drawCategory;
ConcurrentSystemLocker::WriteScope lock(Locker, true); ConcurrentSystemLocker::WriteScope lock(Locker, true);
auto& list = Actors[category]; auto& list = Actors[category];
@@ -192,6 +207,7 @@ void SceneRendering::UpdateActor(Actor* a, int32& key, ISceneRenderingListener::
void SceneRendering::RemoveActor(Actor* a, int32& key) void SceneRendering::RemoveActor(Actor* a, int32& key)
{ {
CHECK_SCENE_EDIT_ACCESS();
const int32 category = a->_drawCategory; const int32 category = a->_drawCategory;
ConcurrentSystemLocker::WriteScope lock(Locker, true); ConcurrentSystemLocker::WriteScope lock(Locker, true);
auto& list = Actors[category]; auto& list = Actors[category];

View File

@@ -2,6 +2,9 @@
#include "ConcurrentSystemLocker.h" #include "ConcurrentSystemLocker.h"
#include "Engine/Platform/Platform.h" #include "Engine/Platform/Platform.h"
#if !BUILD_RELEASE
#include "Engine/Core/Log.h"
#endif
ConcurrentSystemLocker::ConcurrentSystemLocker() ConcurrentSystemLocker::ConcurrentSystemLocker()
{ {
@@ -12,7 +15,25 @@ void ConcurrentSystemLocker::Begin(bool write, bool exclusively)
{ {
volatile int64* thisCounter = &_counters[write]; volatile int64* thisCounter = &_counters[write];
volatile int64* otherCounter = &_counters[!write]; volatile int64* otherCounter = &_counters[!write];
#if !BUILD_RELEASE
int32 retries = 0;
double startTime = Platform::GetTimeSeconds();
#endif
RETRY: RETRY:
#if !BUILD_RELEASE
retries++;
if (retries > 1000)
{
double endTime = Platform::GetTimeSeconds();
if (endTime - startTime > 0.5f)
{
LOG(Error, "Deadlock detected in ConcurrentSystemLocker! Thread 0x{0:x} waits for {1} ms...", Platform::GetCurrentThreadID(), (int32)((endTime - startTime) * 1000.0));
retries = 0;
}
}
#endif
// Check if we can enter (cannot read while someone else is writing and vice versa) // Check if we can enter (cannot read while someone else is writing and vice versa)
if (Platform::AtomicRead(otherCounter) != 0) if (Platform::AtomicRead(otherCounter) != 0)
{ {
@@ -47,3 +68,8 @@ void ConcurrentSystemLocker::End(bool write)
// Mark that we left this section // Mark that we left this section
Platform::InterlockedDecrement(&_counters[write]); Platform::InterlockedDecrement(&_counters[write]);
} }
bool ConcurrentSystemLocker::HasLock(bool write) const
{
return Platform::AtomicRead(&_counters[write]) != 0;
}

View File

@@ -19,6 +19,7 @@ public:
void Begin(bool write, bool exclusively = false); void Begin(bool write, bool exclusively = false);
void End(bool write); void End(bool write);
bool HasLock(bool write) const;
public: public:
template<bool Write> template<bool Write>