AuroraRuntime/Source/Memory/AuHeapAdapter.cpp
Jamie Reece Wilson 8be1afe570 [+] AuMemory::Heap adapters for third party heap allocators
[+] AuMemory::HeapAdapterInterface to describe aforementioned heap allocators of a very limited API
[+] AuMemory::HeapAdapter[Unique,Shared,]
[+] HeapWin32Adapter to convert HANDLE hHeaps of win32s CreateHeap (RtlCreateHeap?) into AuMemory::Heaps
2024-07-19 09:06:56 +01:00

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))
}