void* rtm_alloc(rtm_pool* pool, size_t size) { if (pool == NULL) return malloc(size); if (pool->heap_base == NULL || size == 0) return NULL; MutexLocker _(&pool->lock); // align the size requirement to a kAlignment bytes boundary size = (size - 1 + kAlignment) & ~(size_t)(kAlignment - 1); if (size > pool->available) { TRACE("malloc(): Out of memory!\n"); return NULL; } FreeChunk* chunk = pool->free_anchor.Next(); FreeChunk* last = &pool->free_anchor; while (chunk && chunk->Size() < size) { last = chunk; chunk = chunk->Next(); } if (chunk == NULL) { // could not find a free chunk as large as needed TRACE("malloc(): Out of memory!\n"); return NULL; } if (chunk->Size() > size + sizeof(FreeChunk) + kAlignment) { // if this chunk is bigger than the requested size, // we split it to form two chunks (with a minimal // size of kAlignment allocatable bytes). FreeChunk* freeChunk = chunk->Split(size); last->SetNext(freeChunk); // re-enqueue the free chunk at the correct position freeChunk->Remove(pool, last); freeChunk->Enqueue(pool); } else { // remove the chunk from the free list last->SetNext(chunk->Next()); } pool->available -= size + sizeof(uint32); TRACE("malloc(%lu) -> %p\n", size, chunk->AllocatedAddress()); return chunk->AllocatedAddress(); }
void rtm_pool::Free(void* allocated) { FreeChunk* freedChunk = FreeChunk::SetToAllocated(allocated); available += freedChunk->CompleteSize(); // try to join the new free chunk with an existing one // it may be joined with up to two chunks FreeChunk* chunk = free_anchor.Next(); FreeChunk* last = &free_anchor; int32 joinCount = 0; while (chunk) { if (chunk->IsTouching(freedChunk)) { // almost "insert" it into the list before joining // because the next pointer is inherited by the chunk freedChunk->SetNext(chunk->Next()); freedChunk = chunk->Join(freedChunk); // remove the joined chunk from the list last->SetNext(freedChunk->Next()); chunk = last; if (++joinCount == 2) break; } last = chunk; chunk = chunk->Next(); } // enqueue the link at the right position; the // free link queue is ordered by size freedChunk->Enqueue(this); }