#include "gameheap.h"
using nlib_ns::threading::Tls;
using nlib_ns::threading::SharedCriticalSection;
using nlib_ns::heap::CentralHeap;
namespace {
struct HeapBody {
SharedCriticalSection rw;
bool enabled;
CentralHeap central;
public:
HeapBody() {
enabled = false;
}
};
}
class HeapMgr {
public:
static HeapHandle initialize(
void* mem,
size_t size)
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) {
return;
}
body->central.Free(ptr);
EndHeapBody(body);
}
static void freeAll(HeapHandle h) NLIB_NOEXCEPT {
HeapBody* body = BeginHeapBody(h);
if (!body) return;
body->central.WalkAllocatedPtrs(MyFreeFunc, body);
EndHeapBody(body);
}
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();
return NULL;
}
static void EndHeapBody(HeapBody*& body) NLIB_NO_THREAD_SAFETY_ANALYSIS {
if (body) {
body->rw.unlock_shared();
body = NULL;
}
}
#ifdef NN_PLATFORM_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);
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)
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);
body.enabled = true;
body.rw.unlock();
return HeapHandle(static_cast<int>(idx));
}
body.rw.unlock();
}
}
return HeapHandle(-1);
}
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();
}
return HeapMgr::initialize(size);
}
HeapHandle HeapHandle::createHeap(
void* mem,
size_t size)
NLIB_NOEXCEPT {
return HeapMgr::initialize(mem, size);
}
HeapMgr::destroy(h);
}
void* HeapHandle::alloc(
size_t size,
size_t alignment)
NLIB_NOEXCEPT {
return HeapMgr::alloc(*this, size, alignment);
}
HeapMgr::free(*this, ptr);
}
HeapMgr::freeAll(*this);
}
return HeapMgr::isValid(*this);
}
return HeapMgr::isClean(*this);
}
static nlib_tls g_DefaultHeapHandleTls = 0;
NLIB_UNUSED(e);
NLIB_ASSERT_NOERR(e);
}
nlib_once(&g_InitDefaultHeapHandleTls, InitDefaultHeapHandleTls);
void* value;
return HeapHandle(-1);
}
int32_t idx = static_cast<int32_t>(reinterpret_cast<intptr_t>(value));
return HeapHandle(idx);
}
nlib_once(&g_InitDefaultHeapHandleTls, InitDefaultHeapHandleTls);
void* value = reinterpret_cast<void*>(static_cast<intptr_t>(h.idx_));
}