diff options
| author | Anghelo Carvajal <angheloalf95@gmail.com> | 2023-08-09 20:45:25 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-08-09 20:45:25 -0400 |
| commit | cfa703f013a1e595a418e47ac05df06e9ae4f9b8 (patch) | |
| tree | 6f22ff1f665ac5dfd8f62b321895f846af4bfab5 /src/boot/O2 | |
| parent | bd0c96e41818de39d243604f2a56bdee779956f2 (diff) | |
`malloc.c` (#42)
* malloc
* match
* bss
* Fix naming
* move __osMalloc to libc64 folder
* move headers to libc64 folder
Diffstat (limited to 'src/boot/O2')
| -rw-r--r-- | src/boot/O2/__osMalloc.c | 637 |
1 files changed, 0 insertions, 637 deletions
diff --git a/src/boot/O2/__osMalloc.c b/src/boot/O2/__osMalloc.c deleted file mode 100644 index e30509e..0000000 --- a/src/boot/O2/__osMalloc.c +++ /dev/null @@ -1,637 +0,0 @@ -#include "osmalloc.h" -#include "alignment.h" -#include "boot_functions.h" -#include "fault.h" -#include "libc/stdbool.h" -#include "libc/stddef.h" -#include "libc/stdint.h" -#include "macros.h" - -#define NODE_MAGIC (0x7373) -#define NODE_IS_VALID(node) (((node) != NULL) && ((node)->magic == NODE_MAGIC)) -#define NODE_GET_NEXT(node) (NODE_IS_VALID((node)->next) ? (node)->next : NULL) -#define NODE_GET_PREV(node) (NODE_IS_VALID((node)->prev) ? (node)->prev : NULL) - -OSMesg sArenaLockMsg[1]; - -void __osMallocAddBlock(Arena* arena, void* heap, size_t size); - -void arena_lock_init(Arena* arena) { - osCreateMesgQueue(&arena->lock, sArenaLockMsg, ARRAY_COUNT(sArenaLockMsg)); -} - -void arena_lock(Arena* arena) { - osSendMesg(&arena->lock, NULL, OS_MESG_BLOCK); -} - -void arena_unlock(Arena* arena) { - osRecvMesg(&arena->lock, NULL, OS_MESG_BLOCK); -} - -ArenaNode* search_last_block(Arena* arena) { - ArenaNode* last = NULL; - - if (arena != NULL) { - if (NODE_IS_VALID(arena->head)) { - ArenaNode* iter; - - iter = arena->head; - while (iter != NULL) { - last = iter; - iter = NODE_GET_NEXT(last); - } - } - } - - return last; -} - -/** - * Initializes \p arena to manage the memory region \p heap. - * - * @param arena The Arena to initialize. - * @param heap The memory region to use as heap space. - * @param size The size of the heap. - */ -void __osMallocInit(Arena* arena, void* heap, size_t size) { - bzero(arena, sizeof(Arena)); - - arena_lock_init(arena); - - __osMallocAddBlock(arena, heap, size); - arena->isInit = true; -} - -void __osMallocAddBlock(Arena* arena, void* heap, size_t size) { - ptrdiff_t diff; - s32 alignedSize; - ArenaNode* firstNode; - ArenaNode* lastNode; - - if (heap == NULL) { - return; - } - - firstNode = (ArenaNode*)ALIGN16((uintptr_t)heap); - diff = (uintptr_t)firstNode - (uintptr_t)heap; - alignedSize = ((s32)size - diff) & ~0xF; - - // If the size of the heap is smaller than sizeof(ArenaNode), then the initialization will silently fail - if (alignedSize <= (s32)sizeof(ArenaNode)) { - return; - } - - firstNode->next = NULL; - firstNode->prev = NULL; - firstNode->size = alignedSize - sizeof(ArenaNode); - firstNode->isFree = true; - firstNode->magic = NODE_MAGIC; - - arena_lock(arena); - - lastNode = search_last_block(arena); - - // Checks if there's already a block - if (lastNode == NULL) { - arena->head = firstNode; - arena->start = heap; - } else { - // Chain the existing block with the new one - firstNode->prev = lastNode; - lastNode->next = firstNode; - } - - arena_unlock(arena); -} - -/** - * Clears the whole \p arena, invalidating every allocated pointer to it. - * - * @param arena The Arena to clear. - */ -void __osMallocCleanup(Arena* arena) { - bzero(arena, sizeof(Arena)); -} - -/** - * Returns whether or not the \p arena has been initialized. - * - * @param arena The Arena to check. - * @return u8 `true` if the \p arena has been initialized. `false` otherwise. - */ -u8 __osMallocIsInitalized(Arena* arena) { - return arena->isInit; -} - -/** - * See the description of `__osMalloc`. - * - * The only difference is this function does not lock the arena, making it suitable for being reused from other - * functions of this file. - */ -void* __osMallocNoLock(Arena* arena, size_t size) { - ArenaNode* iter; - size_t blockSize; - void* alloc = NULL; - - size = ALIGN16(size); - blockSize = ALIGN16(size) + sizeof(ArenaNode); - - // Start iterating from the head of the arena. - iter = arena->head; - - // Iterate over the arena looking for a big enough space of memory. - while (iter != NULL) { - if (iter->isFree && (iter->size >= size)) { - - // If the block is larger than the requested size, then split it and just use the required size of the - // current block. - if (blockSize < iter->size) { - ArenaNode* newNode; - ArenaNode* next; - - newNode = (ArenaNode*)((uintptr_t)iter + blockSize); - newNode->next = NODE_GET_NEXT(iter); - - newNode->prev = iter; - newNode->size = iter->size - blockSize; - newNode->isFree = true; - newNode->magic = NODE_MAGIC; - - iter->next = newNode; - iter->size = size; - - next = NODE_GET_NEXT(newNode); - if (next != NULL) { - next->prev = newNode; - } - } - - iter->isFree = 0; - alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode)); - break; - } - - iter = NODE_GET_NEXT(iter); - } - - return alloc; -} - -/** - * Allocates at least \p size bytes of memory using the given \p arena. - * The block of memory will be allocated at the start of the first sufficiently large free block. - * - * - If there's not enough space in the given \p arena, this function will fail, returning `NULL`. - * - If \p size is zero, then an empty region of memory is returned. - * - * To avoid memory leaks, the returned pointer should be eventually deallocated using either `__osFree` or - * `__osRealloc`. - * - * @param[in, out] arena The specific Arena to be used for the allocation. - * @param[in] size The size in bytes that will be allocated. - * @return void* On success, the allocated area of the \p arena memory. Otherwise, `NULL`. - */ -void* __osMalloc(Arena* arena, size_t size) { - void* alloc; - - arena_lock(arena); - - alloc = __osMallocNoLock(arena, size); - - arena_unlock(arena); - - return alloc; -} - -/** - * Allocates at least \p size bytes of memory using the given \p arena. - * Unlike __osMalloc, the block of memory will be allocated from the end of the \p arena. - * - * - If there's not enough space in the given \p arena, this function will fail, returning `NULL`. - * - If \p size is zero, then an empty region of memory is returned. - * - * To avoid memory leaks, the returned pointer should be eventually deallocated using `__osFree` or `__osRealloc`. - * - * @param[in, out] arena The specific Arena to be used for the allocation. - * @param[in] size The size in bytes that will be allocated. - * @return void* On success, the allocated area of the \p arena memory. Otherwise, `NULL`. - */ -void* __osMallocR(Arena* arena, size_t size) { - ArenaNode* newNode; - ArenaNode* temp_a0; - ArenaNode* next; - ArenaNode* iter; - ArenaNode* alloc; - size_t blockSize; - - alloc = NULL; - size = ALIGN16(size); - blockSize = ALIGN16(size) + sizeof(ArenaNode); - - arena_lock(arena); - - // Start iterating from the last block of the arena. - iter = search_last_block(arena); - - // Iterate in reverse the arena looking for a big enough space of memory. - while (iter != NULL) { - if (iter->isFree && (iter->size >= size)) { - // If the block is larger than the requested size, then split it and just use the required size of the - // current block. - if (blockSize < iter->size) { - temp_a0 = (ArenaNode*)((uintptr_t)iter + (iter->size - size)); - - temp_a0->next = NODE_GET_NEXT(iter); - //! FAKE? - newNode = temp_a0; - newNode->prev = iter; - newNode->size = size; - newNode->magic = NODE_MAGIC; - - iter->next = newNode; - iter->size -= blockSize; - - next = NODE_GET_NEXT(newNode); - if (next != NULL) { - next->prev = newNode; - } - - iter = newNode; - } - - iter->isFree = false; - alloc = (void*)((uintptr_t)iter + sizeof(ArenaNode)); - break; - } - - iter = NODE_GET_PREV(iter); - } - - arena_unlock(arena); - - return alloc; -} - -/** - * See the description of `__osFree`. - * - * The only difference is this function does not lock the arena, making it suitable for being reused from other - * functions of this file. - */ -void __osFree_NoLock(Arena* arena UNUSED, void* ptr) { - ArenaNode* node; - ArenaNode* next; - ArenaNode* prev; - - if (ptr == NULL) { - return; - } - - node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode)); - - if ((node == NULL) || (node->magic != NODE_MAGIC) || node->isFree) { - return; - } - - next = NODE_GET_NEXT(node); - prev = NODE_GET_PREV(node); - - node->isFree = true; - - // Checks if the next node is contiguous to the current node and if it isn't currently allocated. Then merge the two - // nodes into one. - if (((uintptr_t)next == ((uintptr_t)node + node->size + sizeof(ArenaNode))) && next->isFree) { - ArenaNode* newNext; - - newNext = NODE_GET_NEXT(next); - - if (newNext != NULL) { - newNext->prev = node; - } - - node->size += next->size + sizeof(ArenaNode); - node->next = newNext; - - next = newNext; - } - - // Checks if the previous node is contiguous to the current node and if it isn't currently allocated. Then merge the - // two nodes into one. - if ((prev != NULL) && prev->isFree && ((uintptr_t)node == ((uintptr_t)prev + prev->size + sizeof(ArenaNode)))) { - if (next != NULL) { - next->prev = prev; - } - - prev->next = next; - prev->size += node->size + sizeof(ArenaNode); - } -} - -/** - * Deallocates the pointer \p ptr previously allocated by `__osMalloc`, `__osMallocR` or `__osRealloc`. - * If \p ptr is `NULL` or it has been already been freed, then this function does nothing. - * - * - The behaviour is undefined if \p ptr is not a memory region returned by one of the cited allocating - * functions. - * - The behaviour is undefined if \p ptr doesn't correspond to the given \p arena. - * - Any access to the freed pointer is undefined behaviour. - * - * @param[in, out] arena The specific Arena to be used for the allocation. - * @param[in, out] ptr The allocated memory block to deallocate. - */ -void __osFree(Arena* arena, void* ptr) { - arena_lock(arena); - - __osFree_NoLock(arena, ptr); - - arena_unlock(arena); -} - -/** - * Reallocates the pointer \p ptr. - * \p ptr must be either a pointer previously allocated by `__osMalloc`, `__osMallocR` or `__osRealloc` and - * not freed yet, or a `NULL` pointer. - * - * - If \p ptr is `NULL` a new pointer is allocated. See `__osMalloc` for more details. - * - If \p newSize is 0, then the given pointer is freed and `NULL` is returned. See `__osFree` for more details. - * - If \p newSize is the same than the currently allocated pointer then the original unmodified pointer is returned. - * - If \p newSize is bigger than the currently allocated allocated pointer, then the area of memory is expanded to a - * size big enough to fit the requested size. - * - If \p newSize is smaller than the currently allocated allocated pointer, then the area of memory is shrinked to an - * smaller size. - * - * Resizing the allocated space of the passed may fail, in which case `NULL` is returned. - * - * - The behaviour is undefined if \p ptr is not a memory region returned by one of the cited allocating - * functions. - * - The behaviour is undefined if \p ptr doesn't correspond to the given \p arena. - * - If the pointer is freed, then any access to the original freed pointer is undefined behaviour. - * - * @param[in, out] arena The specific Arena to be used for the allocation. - * @param[in, out] ptr The allocated memory block to deallocate. - * @param[in] newSize The new requested size. - * @return void* On success, the pointer to the reallocated area of memory. On failure, `NULL` is returned, - * and the original parameter \p ptr remains valid. - */ -void* __osRealloc(Arena* arena, void* ptr, size_t newSize) { - newSize = ALIGN16(newSize); - - osSyncPrintf("__osRealloc(%08x, %d)\n", ptr, newSize); - - arena_lock(arena); - - if (ptr == NULL) { - // if the `ptr` is NULL, then allocate a new pointer with the specified size - // if newSize is 0, then __osMalloc would return a NULL pointer - - ptr = __osMallocNoLock(arena, newSize); - } else if (newSize == 0) { - // if the requested size is zero, then free the pointer - __osFree_NoLock(arena, ptr); - ptr = NULL; - } else { - ArenaNode* node; - ArenaNode* nextAux; - ArenaNode* next; // sp64 - s32 pad UNUSED; - ArenaNode* var_v0; - s32 fullNodeSize; - ArenaNode* var_a1_2; // sp54 - size_t sizeDiff; // sp50 - - // Gets the start of the ArenaNode pointer embedded - node = (ArenaNode*)((uintptr_t)ptr - sizeof(ArenaNode)); - - if (newSize == node->size) { - // If the requested size is the same as the already allocated one then do nothing. - - // "Do nothing because the memory block size doesn't change" - osSyncPrintf("メモリブロックサイズが変わらないためなにもしません\n"); - } else if (node->size < newSize) { - // The requested size is bigger than the already allocated one. - - next = NODE_GET_NEXT(node); - sizeDiff = newSize - node->size; - - // Checks if the next node is contiguous to the current allocated node and it has enough space to fit the - // new requested size - if (((uintptr_t)next == ((uintptr_t)node + node->size + sizeof(ArenaNode))) && next->isFree && - (next->size >= sizeDiff)) { - // "Join because there is a free block after the current memory block" - osSyncPrintf("現メモリブロックの後ろにフリーブロックがあるので結合します\n"); - - next->size -= sizeDiff; - - nextAux = NODE_GET_NEXT(next); - if (nextAux != NULL) { - nextAux->prev = (ArenaNode*)((uintptr_t)next + sizeDiff); - } - - node->next = (ArenaNode*)((uintptr_t)next + sizeDiff); - node->size = newSize; - func_8003BA60_jp(node->next, next, sizeof(ArenaNode)); - } else { - // Create a new pointer and manually copy the data from the old pointer to the new one. - void* newPtr; - - // "Allocate a new memory block and move the contents" - osSyncPrintf("新たにメモリブロックを確保して内容を移動します\n"); - - newPtr = __osMallocNoLock(arena, newSize); - if (newPtr != NULL) { - bcopy(ptr, newPtr, node->size); - __osFree_NoLock(arena, ptr); - } - ptr = newPtr; - } - } else if (newSize < node->size) { - // The requested size is smaller than the already allocated one. - - ArenaNode sp3C; - ArenaNode* temp_v1_2; - s32 pad2 UNUSED; - - var_a1_2 = NODE_GET_NEXT(node); - - if ((var_a1_2 != NULL) && var_a1_2->isFree) { - // Decrease the size of the allocated pointer and pass that size to the next node. - - // "Increase the free block behind the current memory block" - osSyncPrintf("現メモリブロックの後ろのフリーブロックを大きくしました\n"); - - fullNodeSize = ALIGN16(newSize) + sizeof(ArenaNode); - temp_v1_2 = (ArenaNode*)((uintptr_t)node + fullNodeSize); - - sp3C = *var_a1_2; - *temp_v1_2 = sp3C; - - temp_v1_2->size += node->size - newSize; - node->next = temp_v1_2; - node->size = newSize; - - var_v0 = NODE_GET_NEXT(temp_v1_2); - if (var_v0 != NULL) { - var_v0->prev = temp_v1_2; - } - } else if (newSize + sizeof(ArenaNode) < node->size) { - // Create a new node after the current one to allow shrinking it. - - // "Create because there is no free block after the current memory block" - osSyncPrintf("現メモリブロックの後ろにフリーブロックがないので生成します\n"); - - fullNodeSize = ALIGN16(newSize) + sizeof(ArenaNode); - temp_v1_2 = (ArenaNode*)((uintptr_t)node + fullNodeSize); - - temp_v1_2->next = NODE_GET_NEXT(node); - - temp_v1_2->prev = node; - temp_v1_2->size = node->size - fullNodeSize; - temp_v1_2->isFree = true; - temp_v1_2->magic = NODE_MAGIC; - - node->next = temp_v1_2; - node->size = newSize; - - var_v0 = NODE_GET_NEXT(temp_v1_2); - if (var_v0 != NULL) { - var_v0->prev = temp_v1_2; - } - } else { - // "Not enough space to generate free blocks" - osSyncPrintf("フリーブロック生成するだけの空きがありません\n"); - ptr = NULL; - } - } - } - - arena_unlock(arena); - - return ptr; -} - -/** - * Gets the size of the largest free block, the total free space and the total allocated space. - * - * @param[in, out] arena The Arena which will be used to get the values from. - * @param[out] outMaxFree The size of the largest free block. - * @param[out] outFree The total free space. - * @param[out] outAlloc The total allocated space. - */ -void __osGetFreeArena(Arena* arena, size_t* outMaxFree, size_t* outFree, size_t* outAlloc) { - ArenaNode* iter; - - arena_lock(arena); - - *outMaxFree = 0; - *outFree = 0; - *outAlloc = 0; - - iter = arena->head; - while (iter != NULL) { - if (iter->isFree) { - *outFree += iter->size; - if (*outMaxFree < iter->size) { - *outMaxFree = iter->size; - } - } else { - *outAlloc += iter->size; - } - - iter = NODE_GET_NEXT(iter); - } - - arena_unlock(arena); -} - -/** - * Fault Client for an Arena. Reports information about the state of the Arena in the crash debugger. - */ -void ArenaImpl_FaultClient(Arena* arena) { - ArenaNode* iter; - ArenaNode* next; - size_t allocated; - size_t free; - size_t largestFree; - - FaultDrawer_Printf("ARENA INFO (0x%08x)\n", arena); - - if (!__osMallocIsInitalized(arena)) { - FaultDrawer_Printf("Arena is uninitalized\n", arena); - return; - } - - largestFree = 0; - free = 0; - allocated = 0; - - FaultDrawer_Printf("Memory Block Region status size\n"); - - for (iter = arena->head; iter != NULL; iter = next) { - if (NODE_IS_VALID(iter)) { - next = iter->next; - - FaultDrawer_Printf("%08x-%08x%c %s %08x", iter, (uintptr_t)iter + iter->size + sizeof(ArenaNode), - (next == NULL) ? '$' : ((iter != next->prev) ? '!' : ' '), iter->isFree ? "F" : "A", - iter->size); - FaultDrawer_Printf("\n"); - if (iter->isFree) { - free += iter->size; - if (largestFree < iter->size) { - largestFree = iter->size; - } - } else { - allocated += iter->size; - } - } else { - FaultDrawer_SetFontColor(GPACK_RGBA5551(255, 0, 0, 1)); - FaultDrawer_Printf("%08x Block Invalid\n", iter); - next = NULL; - } - } - - FaultDrawer_SetFontColor(GPACK_RGBA5551(0, 255, 192, 1)); - FaultDrawer_Printf("Total Alloc Block Size %08x\n", allocated); - FaultDrawer_Printf("Total Free Block Size %08x\n", free); - FaultDrawer_Printf("Largest Free Block Size %08x\n", largestFree); -} - -/** - * Checks the validity of every node of the \p arena. - * - * @param arena The Arena to check. - * @return s32 `false` if every pointer is valid. `true` otherwise. - */ -s32 __osCheckArena(Arena* arena) { - ArenaNode* iter; - s32 err = false; - - arena_lock(arena); - - // "Checking the contents of the arena..." - osSyncPrintf("アリーナの内容をチェックしています... (%08x)\n", arena); - - iter = arena->head; - while (iter != NULL) { - //! @bug This condition should be inverted. Because of it, this function will report a valid Arena as being - //! faulty. - if (NODE_IS_VALID(iter)) { - // "Oops!!" - osSyncPrintf("おおっと!! (%08x %08x)\n", iter, iter->magic); - - err = true; - break; - } - - iter = NODE_GET_NEXT(iter); - } - - if (!err) { - // "Arena is still valid" - osSyncPrintf("アリーナはまだ、いけそうです\n"); - } - - arena_unlock(arena); - - return err; -} |
