/**************************************************************************** * Copyright (C) 2013 FIX94 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . ****************************************************************************/ #include #include #include "mem_manager.hpp" #include "gecko/gecko.hpp" #include "loader/utils.h" static const u32 MEM_BLOCK_SIZE = 0x80; MemManager::MemManager() { startAddr = NULL; memList = NULL; memListEnd = NULL; memSize = 0; LWP_MutexInit(&memMutex, 0); } MemManager::~MemManager() { LWP_MutexDestroy(memMutex); } void MemManager::Init(u8 *start, u8 *list, u32 size) { LWP_MutexLock(memMutex); //gprintf("Init %x %i\n", memList, memSize); startAddr = start; memList = list; memSize = ALIGN(MEM_BLOCK_SIZE, size) / MEM_BLOCK_SIZE; memListEnd = list + memSize; memset(memList, MEM_FREE , memSize); memset(memListEnd, MEM_END, 1); //thats the +1 LWP_MutexUnlock(memMutex); } void MemManager::ClearMem() { LWP_MutexLock(memMutex); //gprintf("ClearMem %x %i\n", startAddr, memSize * MEM_BLOCK_SIZE); u32 MemFull = memSize * MEM_BLOCK_SIZE; memset(startAddr, 0, MemFull); LWP_MutexUnlock(memMutex); } void *MemManager::Alloc(u32 size) { size = ALIGN(MEM_BLOCK_SIZE, size) / MEM_BLOCK_SIZE; if(size > memSize) return NULL; LWP_MutexLock(memMutex); vu8 *tmp_block; u32 blocksFree; for(vu8 *block = memList; block < memListEnd; block++) { for( ; *block & (ALLOC_USED | ALLOC_END); block++) ; blocksFree = 0; for(tmp_block = block; *tmp_block == MEM_FREE; tmp_block++) { blocksFree++; if(blocksFree == size) { u8 *addr = (u8*)block; memset(addr, ALLOC_USED, blocksFree - 1); //start blocks memset(addr + blocksFree - 1, ALLOC_END, 1); //end block void *ptr = (void*)(startAddr + ((addr - memList)*MEM_BLOCK_SIZE)); //gprintf("Alloc %x mem, %i blocks\n", ptr, blocksFree); LWP_MutexUnlock(memMutex); return ptr; } } block = tmp_block; } LWP_MutexUnlock(memMutex); return NULL; } void MemManager::Free(void *mem) { vu8 *blockUsed = memList+(((u8*)mem-startAddr) / MEM_BLOCK_SIZE); if(blockUsed < memList || blockUsed >= memListEnd || *blockUsed == 0) return; LWP_MutexLock(memMutex); //gprintf("Free %x mem, %x block\n", mem, blockUsed); u32 size = 0; vu8 *tmp_block = blockUsed; for( ; *tmp_block == ALLOC_USED; tmp_block++) size++; if(*tmp_block == ALLOC_END) size++; u8 *addr = (u8*)blockUsed; memset(addr, MEM_FREE, size); LWP_MutexUnlock(memMutex); } u32 MemManager::MemBlockSize(void *mem) { vu8 *blockUsed = memList+(((u8*)mem-startAddr) / MEM_BLOCK_SIZE); if(blockUsed < memList || blockUsed >= memListEnd || *blockUsed == 0) return 0; LWP_MutexLock(memMutex); u32 size = 0; for( ; *blockUsed == ALLOC_USED; blockUsed++) size++; if(*blockUsed == ALLOC_END) size++; size *= MEM_BLOCK_SIZE; LWP_MutexUnlock(memMutex); return size; } u32 MemManager::FreeSize() { LWP_MutexLock(memMutex); u32 free = 0; for(vu8 *block = memList; block < memListEnd; block++) { for( ; *block == MEM_FREE; block++) free++; } free *= MEM_BLOCK_SIZE; LWP_MutexUnlock(memMutex); return free; } void *MemManager::ReAlloc(void *mem, u32 size) { if(mem == NULL) return Alloc(size); //gprintf("Realloc %x, %i\n", mem, size); void *new_m = Alloc(size); if(new_m == NULL) { Free(mem); return NULL; } const u32 copysize = std::min(MemBlockSize(mem), size); LWP_MutexLock(memMutex); memcpy(new_m, mem, copysize); LWP_MutexUnlock(memMutex); Free(mem); return new_m; }