Author: axeld Date: 2009-12-01 16:39:55 +0100 (Tue, 01 Dec 2009) New Revision: 34412 Changeset: http://dev.haiku-os.org/changeset/34412/haiku Modified: haiku/trunk/src/system/boot/loader/heap.cpp Log: * Made a class out of free_chunk. * Fixed realloc() - "size" wasn't what I thought it would be. Modified: haiku/trunk/src/system/boot/loader/heap.cpp =================================================================== --- haiku/trunk/src/system/boot/loader/heap.cpp 2009-12-01 15:36:27 UTC (rev 34411) +++ haiku/trunk/src/system/boot/loader/heap.cpp 2009-12-01 15:39:55 UTC (rev 34412) @@ -42,19 +42,29 @@ #define DEBUG_ALLOCATIONS // if defined, freed memory is filled with 0xcc -struct free_chunk { - uint32 size; - free_chunk* next; +class FreeChunk { +public: + void SetTo(size_t size, FreeChunk* next); - uint32 Size() const; - free_chunk* Split(uint32 splitSize); - bool IsTouching(free_chunk* link); - free_chunk* Join(free_chunk* link); - void Remove(free_chunk* previous = NULL); - void Enqueue(); + uint32 Size() const; + uint32 CompleteSize() const { return fSize; } - void* AllocatedAddress() const; - static free_chunk* SetToAllocated(void* allocated); + FreeChunk* Next() const { return fNext; } + void SetNext(FreeChunk* next) { fNext = next; } + + FreeChunk* Split(uint32 splitSize); + bool IsTouching(FreeChunk* link); + FreeChunk* Join(FreeChunk* link); + void Remove(FreeChunk* previous = NULL); + void Enqueue(); + + void* AllocatedAddress() const; + static FreeChunk* SetToAllocated(void* allocated); + static addr_t NextOffset() { return sizeof(uint32); } + +private: + uint32 fSize; + FreeChunk* fNext; }; @@ -63,31 +73,42 @@ static void* sHeapBase; static uint32 /*sHeapSize,*/ sMaxHeapSize, sAvailable; -static free_chunk sFreeAnchor; +static FreeChunk sFreeAnchor; +void +FreeChunk::SetTo(size_t size, FreeChunk* next) +{ + fSize = size; + fNext = next; +} + + /*! Returns the amount of bytes that can be allocated in this chunk. */ uint32 -free_chunk::Size() const +FreeChunk::Size() const { - return size - sizeof(uint32); + return fSize - FreeChunk::NextOffset(); } /*! Splits the upper half at the requested location and returns it. */ -free_chunk* -free_chunk::Split(uint32 splitSize) +FreeChunk* +FreeChunk::Split(uint32 splitSize) { - free_chunk* chunk = (free_chunk*)((uint8*)this + sizeof(uint32) + splitSize); - chunk->size = size - splitSize - sizeof(uint32); - chunk->next = next; + splitSize = (splitSize - 1 + kAlignment) & ~(kAlignment - 1); - size = splitSize + sizeof(uint32); + FreeChunk* chunk + = (FreeChunk*)((uint8*)this + FreeChunk::NextOffset() + splitSize); + chunk->fSize = fSize - splitSize - FreeChunk::NextOffset(); + chunk->fNext = fNext; + fSize = splitSize + FreeChunk::NextOffset(); + return chunk; } @@ -96,11 +117,11 @@ that they could be joined. */ bool -free_chunk::IsTouching(free_chunk* chunk) +FreeChunk::IsTouching(FreeChunk* chunk) { return chunk - && (((uint8*)this + size == (uint8*)chunk) - || (uint8*)chunk + chunk->size == (uint8*)this); + && (((uint8*)this + fSize == (uint8*)chunk) + || (uint8*)chunk + chunk->fSize == (uint8*)this); } @@ -108,77 +129,78 @@ to the new chunk - which will either be one of the two chunks. Note, the chunks must be joinable, or else this method - doesn't work correctly. Use free_chunk::IsTouching() + doesn't work correctly. Use FreeChunk::IsTouching() to check if this method can be applied. */ -free_chunk* -free_chunk::Join(free_chunk* chunk) +FreeChunk* +FreeChunk::Join(FreeChunk* chunk) { if (chunk < this) { - chunk->size += size; - chunk->next = next; + chunk->fSize += fSize; + chunk->fNext = fNext; return chunk; } - size += chunk->size; - next = chunk->next; + fSize += chunk->fSize; + fNext = chunk->fNext; return this; } void -free_chunk::Remove(free_chunk* previous) +FreeChunk::Remove(FreeChunk* previous) { if (previous == NULL) { // find the previous chunk in the list - free_chunk* chunk = sFreeAnchor.next; + FreeChunk* chunk = sFreeAnchor.fNext; while (chunk != NULL && chunk != this) { previous = chunk; - chunk = chunk->next; + chunk = chunk->fNext; } if (chunk == NULL) panic("try to remove chunk that's not in list"); } - previous->next = this->next; - this->next = NULL; + previous->fNext = fNext; + fNext = NULL; } void -free_chunk::Enqueue() +FreeChunk::Enqueue() { - free_chunk* chunk = sFreeAnchor.next; - free_chunk* last = &sFreeAnchor; - while (chunk && chunk->Size() < size) { + FreeChunk* chunk = sFreeAnchor.fNext; + FreeChunk* last = &sFreeAnchor; + while (chunk && chunk->Size() < fSize) { last = chunk; - chunk = chunk->next; + chunk = chunk->fNext; } - this->next = chunk; - last->next = this; + fNext = chunk; + last->fNext = this; #ifdef DEBUG_ALLOCATIONS - memset((uint8*)this + sizeof(free_chunk), 0xcc, this->size - sizeof(free_chunk)); + memset((uint8*)this + sizeof(FreeChunk), 0xde, + fSize - sizeof(FreeChunk)); #endif } void* -free_chunk::AllocatedAddress() const +FreeChunk::AllocatedAddress() const { - return (void*)&next; + return (void*)&fNext; } -free_chunk* -free_chunk::SetToAllocated(void* allocated) +FreeChunk* +FreeChunk::SetToAllocated(void* allocated) { - return (free_chunk*)((uint8*)allocated - sizeof(uint32)); + return (FreeChunk*)((uint8*)allocated - FreeChunk::NextOffset()); } @@ -207,13 +229,10 @@ // declare the whole heap as one chunk, and add it // to the free list - free_chunk* chunk = (free_chunk*)base; - chunk->size = sMaxHeapSize; - chunk->next = NULL; + FreeChunk* chunk = (FreeChunk*)base; + chunk->SetTo(sMaxHeapSize, NULL); + sFreeAnchor.SetTo(0, chunk); - sFreeAnchor.size = 0; - sFreeAnchor.next = chunk; - return B_OK; } @@ -239,14 +258,15 @@ void dump_chunks(void) { - free_chunk* chunk = sFreeAnchor.next; - free_chunk* last = &sFreeAnchor; + FreeChunk* chunk = sFreeAnchor.Next(); + FreeChunk* last = &sFreeAnchor; while (chunk != NULL) { last = chunk; printf("\t%p: chunk size = %ld, end = %p, next = %p\n", chunk, - chunk->size, (uint8*)chunk + chunk->size, chunk->next); - chunk = chunk->next; + chunk->Size(), (uint8*)chunk + chunk->CompleteSize(), + chunk->Next()); + chunk = chunk->Next(); } } #endif @@ -272,11 +292,11 @@ return NULL; } - free_chunk* chunk = sFreeAnchor.next; - free_chunk* last = &sFreeAnchor; + FreeChunk* chunk = sFreeAnchor.Next(); + FreeChunk* last = &sFreeAnchor; while (chunk && chunk->Size() < size) { last = chunk; - chunk = chunk->next; + chunk = chunk->Next(); } if (chunk == NULL) { @@ -285,13 +305,13 @@ return NULL; } - if (chunk->Size() > size + sizeof(free_chunk) + kAlignment) { + 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). - free_chunk* freeChunk = chunk->Split(size); - last->next = freeChunk; + FreeChunk* freeChunk = chunk->Split(size); + last->SetNext(freeChunk); // re-enqueue the free chunk at the correct position freeChunk->Remove(last); @@ -299,7 +319,7 @@ } else { // remove the chunk from the free list - last->next = chunk->next; + last->SetNext(chunk->Next()); } sAvailable -= size + sizeof(uint32); @@ -320,18 +340,18 @@ size_t copySize = newSize; if (oldBuffer != NULL) { - free_chunk* oldChunk = free_chunk::SetToAllocated(oldBuffer); + FreeChunk* oldChunk = FreeChunk::SetToAllocated(oldBuffer); // Check if the old buffer still fits, and if it makes sense to keep it - if (oldChunk->size >= newSize - && (oldChunk->size < 128 || newSize > oldChunk->size / 3)) { + if (oldChunk->Size() >= newSize + && (oldChunk->Size() < 128 || newSize > oldChunk->Size() / 3)) { TRACE("realloc(%p, %lu) old buffer is large enough\n", oldBuffer, newSize); return oldChunk->AllocatedAddress(); } - if (copySize > oldChunk->size) - copySize = oldChunk->size; + if (copySize > oldChunk->Size()) + copySize = oldChunk->Size(); } void* newBuffer = malloc(newSize); @@ -356,39 +376,41 @@ TRACE("free(%p)\n", allocated); - free_chunk* freedChunk = free_chunk::SetToAllocated(allocated); + FreeChunk* freedChunk = FreeChunk::SetToAllocated(allocated); #ifdef DEBUG_ALLOCATIONS - if (freedChunk->size > sMaxHeapSize) - panic("freed chunk %p clobbered (%lx)!\n", freedChunk, freedChunk->size); -{ - free_chunk* chunk = sFreeAnchor.next; - while (chunk) { - if (chunk->size > sMaxHeapSize || freedChunk == chunk) - panic("invalid chunk in free list, or double free\n"); - chunk = chunk->next; + if (freedChunk->CompleteSize() > sMaxHeapSize) { + panic("freed chunk %p clobbered (%lx)!\n", freedChunk, + freedChunk->Size()); } -} + { + FreeChunk* chunk = sFreeAnchor.Next(); + while (chunk) { + if (chunk->CompleteSize() > sMaxHeapSize || freedChunk == chunk) + panic("invalid chunk in free list, or double free\n"); + chunk = chunk->Next(); + } + } #endif - sAvailable += freedChunk->size; + sAvailable += freedChunk->CompleteSize(); // try to join the new free chunk with an existing one // it may be joined with up to two chunks - free_chunk* chunk = sFreeAnchor.next; - free_chunk* last = &sFreeAnchor; + FreeChunk* chunk = sFreeAnchor.Next(); + FreeChunk* last = &sFreeAnchor; 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->next = chunk->next; + freedChunk->SetNext(chunk->Next()); freedChunk = chunk->Join(freedChunk); // remove the joined chunk from the list - last->next = freedChunk->next; + last->SetNext(freedChunk->Next()); chunk = last; if (++joinCount == 2) @@ -396,7 +418,7 @@ } last = chunk; - chunk = chunk->next; + chunk = chunk->Next(); } // enqueue the link at the right position; the