nlib
heap/gameheap/gameheap.cpp

Refer to the heap/gameheap/gameheap_appcode.cpp documentation.

#include "gameheap.h"
using nlib_ns::threading::Tls;
using nlib_ns::threading::SharedCriticalSection;
using nlib_ns::heap::CentralHeap;
namespace {
struct HeapBody {
// Read Lock: Allocation/Deallocation by the heap.
// Write Lock: Create/Destroy the heap itself.
SharedCriticalSection rw;
bool enabled;
CentralHeap central;
public:
HeapBody() {
enabled = false;
}
};
} // namespace
class HeapMgr {
// Management by handle is not necessary
// if HeapHandle::free() is never called after the finalization of the heap.
public:
static HeapHandle initialize(size_t size) NLIB_NOEXCEPT;
static HeapHandle initialize(void* mem, size_t size) NLIB_NOEXCEPT;
static void destroy(HeapHandle h) NLIB_NOEXCEPT;
static void* alloc(HeapHandle h, size_t size, size_t alignment) NLIB_NOEXCEPT {
HeapBody* body = BeginHeapBody(h);
if (!body) return NULL;
void* ptr = body->central.Alloc(size, alignment);
EndHeapBody(body);
nlib_printf(" alloc: @%p, %d bytes\n", ptr, static_cast<int>(size));
return ptr;
}
static void free(HeapHandle h, void* ptr) NLIB_NOEXCEPT {
HeapBody* body = BeginHeapBody(h);
if (!body) {
// Before free(), the heap is finalized or freeAll() is executed.
// it may crash before here, executing destructors because of page fault.
return;
}
nlib_printf(" free: @%p\n", ptr);
body->central.Free(ptr);
EndHeapBody(body);
}
// static void* realloc(HeapHandle h, void* ptr, size_t new_size)
static void freeAll(HeapHandle h) NLIB_NOEXCEPT {
HeapBody* body = BeginHeapBody(h);
if (!body) return;
body->central.WalkAllocatedPtrs(MyFreeFunc, body);
EndHeapBody(body);
}
// static const void* getStartAddress(HeapHandle h);
// static const void* getEndAddress(HeapHandle h);
// static size_t getSize(HeapHandle h);
// static size_t getFreeSize(HeapHandle h);
// static size_t getMaxAllocatableSize(HeapHandle h, size_t alignment);
// static bool isInclude(HeapHandle h, const void* ptr);
// static void dump();
static bool isValid(HeapHandle h) NLIB_NOEXCEPT {
HeapBody* body = BeginHeapBody(h);
if (!body) return false;
EndHeapBody(body);
return true;
}
static bool isClean(HeapHandle h) NLIB_NOEXCEPT {
HeapBody* body = BeginHeapBody(h);
if (!body) return false;
int rval;
body->central.Query(NMALLOC_QUERY_IS_CLEAN, &rval);
EndHeapBody(body);
return rval != 0;
}
private:
static errno_t MyFreeFunc(void* p, size_t size, void* b) NLIB_NOEXCEPT {
static_cast<void>(size);
HeapBody* body = reinterpret_cast<HeapBody*>(b);
body->central.Free(p);
return 0;
}
static HeapBody* BeginHeapBody(HeapHandle h) NLIB_NO_THREAD_SAFETY_ANALYSIS {
int idx = h.idx_;
if (idx < 0 || idx >= static_cast<int>(kNumHeap)) {
return NULL;
}
HeapBody& body = body_[idx];
body.rw.lock_shared();
if (body.enabled) {
return &body;
}
body.rw.unlock_shared();
// There are objects in use, or the heap is finalized already.
// You can make an assert or warning.
// It may crash before here because of page fault.
return NULL;
}
static void EndHeapBody(HeapBody*& body) NLIB_NO_THREAD_SAFETY_ANALYSIS { // NOLINT
if (body) {
body->rw.unlock_shared();
body = NULL;
}
}
#ifdef NN_PLATFORM_CTR
// SharedCriticalSection use up system Event resource in CTR....
static const size_t kNumHeap = 8;
#else
static const size_t kNumHeap = 64;
#endif
static HeapBody body_[kNumHeap];
};
HeapBody HeapMgr::body_[kNumHeap];
HeapHandle HeapMgr::initialize(size_t size) NLIB_NOEXCEPT NLIB_NO_THREAD_SAFETY_ANALYSIS {
for (size_t idx = 0; idx < kNumHeap; ++idx) {
HeapBody& body = body_[idx];
if (body.rw.try_lock()) {
if (!body.enabled) {
body.central.Init(NULL, size, 0); // check rval
body.enabled = true;
body.rw.unlock();
return HeapHandle(static_cast<int>(idx));
}
body.rw.unlock();
}
}
return HeapHandle(-1);
}
HeapHandle HeapMgr::initialize(void* mem, size_t size)
NLIB_NOEXCEPT NLIB_NO_THREAD_SAFETY_ANALYSIS {
for (size_t idx = 0; idx < kNumHeap; ++idx) {
HeapBody& body = body_[idx];
if (body.rw.try_lock()) {
if (!body.enabled) {
body.central.Init(mem, size, 0); // check rval
body.enabled = true;
body.rw.unlock();
return HeapHandle(static_cast<int>(idx));
}
body.rw.unlock();
}
}
return HeapHandle(-1);
}
void HeapMgr::destroy(HeapHandle h) NLIB_NOEXCEPT {
int idx = h.idx_;
if (idx < 0 || idx >= static_cast<int>(kNumHeap)) return;
HeapBody& body = body_[idx];
body.rw.lock();
{
body.central.Finalize();
body.enabled = false;
}
body.rw.unlock();
}
//
// HeapHandle
//
NLIB_STATIC_ASSERT(sizeof(HeapHandle) <= sizeof(void*));
HeapHandle HeapHandle::createHeap(size_t size) NLIB_NOEXCEPT {
return HeapMgr::initialize(size);
}
HeapHandle HeapHandle::createHeap(void* mem, size_t size) NLIB_NOEXCEPT {
return HeapMgr::initialize(mem, size);
}
void HeapHandle::destroyHeap(HeapHandle h) NLIB_NOEXCEPT {
HeapMgr::destroy(h);
}
void* HeapHandle::alloc(size_t size, size_t alignment) NLIB_NOEXCEPT {
return HeapMgr::alloc(*this, size, alignment);
}
void HeapHandle::free(void* ptr) NLIB_NOEXCEPT {
HeapMgr::free(*this, ptr);
}
void HeapHandle::freeAll() NLIB_NOEXCEPT {
HeapMgr::freeAll(*this);
}
bool HeapHandle::isValid() NLIB_NOEXCEPT {
return HeapMgr::isValid(*this);
}
bool HeapHandle::isClean() NLIB_NOEXCEPT {
return HeapMgr::isClean(*this);
}
static nlib_tls g_DefaultHeapHandleTls = 0;
static void InitDefaultHeapHandleTls() NLIB_NOEXCEPT {
errno_t e = nlib_tls_alloc(&g_DefaultHeapHandleTls, NULL);
NLIB_UNUSED(e);
NLIB_ASSERT_NOERR(e);
}
static nlib_onceflag g_InitDefaultHeapHandleTls = NLIB_ONCE_INIT;
HeapHandle GetThreadDefaultHeapHandle() NLIB_NOEXCEPT {
nlib_once(&g_InitDefaultHeapHandleTls, InitDefaultHeapHandleTls);
void* value;
if (nlib_tls_getvalue(g_DefaultHeapHandleTls, &value) != 0) {
return HeapHandle(-1);
}
int32_t idx = static_cast<int32_t>(reinterpret_cast<intptr_t>(value));
return HeapHandle(idx);
}
void SetThreadDefaultHeapHandle(HeapHandle h) NLIB_NOEXCEPT {
nlib_once(&g_InitDefaultHeapHandleTls, InitDefaultHeapHandleTls);
void* value = reinterpret_cast<void*>(static_cast<intptr_t>(h.idx_));
nlib_tls_setvalue(g_DefaultHeapHandleTls, value);
}