mirror of
https://github.com/zeldaret/ss
synced 2026-06-11 05:08:16 -04:00
207 lines
5.4 KiB
C++
207 lines
5.4 KiB
C++
#include "egg/core/eggHeap.h"
|
|
|
|
#include "egg/core/eggAllocator.h"
|
|
#include "egg/core/eggThread.h"
|
|
#include "nw4r/ut/ut_list.h"
|
|
|
|
namespace EGG {
|
|
|
|
nw4r::ut::List Heap::sHeapList;
|
|
OSMutex Heap::sRootMutex;
|
|
Heap *Heap::sCurrentHeap;
|
|
int Heap::sIsHeapListInitialized;
|
|
Heap *Heap::sAllocatableHeap;
|
|
ErrorCallback Heap::sErrorCallback;
|
|
HeapAllocCallback Heap::sAllocCallback;
|
|
HeapFreeCallback Heap::sFreeCallback;
|
|
void *Heap::sErrorCallbackArg;
|
|
void *Heap::sAllocCallbackArg;
|
|
void *Heap::sFreeCallbackArg;
|
|
HeapCreateCallback Heap::sCreateCallback;
|
|
HeapDestroyCallback Heap::sDestroyCallback;
|
|
|
|
void Heap::initialize() {
|
|
nw4r::ut::List_Init(&sHeapList, 0x1c /* todo offsetof() */);
|
|
OSInitMutex(&sRootMutex);
|
|
sIsHeapListInitialized = true;
|
|
}
|
|
|
|
Heap::Heap(MEMiHeapHead *head) : mHeapHandle(head), mParentBlock(nullptr), mName("NoName"), mFlag() {
|
|
mFlag.value = 0;
|
|
nw4r::ut::List_Init(&mChildren, 0x8 /* todo offsetof() */);
|
|
OSLockMutex(&sRootMutex);
|
|
nw4r::ut::List_Append(&sHeapList, this);
|
|
OSUnlockMutex(&sRootMutex);
|
|
}
|
|
|
|
Heap::~Heap() {
|
|
OSLockMutex(&sRootMutex);
|
|
nw4r::ut::List_Remove(&sHeapList, this);
|
|
OSUnlockMutex(&sRootMutex);
|
|
}
|
|
|
|
void *Heap::alloc(size_t size, int align, Heap *heap) {
|
|
Heap *currentHeap = sCurrentHeap;
|
|
Thread *thread = Thread::findThread(OSGetCurrentThread());
|
|
Heap *threadHeap = nullptr;
|
|
|
|
if (thread != nullptr) {
|
|
threadHeap = thread->mAllocatableHeap;
|
|
if (threadHeap != nullptr) {
|
|
heap = threadHeap;
|
|
}
|
|
}
|
|
if (sAllocatableHeap != nullptr) {
|
|
if (heap == nullptr) {
|
|
heap = currentHeap;
|
|
}
|
|
if (heap != sAllocatableHeap) {
|
|
OSReport(
|
|
"cannot allocate from heap %x(%s) : allocatable heap is %x(%s)\n", heap, heap->getName(),
|
|
sAllocatableHeap, sAllocatableHeap->getName()
|
|
);
|
|
OSReport("\tthread heap=%x(%s)\n", threadHeap, threadHeap != nullptr ? threadHeap->getName() : "none");
|
|
if (sErrorCallback != nullptr) {
|
|
HeapErrorArg arg;
|
|
arg.msg = "disable_but";
|
|
arg.userdata = sErrorCallbackArg;
|
|
sErrorCallback(&arg);
|
|
}
|
|
dumpAll();
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
if (heap == nullptr) {
|
|
heap = currentHeap;
|
|
}
|
|
void *ptr = nullptr;
|
|
if (heap) {
|
|
ptr = heap->alloc(size, align);
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
Heap *Heap::findHeap(MEMiHeapHead *head) {
|
|
Heap *heap = nullptr;
|
|
OSLockMutex(&sRootMutex);
|
|
if (sIsHeapListInitialized) {
|
|
Heap *heap2 = nullptr;
|
|
while ((heap2 = (Heap *)nw4r::ut::List_GetNext(&sHeapList, heap2))) {
|
|
if (heap2->mHeapHandle == head) {
|
|
heap = heap2;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
OSUnlockMutex(&sRootMutex);
|
|
return heap;
|
|
}
|
|
|
|
Heap *Heap::findParentHeap() {
|
|
Heap *retHeap = nullptr;
|
|
MEMiHeapHead *heap = MEMFindParentHeap(mHeapHandle);
|
|
if (heap) {
|
|
retHeap = findHeap(heap);
|
|
}
|
|
|
|
return retHeap;
|
|
}
|
|
|
|
Heap *Heap::findContainHeap(const void *memBlock) {
|
|
Heap *retHeap = nullptr;
|
|
MEMiHeapHead *heap = MEMFindContainHeap(memBlock);
|
|
if (heap) {
|
|
retHeap = findHeap(heap);
|
|
}
|
|
|
|
return retHeap;
|
|
}
|
|
|
|
void Heap::free(void *ptr, Heap *heap) {
|
|
if (heap == nullptr) {
|
|
MEMiHeapHead *iheap = MEMFindContainHeap(ptr);
|
|
if (iheap == nullptr) {
|
|
return;
|
|
}
|
|
heap = findHeap(iheap);
|
|
if (heap == nullptr) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
heap->free(ptr);
|
|
}
|
|
|
|
void Heap::dispose() {
|
|
mFlag.setBit(1);
|
|
Heap *heap;
|
|
while ((heap = (Heap *)nw4r::ut::List_GetFirst(&mChildren)) != nullptr) {
|
|
heap->~Heap();
|
|
}
|
|
mFlag.resetBit(1);
|
|
}
|
|
|
|
void Heap::dump() {}
|
|
|
|
void Heap::dumpAll() {
|
|
Heap *heap = nullptr;
|
|
u32 mem[2] = {0, 0};
|
|
|
|
OSLockMutex(&sRootMutex);
|
|
while ((heap = (Heap *)nw4r::ut::List_GetNext(&sHeapList, heap)) != nullptr) {
|
|
Heap *childHeap = nullptr;
|
|
Heap *parentHeap = heap->findParentHeap();
|
|
if ((u32)heap < 0x90000000) {
|
|
mem[0] += heap->getAllocatableSize(4);
|
|
} else {
|
|
mem[1] += heap->getAllocatableSize(4);
|
|
}
|
|
|
|
while ((childHeap = (Heap *)nw4r::ut::List_GetNext(&sHeapList, childHeap)) != nullptr) {
|
|
if (parentHeap == childHeap) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
OSUnlockMutex(&sRootMutex);
|
|
}
|
|
|
|
Heap *Heap::becomeCurrentHeap() {
|
|
OSLockMutex(&sRootMutex);
|
|
Heap *h = sCurrentHeap;
|
|
sCurrentHeap = this;
|
|
OSUnlockMutex(&sRootMutex);
|
|
return h;
|
|
}
|
|
|
|
Heap *Heap::_becomeCurrentHeapWithoutLock() {
|
|
Heap *h = sCurrentHeap;
|
|
sCurrentHeap = this;
|
|
DCStoreRange(&sCurrentHeap, sizeof(sCurrentHeap));
|
|
return h;
|
|
}
|
|
|
|
// TODO this could be an inline virtual function
|
|
void Heap::initAllocator(Allocator *alloc, s32 align) {
|
|
MEMInitAllocatorFor_Heap(alloc, align, this);
|
|
}
|
|
|
|
} // namespace EGG
|
|
|
|
void *operator new(size_t, void *p) {
|
|
return p;
|
|
}
|
|
void *operator new(size_t size, EGG::Heap *heap, int align) {
|
|
return EGG::Heap::alloc(size, align, heap);
|
|
}
|
|
void *operator new(size_t size, EGG::Allocator *alloc) {
|
|
return MEMAllocFromAllocator(alloc->getHandle(), size);
|
|
}
|
|
void *operator new[](size_t size, int align) {
|
|
return EGG::Heap::alloc(size, align, nullptr);
|
|
}
|
|
void *operator new[](size_t size, EGG::Heap *heap, int align) {
|
|
return EGG::Heap::alloc(size, align, heap);
|
|
}
|