mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-05-26 23:26:47 -04:00
637 lines
20 KiB
C
637 lines
20 KiB
C
#include "libc64/__osMalloc.h"
|
|
|
|
#include <dolphin/os.h>
|
|
#include "libultra/libultra.h"
|
|
#include "terminal.h"
|
|
|
|
#define OS_MALLOC_MAGIC (s16)'ss' // magic number for an OSMemBlock
|
|
#define OS_MALLOC_BLOCK_OK(block) ((block) != NULL && (block)->magic == OS_MALLOC_MAGIC) // check if OSMemBlock structure is OK
|
|
#define OS_MALLOC_DATA2BLOCK(data) ((OSMemBlock*)((u32)(data) - sizeof(OSMemBlock))) // get memblock data pointer from OSMemBlock
|
|
#define OS_MALLOC_BLOCK2DATA(block) ((u8*)(block) + sizeof(OSMemBlock)) // get OSMemBlock pointer from data
|
|
|
|
// Gets the pointer to the next OSMemBlock immediately following this block in RAM, may or may not be a valid OSMemBlock
|
|
#define OS_MALLOC_NEXTMEMBLOCK(block) ((OSMemBlock*)((u32)(block) + sizeof(OSMemBlock) + (block)->size))
|
|
|
|
int __osMalloc_FreeBlockTest_Enable = FALSE;
|
|
|
|
static void setDebugInfo(OSMemBlock* block, const char* file, s32 line, OSArena* arena) {
|
|
block->file = file;
|
|
block->line = line;
|
|
block->threadId = osGetThreadId(NULL);
|
|
block->arena = arena;
|
|
block->time = osGetTime();
|
|
}
|
|
|
|
static void arena_lock_init(OSArena* arena) {
|
|
static OSMesg arena_lock_msg;
|
|
|
|
osCreateMesgQueue(&arena->lockQueue, &arena_lock_msg, OS_MESG_BLOCK);
|
|
}
|
|
|
|
static void arena_lock(OSArena* arena) {
|
|
osSendMesg(&arena->lockQueue, NULL, OS_MESG_BLOCK);
|
|
}
|
|
|
|
static void arena_unlock(OSArena* arena) {
|
|
osRecvMesg(&arena->lockQueue, NULL, OS_MESG_BLOCK);
|
|
}
|
|
|
|
static OSMemBlock* get_block_next(OSMemBlock* block) {
|
|
if (block->next != NULL && !OS_MALLOC_BLOCK_OK(block->next)) {
|
|
// Emergency! Memory leak discovered!
|
|
OSReport(VT_COL(RED, WHITE) "緊急事態!メモリリーク発見! (block=%08x)\n" VT_RST, block->next);
|
|
OSPanic(__FILE__, 133, "");
|
|
block->next = NULL; // @BUG - OSPanic halts CPU execution, this is pointless
|
|
}
|
|
|
|
return block->next;
|
|
}
|
|
|
|
static OSMemBlock* get_block_prev(OSMemBlock* block) {
|
|
// @BUG - this shouldn't check for block->prev != NULL
|
|
if (block->prev != NULL && !OS_MALLOC_BLOCK_OK(block->prev)) {
|
|
// Emergency! Memory leak discovered!
|
|
OSReport(VT_COL(RED, WHITE) "緊急事態!メモリリーク発見! (block=%08x)\n" VT_RST, block->prev);
|
|
OSPanic(__FILE__, 144, "");
|
|
block->prev = NULL; // @BUG - OSPanic halts CPU execution, this is pointless
|
|
}
|
|
|
|
return block->prev;
|
|
}
|
|
|
|
static OSMemBlock* search_last_block(OSArena* arena) {
|
|
OSMemBlock* block = NULL;
|
|
|
|
if (arena != NULL) {
|
|
OSMemBlock* current = arena->head;
|
|
|
|
if (OS_MALLOC_BLOCK_OK(current)) {
|
|
while (current != NULL) {
|
|
block = current;
|
|
current = get_block_next(current);
|
|
}
|
|
}
|
|
}
|
|
|
|
return block;
|
|
}
|
|
|
|
extern void __osMallocInit(OSArena* arena, u8* base, s32 size) {
|
|
bzero(arena, sizeof(OSArena));
|
|
arena_lock_init(arena);
|
|
__osMallocAddBlock(arena, base, size);
|
|
arena->initialized = TRUE;
|
|
}
|
|
|
|
extern void __osMallocAddBlock(OSArena* arena, u8* base, s32 size) {
|
|
s32 align_size;
|
|
OSMemBlock* block;
|
|
OSMemBlock* last;
|
|
|
|
if (base != NULL) {
|
|
block = (OSMemBlock*)ALIGN_NEXT((u32)base, 32);
|
|
align_size = ALIGN_PREV(size - ((u32)block - (u32)base), 32);
|
|
|
|
if (align_size > (int)sizeof(OSMemBlock)) {
|
|
memset(block, 0xAB, align_size);
|
|
block->next = NULL;
|
|
block->prev = NULL;
|
|
block->size = align_size - sizeof(OSMemBlock);
|
|
block->free = TRUE;
|
|
block->magic = OS_MALLOC_MAGIC;
|
|
|
|
arena_lock(arena);
|
|
last = search_last_block(arena);
|
|
if (last == NULL) {
|
|
arena->head = block;
|
|
arena->base = base;
|
|
} else {
|
|
block->prev = last;
|
|
last->next = block;
|
|
}
|
|
arena_unlock(arena);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void destroy_all_block(OSArena* arena) {
|
|
OSMemBlock* block;
|
|
OSMemBlock* next;
|
|
|
|
arena_lock(arena);
|
|
block = arena->head;
|
|
while (block != NULL) {
|
|
next = get_block_next(block);
|
|
memset(block, 0xAB, block->size + sizeof(OSMemBlock));
|
|
block = next;
|
|
}
|
|
arena_unlock(arena);
|
|
}
|
|
|
|
extern void __osMallocCleanup(OSArena* arena) {
|
|
destroy_all_block(arena);
|
|
bzero(arena, sizeof(OSArena));
|
|
}
|
|
|
|
extern BOOL __osMallocIsInitalized(OSArena* arena) {
|
|
return arena->initialized;
|
|
}
|
|
|
|
static void __osMalloc_FreeBlockTest(OSArena* arena, OSMemBlock* block) {
|
|
if (__osMalloc_FreeBlockTest_Enable) {
|
|
u32* s = (u32*)(OS_MALLOC_BLOCK2DATA(block));
|
|
u32* e = (u32*)(OS_MALLOC_BLOCK2DATA(block) + block->size);
|
|
u32* p;
|
|
|
|
for (p = s; p < e; p++) {
|
|
u32 v = *p;
|
|
|
|
if (v != 0xABABABAB && v != 0xEFEFEFEF) {
|
|
// Emergency! Memory leak detected!
|
|
OSReport(VT_COL(RED, WHITE) "緊急事態!メモリリーク検出! (block=%08x s=%08x e=%08x p=%08x)\n" VT_RST, block, s, e, p);
|
|
__osDisplayArena(arena);
|
|
OSPanic(__FILE__, 300, "");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void* __osMallocAlign_NoLock(OSArena* arena, u32 size, u32 align) {
|
|
OSMemBlock* aligned_block;
|
|
OSMemBlock* new_next;
|
|
int alignment_bytes;
|
|
OSMemBlock* block;
|
|
u8* data_p = NULL;
|
|
OSMemBlock* next;
|
|
u32 full_size;
|
|
u32 mask;
|
|
int remain;
|
|
|
|
size = ALIGN_NEXT(size, 32);
|
|
full_size = ALIGN_NEXT(size, 32) + sizeof(OSMemBlock);
|
|
|
|
if (align <= 16) {
|
|
align = 16;
|
|
} else if (align <= 32) {
|
|
align = 32;
|
|
} else if (align <= 64) {
|
|
align = 64;
|
|
} else if (align <= 128) {
|
|
align = 128;
|
|
} else if (align <= 256) {
|
|
align = 256;
|
|
} else if (align <= 1024) {
|
|
align = 1024;
|
|
} else {
|
|
align = 8;
|
|
}
|
|
|
|
block = arena->head;
|
|
mask = align - 1;
|
|
while (block != NULL) {
|
|
if (block->free) {
|
|
remain = ((u32)block + sizeof(OSMemBlock)) & mask;
|
|
alignment_bytes = remain == 0 ? 0 : align - remain;
|
|
aligned_block = (OSMemBlock*)((u32)block + alignment_bytes);
|
|
|
|
if (block->size - alignment_bytes >= size) {
|
|
if (arena->flags & OSArena_FLAG_FREE_BLOCK_TEST) {
|
|
__osMalloc_FreeBlockTest(arena, block);
|
|
}
|
|
|
|
if (block != aligned_block) {
|
|
memmove(aligned_block, block, sizeof(OSMemBlock));
|
|
block = aligned_block;
|
|
block->size -= alignment_bytes;
|
|
if (block->prev != NULL) {
|
|
block->prev->next = block;
|
|
block->prev->size += alignment_bytes; // do not orphan alignment bytes
|
|
} else {
|
|
arena->head = block;
|
|
}
|
|
|
|
if (block->next != NULL) {
|
|
block->next->prev = block;
|
|
}
|
|
}
|
|
|
|
if (block->size > full_size) {
|
|
new_next = (OSMemBlock*)((u32)block + full_size);
|
|
new_next->next = get_block_next(block);
|
|
new_next->prev = block;
|
|
new_next->size = block->size - full_size;
|
|
new_next->free = TRUE;
|
|
new_next->magic = OS_MALLOC_MAGIC;
|
|
block->next = new_next;
|
|
block->size = size;
|
|
|
|
next = get_block_next(new_next);
|
|
if (next != NULL) {
|
|
next->prev = new_next;
|
|
}
|
|
}
|
|
|
|
block->free = FALSE;
|
|
setDebugInfo(block, NULL, 0, arena);
|
|
data_p = OS_MALLOC_BLOCK2DATA(block);
|
|
if (arena->flags & OSArena_FLAG_CLEAR_MEM_ON_ALLOC) {
|
|
memset(data_p, 0xCD, size);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
block = get_block_next(block);
|
|
}
|
|
|
|
return data_p;
|
|
}
|
|
|
|
static void* __osMalloc_NoLock(OSArena* arena, u32 size) {
|
|
return __osMallocAlign_NoLock(arena, size, 0);
|
|
}
|
|
|
|
extern void* __osMallocAlign(OSArena* arena, u32 size, u32 align) {
|
|
void* ret;
|
|
|
|
arena_lock(arena);
|
|
ret = __osMallocAlign_NoLock(arena, size, align);
|
|
arena_unlock(arena);
|
|
return ret;
|
|
}
|
|
|
|
extern void* __osMalloc(OSArena* arena, u32 size) {
|
|
return __osMallocAlign(arena, size, 0);
|
|
}
|
|
|
|
extern void* __osMallocR(OSArena* arena, u32 size) {
|
|
OSMemBlock* block;
|
|
OSMemBlock* next;
|
|
OSMemBlock* n;
|
|
u8* ret = NULL;
|
|
u32 full_size;
|
|
|
|
size = ALIGN_NEXT(size, 32);
|
|
full_size = ALIGN_NEXT(size, 32) + sizeof(OSMemBlock);
|
|
arena_lock(arena);
|
|
block = search_last_block(arena);
|
|
while (block != NULL) {
|
|
if (block->free && block->size >= size) {
|
|
if (arena->flags & OSArena_FLAG_FREE_BLOCK_TEST) {
|
|
__osMalloc_FreeBlockTest(arena, block);
|
|
}
|
|
|
|
if (block->size > full_size) {
|
|
next = (OSMemBlock*)((u32)block + block->size - size);
|
|
next->next = get_block_next(block);
|
|
next->prev = block;
|
|
next->size = size;
|
|
next->magic = OS_MALLOC_MAGIC;
|
|
block->next = next;
|
|
block->size -= full_size;
|
|
n = get_block_next(next);
|
|
if (n != NULL) {
|
|
n->prev = next;
|
|
}
|
|
block = next;
|
|
}
|
|
|
|
block->free = FALSE;
|
|
setDebugInfo(block, NULL, 0, arena);
|
|
ret = OS_MALLOC_BLOCK2DATA(block);
|
|
if (arena->flags & OSArena_FLAG_CLEAR_MEM_ON_ALLOC) {
|
|
memset(ret, 0xCD, size);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
block = get_block_prev(block);
|
|
}
|
|
|
|
arena_unlock(arena);
|
|
return ret;
|
|
}
|
|
|
|
static void __osFree_NoLock(OSArena* arena, void* ptr) {
|
|
OSMemBlock* block = OS_MALLOC_DATA2BLOCK(ptr);
|
|
OSMemBlock* next;
|
|
OSMemBlock* prev;
|
|
OSMemBlock* temp;
|
|
|
|
if (ptr != NULL) {
|
|
if (!OS_MALLOC_BLOCK_OK(block)) {
|
|
OSReport(VT_COL(RED, WHITE) "__osFree:不正解放(%08x)\n" VT_RST, ptr); // __osFree: irregular deallocation
|
|
OSPanic(__FILE__, 738, "");
|
|
return;
|
|
}
|
|
|
|
if (block->free) {
|
|
OSReport(VT_COL(RED, WHITE) "__osFree:二重解放(%08x)\n" VT_RST, ptr); // __osFree: double deallocation
|
|
OSPanic(__FILE__, 743, "");
|
|
return;
|
|
}
|
|
|
|
if (block->arena != arena && arena != NULL) {
|
|
OSReport(VT_COL(RED, WHITE) "__osFree:確保時と違う方法で解放しようとした (%08x:%08x)\n" VT_RST, arena, block->arena); // __osFree: attempt to release memory in a different arena from where it was allocated
|
|
OSPanic(__FILE__, 750, "");
|
|
return;
|
|
}
|
|
|
|
next = get_block_next(block);
|
|
prev = get_block_prev(block);
|
|
block->free = TRUE;
|
|
setDebugInfo(block, NULL, 0, arena);
|
|
if (arena->flags & OSArena_FLAG_CLEAR_MEM_ON_FREE) {
|
|
memset(OS_MALLOC_BLOCK2DATA(block), 0xEF, block->size);
|
|
}
|
|
|
|
if (next == OS_MALLOC_NEXTMEMBLOCK(block)) {
|
|
if (next->free) {
|
|
temp = get_block_next(next);
|
|
if (temp != NULL) {
|
|
temp->prev = block;
|
|
}
|
|
|
|
block->size += next->size + sizeof(OSMemBlock);
|
|
if (arena->flags & OSArena_FLAG_CLEAR_MEM_ON_FREE) {
|
|
memset(next, 0xEF, sizeof(OSMemBlock));
|
|
}
|
|
block->next = temp;
|
|
next = temp;
|
|
}
|
|
}
|
|
|
|
if (prev != NULL && prev->free && block == OS_MALLOC_NEXTMEMBLOCK(prev)) {
|
|
if (next != NULL) {
|
|
next->prev = prev;
|
|
}
|
|
|
|
prev->next = next;
|
|
prev->size += block->size + sizeof(OSMemBlock);
|
|
if (arena->flags & OSArena_FLAG_CLEAR_MEM_ON_FREE) {
|
|
memset(block, 0xEF, sizeof(OSMemBlock));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
extern void __osFree(OSArena* arena, void* ptr) {
|
|
arena_lock(arena);
|
|
__osFree_NoLock(arena, ptr);
|
|
arena_unlock(arena);
|
|
}
|
|
|
|
// @fabricated, most likely suspect from DnM+'s symbol map
|
|
static void* __osFree_NoLock_DEBUG(OSArena* arena, void* ptr) {
|
|
// __osFree: irregular deallocation
|
|
OSReport(VT_COL(RED, WHITE) "__osFree:不正解放(%08x) [%s:%d ]\n" VT_RST);
|
|
|
|
// __osFree: double deallocation
|
|
OSReport(VT_COL(RED, WHITE) "__osFree:二重解放(%08x) [%s:%d ]\n" VT_RST);
|
|
}
|
|
|
|
#pragma force_active on
|
|
extern void* __osRealloc(OSArena* arena, void* ptr, u32 size) {
|
|
void* new_ptr;
|
|
OSMemBlock* orig_block;
|
|
OSMemBlock* next;
|
|
OSMemBlock* temp;
|
|
OSMemBlock* new_next;
|
|
u32 full_size;
|
|
u32 need_size;
|
|
|
|
orig_block = OS_MALLOC_DATA2BLOCK(ptr);
|
|
size = ALIGN_NEXT(size, 32);
|
|
full_size = ALIGN_NEXT(size, 32) + sizeof(OSMemBlock);
|
|
|
|
arena_lock(arena);
|
|
|
|
if (ptr == NULL) {
|
|
ptr = __osMalloc_NoLock(arena, size);
|
|
} else if (size == 0) {
|
|
__osFree_NoLock(arena, ptr);
|
|
ptr = NULL;
|
|
} else if (size != orig_block->size) {
|
|
if (size > orig_block->size) {
|
|
next = get_block_next(orig_block);
|
|
need_size = size - orig_block->size;
|
|
if (next == OS_MALLOC_NEXTMEMBLOCK(orig_block) && next->free && next->size >= need_size) {
|
|
OSMemBlock* new_next = (OSMemBlock*)((u32)next + need_size);
|
|
next->size -= need_size;
|
|
temp = get_block_next(next);
|
|
if (temp != NULL) {
|
|
temp->prev = new_next;
|
|
}
|
|
orig_block->next = new_next;
|
|
orig_block->size = size;
|
|
memmove(new_next, next, sizeof(OSMemBlock));
|
|
} else {
|
|
new_ptr = __osMalloc_NoLock(arena, size);
|
|
if (new_ptr != NULL) {
|
|
memmove(new_ptr, ptr, orig_block->size);
|
|
__osFree_NoLock(arena, ptr);
|
|
}
|
|
ptr = new_ptr;
|
|
}
|
|
} else if (size < orig_block->size) {
|
|
next = get_block_next(orig_block);
|
|
if (next != NULL && next->free) {
|
|
OSMemBlock* new_next = (OSMemBlock*)((u32)orig_block + full_size);
|
|
*new_next = *next;
|
|
new_next->size += orig_block->size - size;
|
|
orig_block->next = new_next;
|
|
orig_block->size = size;
|
|
temp = get_block_next(new_next);
|
|
if (temp != NULL) {
|
|
temp->prev = new_next;
|
|
}
|
|
} else if (size + sizeof(OSMemBlock) < orig_block->size) {
|
|
new_next = (OSMemBlock*)((u32)orig_block + full_size);
|
|
new_next->next = get_block_next(orig_block);
|
|
new_next->prev = orig_block;
|
|
new_next->size = orig_block->size - full_size;
|
|
new_next->free = TRUE;
|
|
new_next->magic = OS_MALLOC_MAGIC;
|
|
orig_block->next = new_next;
|
|
orig_block->size = size;
|
|
temp = get_block_next(new_next);
|
|
if (temp != NULL) {
|
|
temp->prev = new_next;
|
|
}
|
|
} else {
|
|
ptr = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
arena_unlock(arena);
|
|
return ptr;
|
|
}
|
|
#pragma force_active reset
|
|
|
|
static int __osAnalyzeArena(OSArena* arena, u32* ptr) {
|
|
OSMemBlock* block;
|
|
u32 max_free_block_size = 0;
|
|
u32 free_blocks_size = 0;
|
|
u32 free_blocks = 0;
|
|
u32 used_blocks_size = 0;
|
|
u32 used_blocks = 0;
|
|
|
|
if (arena == NULL || ptr == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
arena_lock(arena);
|
|
|
|
for (block = arena->head; block != NULL; block = get_block_next(block)) {
|
|
if (block->free) {
|
|
free_blocks++;
|
|
free_blocks_size += block->size;
|
|
if (max_free_block_size < block->size) {
|
|
max_free_block_size = block->size;
|
|
}
|
|
} else {
|
|
used_blocks++;
|
|
used_blocks_size += block->size;
|
|
}
|
|
}
|
|
|
|
ptr[0] = max_free_block_size;
|
|
ptr[1] = free_blocks_size;
|
|
ptr[2] = free_blocks;
|
|
ptr[3] = used_blocks_size;
|
|
ptr[4] = used_blocks;
|
|
|
|
arena_unlock(arena);
|
|
return 0;
|
|
}
|
|
|
|
extern void __osGetFreeArena(OSArena* arena, u32* max_free_block_size, u32* free_blocks_size, u32* used_blocks_size) {
|
|
u32 data[5];
|
|
|
|
if (__osAnalyzeArena(arena, data) == 0) {
|
|
if (max_free_block_size != NULL) {
|
|
*max_free_block_size = data[0];
|
|
}
|
|
|
|
if (free_blocks_size != NULL) {
|
|
*free_blocks_size = data[1];
|
|
}
|
|
|
|
if (used_blocks_size != NULL) {
|
|
*used_blocks_size = data[3];
|
|
}
|
|
}
|
|
}
|
|
|
|
extern u32 __osGetTotalFreeSize(OSArena* arena) {
|
|
u32 total_free_size;
|
|
|
|
__osGetFreeArena(arena, NULL, &total_free_size, NULL);
|
|
return total_free_size;
|
|
}
|
|
|
|
#pragma force_active on
|
|
extern u32 __osGetFreeSize(OSArena* arena) {
|
|
u32 free_size;
|
|
|
|
__osGetFreeArena(arena, &free_size, NULL, NULL);
|
|
return free_size;
|
|
}
|
|
#pragma force_active reset
|
|
|
|
extern s32 __osGetMemBlockSize(OSArena* arena, void* ptr) {
|
|
OSMemBlock* block;
|
|
|
|
if (ptr == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
block = OS_MALLOC_DATA2BLOCK(ptr);
|
|
if (OS_MALLOC_BLOCK_OK(block)) {
|
|
return block->size;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
extern void __osDisplayArena(OSArena* arena) {
|
|
OSMemBlock* block;
|
|
OSMemBlock* next;
|
|
u32 max_free;
|
|
u32 total_free;
|
|
u32 total_used;
|
|
|
|
if (__osMallocIsInitalized(arena)) {
|
|
arena_lock(arena);
|
|
max_free = 0;
|
|
total_free = 0;
|
|
total_used = 0;
|
|
|
|
// Arena Contents
|
|
OSReport("アリーナの内容 (0x%08x)\n", arena);
|
|
// Memory block span | status | size | [time s ms us ns: TID:src:line]
|
|
OSReport("メモリブロック範囲 status サイズ [時刻 s ms us ns: TID:src:行]\n");
|
|
|
|
block = arena->head;
|
|
while (block != NULL) {
|
|
if (OS_MALLOC_BLOCK_OK(block)) {
|
|
next = block->next;
|
|
OSReport("%08x-%08x%c %s %08x", (u32)block, (u32)block + sizeof(OSMemBlock) + block->size, next == NULL ? '$' : (next->prev != block ? '!' : ' '), block->free ? "空き" : "確保", block->size);
|
|
if (!block->free) {
|
|
// 空き = free, 確保 = used
|
|
OSReport(" [%016llu:%2d:%s:%d]", OSTicksToMicroseconds((u64)block->time * 1000), block->threadId, block->file != NULL ? block->file : "**NULL**", block->line);
|
|
}
|
|
OSReport("\n");
|
|
if (block->free) {
|
|
total_free += block->size;
|
|
if (max_free < block->size) {
|
|
max_free = block->size;
|
|
}
|
|
} else {
|
|
total_used += block->size;
|
|
}
|
|
} else {
|
|
OSReport("%08x Block Invalid\n", block);
|
|
next = NULL;
|
|
}
|
|
|
|
block = next;
|
|
}
|
|
|
|
// Total used memblock size: 0x%08x bytes
|
|
OSReport("確保ブロックサイズの合計 0x%08x バイト\n", total_used);
|
|
// Total free memblock size: 0x%08x bytes
|
|
OSReport("空きブロックサイズの合計 0x%08x バイト\n", total_free);
|
|
// Largest free block size: %08x bytes
|
|
OSReport("最大空きブロックサイズ 0x%08x バイト\n", max_free);
|
|
arena_unlock(arena);
|
|
}
|
|
}
|
|
|
|
#pragma force_active on
|
|
extern int __osCheckArena(OSArena* arena) {
|
|
int ret = FALSE;
|
|
OSMemBlock* block;
|
|
|
|
arena_lock(arena);
|
|
block = arena->head;
|
|
while (block != NULL) {
|
|
if (!OS_MALLOC_BLOCK_OK(block)) {
|
|
// Oops!!
|
|
OSReport(VT_COL(RED, WHITE) "おおっと!! (%08x %08x)\n" VT_RST, block, block->magic);
|
|
OSPanic(__FILE__, 1307, "");
|
|
ret = TRUE;
|
|
break;
|
|
}
|
|
|
|
block = get_block_next(block);
|
|
}
|
|
arena_unlock(arena);
|
|
return ret;
|
|
}
|
|
#pragma force_active reset
|