From 15740faf9fe9fe4be08965098bbf2947e096aeeb Mon Sep 17 00:00:00 2001 From: chai Date: Wed, 14 Aug 2019 22:50:43 +0800 Subject: +Unity Runtime code --- Runtime/Allocator/DualThreadAllocator.cpp | 263 ++++++++++++++++++++++++++++++ 1 file changed, 263 insertions(+) create mode 100644 Runtime/Allocator/DualThreadAllocator.cpp (limited to 'Runtime/Allocator/DualThreadAllocator.cpp') diff --git a/Runtime/Allocator/DualThreadAllocator.cpp b/Runtime/Allocator/DualThreadAllocator.cpp new file mode 100644 index 0000000..921ecf9 --- /dev/null +++ b/Runtime/Allocator/DualThreadAllocator.cpp @@ -0,0 +1,263 @@ +#include "UnityPrefix.h" +#include "DualThreadAllocator.h" +#include "Runtime/Threads/Thread.h" +#include "Runtime/Allocator/DynamicHeapAllocator.h" + +#if ENABLE_MEMORY_MANAGER + +class DelayedPointerDeletionManager +{ +public: + DelayedPointerDeletionManager(BaseAllocator* mainAlloc, BaseAllocator* threadAlloc) : + m_HasPendingDeletes (0), + m_MainAlloctor (mainAlloc), + m_ThreadAlloctor (threadAlloc), + m_MainThreadPendingPointers(NULL), + m_MainThreadPendingCount (0), + m_MainThreadPendingReserved (0) {} + ~DelayedPointerDeletionManager(){ CleanupPendingMainThreadPointers(); } + + bool HasPending() {return m_HasPendingDeletes != 0;} + void AddPointerToMainThreadDealloc( void* ptr) ; + void CleanupPendingMainThreadPointers() ; + void DeallocateLocalMemory(); +private: + void GrowPendingBuffer(); + void** m_MainThreadPendingPointers; + UInt32 m_MainThreadPendingCount; + UInt32 m_MainThreadPendingReserved; + + volatile int m_HasPendingDeletes; + BaseAllocator* m_MainAlloctor; + BaseAllocator* m_ThreadAlloctor; + Mutex m_MainThreadPendingPointersMutex; +}; + +void DelayedPointerDeletionManager::AddPointerToMainThreadDealloc( void* ptr) +{ + Mutex::AutoLock autolock(m_MainThreadPendingPointersMutex); + if(++m_MainThreadPendingCount > m_MainThreadPendingReserved) + GrowPendingBuffer(); + m_MainThreadPendingPointers[m_MainThreadPendingCount-1] = ptr; + m_HasPendingDeletes = 1; +} + +void DelayedPointerDeletionManager::CleanupPendingMainThreadPointers() +{ + Mutex::AutoLock autolock(m_MainThreadPendingPointersMutex); + Assert(Thread::CurrentThreadIsMainThread()); + m_HasPendingDeletes = 0; + + for(UInt32 i = 0; i < m_MainThreadPendingCount; ++i) + m_MainAlloctor->Deallocate(m_MainThreadPendingPointers[i]); + m_MainThreadPendingCount = 0; +} + +void DelayedPointerDeletionManager::DeallocateLocalMemory() +{ + Assert(!m_HasPendingDeletes && m_MainThreadPendingCount == 0); + m_ThreadAlloctor->Deallocate(m_MainThreadPendingPointers); + m_MainThreadPendingPointers = NULL; + m_MainThreadPendingReserved = 0; +}; + +void DelayedPointerDeletionManager::GrowPendingBuffer() +{ + const UInt32 kInitialBufferSize = 128; + m_MainThreadPendingReserved = std::max(m_MainThreadPendingReserved*2, kInitialBufferSize); + m_MainThreadPendingPointers = (void**) m_ThreadAlloctor->Reallocate(m_MainThreadPendingPointers, m_MainThreadPendingReserved*sizeof(void*), kDefaultMemoryAlignment); +} + + +template +DualThreadAllocator::DualThreadAllocator(const char* name, BaseAllocator* mainAllocator, BaseAllocator* threadAllocator) +: BaseAllocator(name) +{ + m_MainAllocator = (UnderlyingAllocator*)mainAllocator; + m_ThreadAllocator = (UnderlyingAllocator*)threadAllocator; + m_DelayedDeletion = NULL; +} + +template +void DualThreadAllocator::ThreadCleanup() +{ + if(Thread::CurrentThreadIsMainThread()) + UNITY_DELETE(m_DelayedDeletion, kMemManager); +} + +template +void DualThreadAllocator::FrameMaintenance(bool cleanup) +{ + if(m_DelayedDeletion) + { + m_DelayedDeletion->CleanupPendingMainThreadPointers(); + if(cleanup) + m_DelayedDeletion->DeallocateLocalMemory(); + } +} + +template +UnderlyingAllocator* DualThreadAllocator::GetCurrentAllocator() +{ + if(Thread::CurrentThreadIsMainThread()) + return m_MainAllocator; + else + return m_ThreadAllocator; +} + + +template +void* DualThreadAllocator::Allocate( size_t size, int align ) +{ + UnderlyingAllocator* alloc = GetCurrentAllocator(); + bool isMainThread = alloc == m_MainAllocator; + if(isMainThread && m_DelayedDeletion && m_DelayedDeletion->HasPending()) + m_DelayedDeletion->CleanupPendingMainThreadPointers(); + + return alloc->UnderlyingAllocator::Allocate(size, align); +} + +template +void* DualThreadAllocator::Reallocate( void* p, size_t size, int align ) +{ + UnderlyingAllocator* alloc = GetCurrentAllocator(); + + if(alloc->UnderlyingAllocator::Contains(p)) + return alloc->UnderlyingAllocator::Reallocate(p, size, align); + + UnderlyingAllocator* containingAlloc = NULL; + if (alloc == m_MainAllocator) + { + Assert(m_ThreadAllocator->UnderlyingAllocator::Contains(p)); + containingAlloc = m_ThreadAllocator; + } + else + { + Assert(m_MainAllocator->UnderlyingAllocator::Contains(p)); + containingAlloc = m_MainAllocator; + } + + size_t oldSize = containingAlloc->UnderlyingAllocator::GetPtrSize(p); + void* ptr = alloc->UnderlyingAllocator::Allocate(size, align); + memcpy(ptr, p, std::min(size,oldSize)); + Deallocate(p); + return ptr; +} + +template +void DualThreadAllocator::Deallocate( void* p ) +{ + UnderlyingAllocator* alloc = GetCurrentAllocator(); + + if(alloc->UnderlyingAllocator::Contains(p)) + return alloc->UnderlyingAllocator::Deallocate(p); + + if (alloc == m_MainAllocator) + { + DebugAssert(m_ThreadAllocator->UnderlyingAllocator::Contains(p)); + m_ThreadAllocator->UnderlyingAllocator::Deallocate(p); + } + else + { + DebugAssert(m_MainAllocator->UnderlyingAllocator::Contains(p)); + if(!m_DelayedDeletion) + { + SET_ALLOC_OWNER(NULL); + m_DelayedDeletion = UNITY_NEW(DelayedPointerDeletionManager(m_MainAllocator, m_ThreadAllocator), kMemManager); + } + m_DelayedDeletion->AddPointerToMainThreadDealloc(p); + } +} + +template +bool DualThreadAllocator::TryDeallocate( void* p ) +{ + UnderlyingAllocator* alloc = GetCurrentAllocator(); + + if(alloc->UnderlyingAllocator::Contains(p)) + { + alloc->UnderlyingAllocator::Deallocate(p); + return true; + } + + if (m_ThreadAllocator->UnderlyingAllocator::Contains(p)) + { + m_ThreadAllocator->UnderlyingAllocator::Deallocate(p); + return true; + } + if(m_MainAllocator->UnderlyingAllocator::Contains(p)) + { + if(!m_DelayedDeletion) + m_DelayedDeletion = UNITY_NEW(DelayedPointerDeletionManager(m_MainAllocator, m_ThreadAllocator), kMemManager); + m_DelayedDeletion->AddPointerToMainThreadDealloc(p); + return true; + } + return false; +} + + +template +bool DualThreadAllocator::Contains( const void* p ) +{ + UnderlyingAllocator* alloc = GetCurrentAllocator(); + if(alloc->UnderlyingAllocator::Contains(p)) + return true; + if(m_ThreadAllocator->UnderlyingAllocator::Contains(p)) + return true; + if(m_MainAllocator->UnderlyingAllocator::Contains(p)) + return true; + return false; +} + +template +size_t DualThreadAllocator::GetAllocatedMemorySize( ) const +{ + return m_MainAllocator->GetAllocatedMemorySize() + (m_ThreadAllocator?m_ThreadAllocator->GetAllocatedMemorySize():0); +} + +template +size_t DualThreadAllocator::GetAllocatorSizeTotalUsed() const +{ + return m_MainAllocator->GetAllocatorSizeTotalUsed() + (m_ThreadAllocator?m_ThreadAllocator->GetAllocatorSizeTotalUsed():0); +} + +template +size_t DualThreadAllocator::GetReservedSizeTotal() const +{ + return m_MainAllocator->GetReservedSizeTotal() + (m_ThreadAllocator?m_ThreadAllocator->GetReservedSizeTotal():0); +} + +template +size_t DualThreadAllocator::GetPtrSize( const void* ptr ) const +{ + // all allocators have the same allocation header + return m_MainAllocator->UnderlyingAllocator::GetPtrSize(ptr); +} + +template +ProfilerAllocationHeader* DualThreadAllocator::GetProfilerHeader( const void* ptr ) const +{ + return m_MainAllocator->UnderlyingAllocator::GetProfilerHeader(ptr); +} + + +template +bool DualThreadAllocator::CheckIntegrity() +{ + bool valid = m_ThreadAllocator->UnderlyingAllocator::CheckIntegrity(); + if(Thread::CurrentThreadIsMainThread()) + valid &= m_MainAllocator->UnderlyingAllocator::CheckIntegrity(); + Assert(valid); + return valid; +} + +template +bool DualThreadAllocator::ValidatePointer(void* ptr) +{ + UnderlyingAllocator* alloc = GetCurrentAllocator(); + return alloc->UnderlyingAllocator::ValidatePointer(ptr); +} + +template class DualThreadAllocator< DynamicHeapAllocator< LowLevelAllocator > >; + +#endif // #if ENABLE_MEMORY_MANAGER -- cgit v1.1-26-g67d0