* Made a class out of free_chunk.

* Fixed realloc() - "size" wasn't what I thought it would be.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34412 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2009-12-01 15:39:55 +00:00
parent 86a3b75e8a
commit 943bec1287
+108 -86
View File
@@ -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,30 +73,41 @@ const static uint32 kAlignment = 4;
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 @@ free_chunk::Split(uint32 splitSize)
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 @@ free_chunk::IsTouching(free_chunk* chunk)
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,12 +229,9 @@ heap_init(stage2_args* args)
// 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;
sFreeAnchor.size = 0;
sFreeAnchor.next = chunk;
FreeChunk* chunk = (FreeChunk*)base;
chunk->SetTo(sMaxHeapSize, NULL);
sFreeAnchor.SetTo(0, chunk);
return B_OK;
}
@@ -239,14 +258,15 @@ grow_heap(uint32 bytes)
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 @@ malloc(size_t size)
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 @@ malloc(size_t size)
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 @@ malloc(size_t size)
} else {
// remove the chunk from the free list
last->next = chunk->next;
last->SetNext(chunk->Next());
}
sAvailable -= size + sizeof(uint32);
@@ -320,18 +340,18 @@ realloc(void* oldBuffer, size_t newSize)
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 @@ free(void* allocated)
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 @@ free(void* allocated)
}
last = chunk;
chunk = chunk->next;
chunk = chunk->Next();
}
// enqueue the link at the right position; the