280 lines
6.6 KiB
C++
280 lines
6.6 KiB
C++
|
/***
|
||
|
Copyright (C) 2021-2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved.
|
||
|
|
||
|
File: AuHeapAdapter.cpp
|
||
|
File: Heap.hpp
|
||
|
Date: 2024-7-17
|
||
|
Author: Reece
|
||
|
***/
|
||
|
#include <Source/RuntimeInternal.hpp>
|
||
|
#include "AuHeap.hpp"
|
||
|
#include "AuHeapAdapter.hpp"
|
||
|
#include "AuHeapInternal.hpp"
|
||
|
#include "AuHeapDeletable.hpp"
|
||
|
#include "AuHeapAlignmentInterface.hpp"
|
||
|
|
||
|
namespace Aurora::Memory
|
||
|
{
|
||
|
ImplHeapAdapter::ImplHeapAdapter(const HeapAdapterInterface &heapInterface)
|
||
|
{
|
||
|
if (!this->Init(heapInterface))
|
||
|
{
|
||
|
AU_THROW_CONST_STRING("Invalid heap adapter configuration");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ImplHeapAdapter::ImplHeapAdapter()
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
ImplHeapAdapter::~ImplHeapAdapter()
|
||
|
{
|
||
|
if (this->adapter.fHeapDestroy)
|
||
|
{
|
||
|
this->adapter.fHeapDestroy(&this->adapter.handle);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ImplHeapAdapter::Init(const HeapAdapterInterface &heapInterface)
|
||
|
{
|
||
|
this->adapter = heapInterface;
|
||
|
|
||
|
if (!this->adapter.fFree ||
|
||
|
!this->adapter.fAllocate)
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if (!this->adapter.fGetBlockSize ||
|
||
|
!this->adapter.bHasAlignmentAwareness)
|
||
|
{
|
||
|
if (!MakeHeapInterfaceOfStricterAlignment(&this->adapter))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
HeapStats &ImplHeapAdapter::GetStats()
|
||
|
{
|
||
|
return this->stats;
|
||
|
}
|
||
|
|
||
|
Types::size_t ImplHeapAdapter::GetChunkSize(const void *head)
|
||
|
{
|
||
|
if (!head)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
return this->adapter.fGetBlockSize(&this->adapter.handle, (void *)head);
|
||
|
}
|
||
|
|
||
|
AuSPtr<Heap> ImplHeapAdapter::AllocateDivision(AuUInt32 heap, AuUInt32 alignment)
|
||
|
{
|
||
|
return AllocateDivisionGlobal(this, heap, alignment);
|
||
|
}
|
||
|
|
||
|
void *ImplHeapAdapter::_FAlloc(Types::size_t uLength)
|
||
|
{
|
||
|
return _FAlloc(uLength, alignof(void *));
|
||
|
}
|
||
|
|
||
|
void *ImplHeapAdapter::_FAlloc(Types::size_t uLength, Types::size_t uAlign)
|
||
|
{
|
||
|
if (!uLength)
|
||
|
{
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
auto pRet = this->adapter.fAllocate(&this->adapter.handle, uLength, uAlign);
|
||
|
if (!pRet)
|
||
|
{
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
auto uLengthCurrent = this->GetChunkSize(pRet);
|
||
|
|
||
|
AuAtomicAdd(&this->stats.uBytesLiveCounter, uLengthCurrent);
|
||
|
AuAtomicAdd(&this->stats.uBytesAllocatedLifetime, uLengthCurrent);
|
||
|
|
||
|
return pRet;
|
||
|
}
|
||
|
|
||
|
void *ImplHeapAdapter::_ZAlloc(Types::size_t uLength)
|
||
|
{
|
||
|
auto ptr = this->_FAlloc(uLength);
|
||
|
if (!ptr)
|
||
|
{
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
AuMemset(ptr, 0, uLength);
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
void *ImplHeapAdapter::_ZAlloc(Types::size_t uLength, Types::size_t uAlign)
|
||
|
{
|
||
|
auto ptr = this->_FAlloc(uLength, uAlign);
|
||
|
if (!ptr)
|
||
|
{
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
AuMemset(ptr, 0, uLength);
|
||
|
return ptr;
|
||
|
}
|
||
|
|
||
|
void *ImplHeapAdapter::_ZRealloc(void *pBuffer, Types::size_t uLength)
|
||
|
{
|
||
|
auto prevLength = this->GetChunkSize(pBuffer);
|
||
|
auto alloc = this->_ZAlloc(uLength);
|
||
|
if (!alloc)
|
||
|
{
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
AuMemcpy(alloc, pBuffer, AuMin(prevLength, uLength));
|
||
|
this->_Free(pBuffer);
|
||
|
return alloc;
|
||
|
}
|
||
|
|
||
|
void *ImplHeapAdapter::_ZRealloc(void *pBuffer, Types::size_t uLength, Types::size_t uAlign)
|
||
|
{
|
||
|
auto prevLength = this->GetChunkSize(pBuffer);
|
||
|
auto alloc = this->_ZAlloc(uLength, uAlign);
|
||
|
if (!alloc)
|
||
|
{
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
AuMemcpy(alloc, pBuffer, AuMin(prevLength, uLength));
|
||
|
this->_Free(pBuffer);
|
||
|
return alloc;
|
||
|
}
|
||
|
|
||
|
void *ImplHeapAdapter::_FRealloc(void *pBuffer, Types::size_t uLength)
|
||
|
{
|
||
|
auto prevLength = this->GetChunkSize(pBuffer);
|
||
|
auto alloc = this->_FAlloc(uLength);
|
||
|
if (!alloc)
|
||
|
{
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
AuMemcpy(alloc, pBuffer, AuMin(prevLength, uLength));
|
||
|
this->_Free(pBuffer);
|
||
|
return alloc;
|
||
|
}
|
||
|
|
||
|
void *ImplHeapAdapter::_FRealloc(void *pBuffer, Types::size_t uLength, Types::size_t uAlign)
|
||
|
{
|
||
|
auto prevLength = this->GetChunkSize(pBuffer);
|
||
|
auto alloc = this->_FAlloc(uLength, uAlign);
|
||
|
if (!alloc)
|
||
|
{
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
AuMemcpy(alloc, pBuffer, AuMin(prevLength, uLength));
|
||
|
this->_Free(pBuffer);
|
||
|
return alloc;
|
||
|
}
|
||
|
|
||
|
void ImplHeapAdapter::_Free(void *pBuffer)
|
||
|
{
|
||
|
if (pBuffer == nullptr)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
auto uLengthCurrent = this->GetChunkSize(pBuffer);
|
||
|
|
||
|
this->adapter.fFree(&this->adapter.handle, pBuffer);
|
||
|
|
||
|
AuAtomicAdd(&this->stats.uBytesFreeLifetime, uLengthCurrent);
|
||
|
AuAtomicSub(&this->stats.uBytesLiveCounter, uLengthCurrent);
|
||
|
|
||
|
TryRelease();
|
||
|
}
|
||
|
|
||
|
void ImplHeapAdapter::TryRelease()
|
||
|
{
|
||
|
if (!this->bIsDangling_)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (AuAtomicLoad(&this->stats.uBytesLiveCounter) == 0)
|
||
|
{
|
||
|
delete this;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ImplHeapAdapter::RequestTermination()
|
||
|
{
|
||
|
if (AuAtomicLoad(&this->stats.uBytesLiveCounter))
|
||
|
{
|
||
|
SysPushErrorMemory("Heap life was less than its allocations, waiting for final free");
|
||
|
SysPushErrorMemory("Reporting using mayday!");
|
||
|
|
||
|
// Write a crash dump for later review, and do not panic.
|
||
|
// We just have a leak with no sign of corruption
|
||
|
Telemetry::Mayday();
|
||
|
|
||
|
this->bIsDangling_ = true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
delete this;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void ImplHeapAdapter::WalkHeap(bool(*fCallback)(void *, void *), void *pSecondArg)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
|
||
|
AuSPtr<Heap> ImplHeapAdapter::GetSelfReference()
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
return AuSharedFromThis();
|
||
|
}
|
||
|
catch (...)
|
||
|
{
|
||
|
return {};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Heap *ImplHeapAdapter::GetSelfReferenceRaw()
|
||
|
{
|
||
|
return this;
|
||
|
}
|
||
|
|
||
|
AUKN_SYM Heap *HeapAdapterNew(const HeapAdapterInterface &adapterInterface)
|
||
|
{
|
||
|
auto pHeap = _new ImplHeapAdapter();
|
||
|
if (!pHeap)
|
||
|
{
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
if (!pHeap->Init(adapterInterface))
|
||
|
{
|
||
|
delete pHeap;
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
return pHeap;
|
||
|
}
|
||
|
|
||
|
AUKN_SYM void HeapAdapterRelease(Heap *pHeap)
|
||
|
{
|
||
|
static_cast<ImplHeapAdapter *>(pHeap)->RequestTermination();
|
||
|
}
|
||
|
|
||
|
AUROXTL_INTERFACE_SOO_SRC_EX(AURORA_SYMBOL_EXPORT, HeapAdapter, ImplHeapAdapter, (const HeapAdapterInterface &, adapterInterface))
|
||
|
}
|