diff --git a/Source/Engine/Core/ObjectsRemovalService.cpp b/Source/Engine/Core/ObjectsRemovalService.cpp index bb3fd8bf1..a020f7844 100644 --- a/Source/Engine/Core/ObjectsRemovalService.cpp +++ b/Source/Engine/Core/ObjectsRemovalService.cpp @@ -5,7 +5,6 @@ #include "Collections/Dictionary.h" #include "Engine/Engine/Time.h" #include "Engine/Engine/EngineService.h" -#include "Engine/Threading/Threading.h" #include "Engine/Profiler/ProfilerCPU.h" #include "Engine/Scripting/ScriptingObject.h" @@ -14,16 +13,15 @@ const Char* HertzSizesData[] = { TEXT("Hz"), TEXT("KHz"), TEXT("MHz"), TEXT("GHz Span Utilities::Private::BytesSizes(BytesSizesData, ARRAY_COUNT(BytesSizesData)); Span Utilities::Private::HertzSizes(HertzSizesData, ARRAY_COUNT(HertzSizesData)); -namespace ObjectsRemovalServiceImpl +namespace { CriticalSection PoolLocker; DateTime LastUpdate; float LastUpdateGameTime; Dictionary Pool(8192); + uint64 PoolCounter = 0; } -using namespace ObjectsRemovalServiceImpl; - class ObjectsRemoval : public EngineService { public: @@ -64,6 +62,7 @@ void ObjectsRemovalService::Add(Object* obj, float timeToLive, bool useGameTime) PoolLocker.Lock(); Pool[obj] = timeToLive; + PoolCounter++; PoolLocker.Unlock(); } @@ -72,6 +71,7 @@ void ObjectsRemovalService::Flush(float dt, float gameDelta) PROFILE_CPU(); PoolLocker.Lock(); + PoolCounter = 0; // Update timeouts and delete objects that timed out for (auto i = Pool.Begin(); i.IsNotEnd(); ++i) @@ -90,6 +90,24 @@ void ObjectsRemovalService::Flush(float dt, float gameDelta) } } + // If any object was added to the pool while removing objects (by this thread) then retry removing any nested objects (but without delta time) + if (PoolCounter != 0) + { + RETRY: + PoolCounter = 0; + for (auto i = Pool.Begin(); i.IsNotEnd(); ++i) + { + if (i->Value <= 0.0f) + { + Object* obj = i->Key; + Pool.Remove(i); + obj->OnDeleteObject(); + } + } + if (PoolCounter != 0) + goto RETRY; + } + PoolLocker.Unlock(); } @@ -121,7 +139,7 @@ void ObjectsRemoval::Dispose() // Delete all remaining objects { - ScopeLock lock(PoolLocker); + PoolLocker.Lock(); for (auto i = Pool.Begin(); i.IsNotEnd(); ++i) { Object* obj = i->Key; @@ -129,6 +147,7 @@ void ObjectsRemoval::Dispose() obj->OnDeleteObject(); } Pool.Clear(); + PoolLocker.Unlock(); } } diff --git a/Source/Engine/Scripting/Internal/EngineInternalCalls.cpp b/Source/Engine/Scripting/Internal/EngineInternalCalls.cpp index 27bb8aa47..e3e5b4342 100644 --- a/Source/Engine/Scripting/Internal/EngineInternalCalls.cpp +++ b/Source/Engine/Scripting/Internal/EngineInternalCalls.cpp @@ -190,7 +190,6 @@ DEFINE_INTERNAL_CALL(bool) ScriptingInternal_IsTypeFromGameScripts(MTypeObject* DEFINE_INTERNAL_CALL(void) ScriptingInternal_FlushRemovedObjects() { - ASSERT(IsInMainThread()); ObjectsRemovalService::Flush(); }