nlib
heap/gameheap/gameheap.cpp

heap/gameheap/gameheap_appcode.cpp の説明を御覧ください

/*--------------------------------------------------------------------------------*
Project: CrossRoad
Copyright (C)Nintendo All rights reserved.
These coded instructions, statements, and computer programs contain proprietary
information of Nintendo and/or its licensed developers and are protected by
national and international copyright laws. They may not be disclosed to third
parties or copied or duplicated in any form, in whole or in part, without the
prior written consent of Nintendo.
The content herein is highly confidential and should be handled accordingly.
*--------------------------------------------------------------------------------*/
#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(kNmallocQueryIsClean, &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_default_heaphandle_tls = 0;
static void InitDefaultHeapHandleTls() NLIB_NOEXCEPT {
errno_t e = nlib_tls_alloc(&g_default_heaphandle_tls, NULL);
NLIB_UNUSED(e);
NLIB_ASSERT_NOERR(e);
}
static nlib_onceflag g_init_default_heaphandle_tls = NLIB_ONCE_INIT;
HeapHandle GetThreadDefaultHeapHandle() NLIB_NOEXCEPT {
nlib_once(&g_init_default_heaphandle_tls, InitDefaultHeapHandleTls);
void* value;
if (nlib_tls_getvalue(g_default_heaphandle_tls, &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_init_default_heaphandle_tls, InitDefaultHeapHandleTls);
void* value = reinterpret_cast<void*>(static_cast<intptr_t>(h.idx_));
nlib_tls_setvalue(g_default_heaphandle_tls, value);
}