Fix formatting and remove namespaces in libmaxsi heap.cpp.

What a mess.
This commit is contained in:
Jonas 'Sortie' Termansen 2012-09-26 19:56:28 +02:00
parent d81cdc09e9
commit 31df7c0c93
1 changed files with 586 additions and 597 deletions

View File

@ -54,41 +54,37 @@
typedef uintptr_t addr_t; typedef uintptr_t addr_t;
#endif #endif
namespace Maxsi //
{ // This first section is just magic compiler/platform stuff, you should
namespace Memory // skip ahead to the actual algorithm.
{ //
//
// This first section is just magic compiler/platform stuff, you should
// skip ahead to the actual algorithm.
//
#if defined(__x86_64__) #if defined(__x86_64__)
const size_t MAGIC = 0xDEADDEADDEADDEADUL; const size_t MAGIC = 0xDEADDEADDEADDEADUL;
const size_t ALIGNMENT = 16UL; const size_t ALIGNMENT = 16UL;
#else #else
const size_t MAGIC = 0xDEADDEADUL; const size_t MAGIC = 0xDEADDEADUL;
const size_t ALIGNMENT = 8UL; const size_t ALIGNMENT = 8UL;
#endif #endif
const size_t PAGESIZE = 4UL * 1024UL; // 4 KiB const size_t PAGESIZE = 4UL * 1024UL; // 4 KiB
const size_t NUMBINS = 8UL * sizeof(size_t); const size_t NUMBINS = 8UL * sizeof(size_t);
extern addr_t wilderness; extern addr_t wilderness;
#ifdef SORTIX_KERNEL #ifdef SORTIX_KERNEL
addr_t GetHeapStart() static addr_t GetHeapStart()
{ {
return Sortix::Memory::GetHeapUpper(); return Sortix::Memory::GetHeapUpper();
} }
size_t GetHeapMaxSize() static size_t GetHeapMaxSize()
{ {
return Sortix::Memory::GetHeapUpper() - Sortix::Memory::GetHeapLower(); return Sortix::Memory::GetHeapUpper() - Sortix::Memory::GetHeapLower();
} }
void FreeMemory(addr_t where, size_t bytes) static void FreeMemory(addr_t where, size_t bytes)
{ {
assert(Sortix::Page::IsAligned(where + bytes)); assert(Sortix::Page::IsAligned(where + bytes));
while ( bytes ) while ( bytes )
@ -99,10 +95,10 @@ namespace Maxsi
bytes -= PAGESIZE; bytes -= PAGESIZE;
where += PAGESIZE; where += PAGESIZE;
} }
} }
bool AllocateMemory(addr_t where, size_t bytes) static bool AllocateMemory(addr_t where, size_t bytes)
{ {
assert(Sortix::Page::IsAligned(where + bytes)); assert(Sortix::Page::IsAligned(where + bytes));
addr_t pos = where; addr_t pos = where;
@ -128,10 +124,10 @@ namespace Maxsi
} }
return true; return true;
} }
bool ExtendHeap(size_t bytesneeded) static bool ExtendHeap(size_t bytesneeded)
{ {
#ifdef HEAP_GROWS_DOWNWARDS #ifdef HEAP_GROWS_DOWNWARDS
addr_t newwilderness = wilderness - bytesneeded; addr_t newwilderness = wilderness - bytesneeded;
#else #else
@ -139,10 +135,10 @@ namespace Maxsi
#endif #endif
return AllocateMemory(newwilderness, bytesneeded); return AllocateMemory(newwilderness, bytesneeded);
} }
#else #else
addr_t GetHeapStart() static addr_t GetHeapStart()
{ {
addr_t base = (addr_t) sbrk(0); addr_t base = (addr_t) sbrk(0);
addr_t unaligned = base % ALIGNMENT; addr_t unaligned = base % ALIGNMENT;
if ( unaligned ) if ( unaligned )
@ -151,28 +147,28 @@ namespace Maxsi
} }
addr_t result = (addr_t) sbrk(0); addr_t result = (addr_t) sbrk(0);
return result; return result;
} }
size_t GetHeapMaxSize() static size_t GetHeapMaxSize()
{ {
// TODO: A bit of a hack! // TODO: A bit of a hack!
return SIZE_MAX; return SIZE_MAX;
} }
bool ExtendHeap(size_t bytesneeded) static bool ExtendHeap(size_t bytesneeded)
{ {
void* newheapend = sbrk(bytesneeded); void* newheapend = sbrk(bytesneeded);
return newheapend != (void*) -1UL; return newheapend != (void*) -1UL;
} }
#endif #endif
// TODO: BitScanForward and BitScanReverse are x86 instructions, but // TODO: BitScanForward and BitScanReverse are x86 instructions, but
// directly using them messes with the optimizer. Once possible, use // directly using them messes with the optimizer. Once possible, use
// the inline assembly instead of the C-version of the functions. // the inline assembly instead of the C-version of the functions.
// Returns the index of the most significant set bit. // Returns the index of the most significant set bit.
inline size_t BSR(size_t Value) inline size_t BSR(size_t Value)
{ {
#if 1 #if 1
assert(Value > 0); assert(Value > 0);
for ( size_t I = 8*sizeof(size_t); I > 0; I-- ) for ( size_t I = 8*sizeof(size_t); I > 0; I-- )
@ -185,11 +181,11 @@ namespace Maxsi
asm("bsr %0, %1" : "=r"(Result) : "r"(Value)); asm("bsr %0, %1" : "=r"(Result) : "r"(Value));
return Result; return Result;
#endif #endif
} }
// Returns the index of the least significant set bit. // Returns the index of the least significant set bit.
inline size_t BSF(size_t Value) inline size_t BSF(size_t Value)
{ {
#if 1 #if 1
assert(Value > 0); assert(Value > 0);
for ( size_t I = 0; I < 8*sizeof(size_t); I++ ) for ( size_t I = 0; I < 8*sizeof(size_t); I++ )
@ -202,46 +198,46 @@ namespace Maxsi
asm("bsf %0, %1" : "=r"(Result) : "r"(Value)); asm("bsf %0, %1" : "=r"(Result) : "r"(Value));
return Result; return Result;
#endif #endif
} }
// //
// Now for some helper functions and structures. // Now for some helper functions and structures.
// //
struct Chunk; struct Chunk;
struct Trailer; struct Trailer;
#ifdef SORTIX_KERNEL #ifdef SORTIX_KERNEL
Sortix::kthread_mutex_t heaplock; Sortix::kthread_mutex_t heaplock;
#endif #endif
// The location where the heap originally grows from. // The location where the heap originally grows from.
addr_t heapstart; addr_t heapstart;
// If heap grows down: Location of the first mapped page. // If heap grows down: Location of the first mapped page.
// If heap grows up: Location of the first not-mapped page. // If heap grows up: Location of the first not-mapped page.
addr_t wilderness; addr_t wilderness;
// How many bytes remain in the wilderness. // How many bytes remain in the wilderness.
size_t wildernesssize; size_t wildernesssize;
// How many bytes are the heap allow to grow to (including wilderness). // How many bytes are the heap allow to grow to (including wilderness).
size_t heapmaxsize; size_t heapmaxsize;
// How many bytes are currently used for chunks in the heap, which // How many bytes are currently used for chunks in the heap, which
// excludes the wilderness. // excludes the wilderness.
size_t heapsize; size_t heapsize;
// bins[N] contain a linked list of chunks that are at least 2^(N+1) // bins[N] contain a linked list of chunks that are at least 2^(N+1)
// bytes, but less than 2^(N+2) bytes. By selecting the proper bin in // bytes, but less than 2^(N+2) bytes. By selecting the proper bin in
// constant time, we can allocate chunks in constant time. // constant time, we can allocate chunks in constant time.
Chunk* bins[NUMBINS]; Chunk* bins[NUMBINS];
// Bit N is set if bin[N] contains a chunk. // Bit N is set if bin[N] contains a chunk.
size_t bincontainschunks; size_t bincontainschunks;
static bool IsGoodHeapPointer(void* ptr, size_t size) static bool IsGoodHeapPointer(void* ptr, size_t size)
{ {
uintptr_t ptrlower = (uintptr_t) ptr; uintptr_t ptrlower = (uintptr_t) ptr;
uintptr_t ptrupper = ptrlower + size; uintptr_t ptrupper = ptrlower + size;
#ifdef HEAP_GROWS_DOWNWARDS #ifdef HEAP_GROWS_DOWNWARDS
@ -252,12 +248,12 @@ namespace Maxsi
uintptr_t heapupper = wilderness; uintptr_t heapupper = wilderness;
#endif #endif
return heaplower <= ptrlower && ptrupper <= heapupper; return heaplower <= ptrlower && ptrupper <= heapupper;
} }
// A preamble to every chunk providing meta-information. // A preamble to every chunk providing meta-information.
struct Chunk struct Chunk
{ {
public: public:
size_t size; // Includes size of Chunk and Trailer size_t size; // Includes size of Chunk and Trailer
union union
{ {
@ -265,19 +261,19 @@ namespace Maxsi
Chunk* nextunused; Chunk* nextunused;
}; };
public: public:
bool IsUsed() { return magic == MAGIC; } bool IsUsed() { return magic == MAGIC; }
Trailer* GetTrailer(); Trailer* GetTrailer();
Chunk* LeftNeighbor(); Chunk* LeftNeighbor();
Chunk* RightNeighbor(); Chunk* RightNeighbor();
bool IsSane(); bool IsSane();
}; };
// A trailer ro every chunk providing meta-information. // A trailer to every chunk providing meta-information.
struct Trailer struct Trailer
{ {
public: public:
union union
{ {
size_t magic; size_t magic;
@ -285,45 +281,45 @@ namespace Maxsi
}; };
size_t size; // Includes size of Chunk and Trailer size_t size; // Includes size of Chunk and Trailer
public: public:
bool IsUsed() { return magic == MAGIC; } bool IsUsed() { return magic == MAGIC; }
Chunk* GetChunk(); Chunk* GetChunk();
}; };
const size_t OVERHEAD = sizeof(Chunk) + sizeof(Trailer); const size_t OVERHEAD = sizeof(Chunk) + sizeof(Trailer);
// This is how a real chunk actually looks: // This is how a real chunk actually looks:
//struct RealChunk //struct RealChunk
//{ //{
// Chunk header; // Chunk header;
// byte data[...]; // byte data[...];
// Trailer footer; // Trailer footer;
// }; // };
Trailer* Chunk::GetTrailer() Trailer* Chunk::GetTrailer()
{ {
return (Trailer*) (((addr_t) this) + size - sizeof(Trailer)); return (Trailer*) (((addr_t) this) + size - sizeof(Trailer));
} }
Chunk* Chunk::LeftNeighbor() Chunk* Chunk::LeftNeighbor()
{ {
Trailer* trailer = (Trailer*) (((addr_t) this) - sizeof(Trailer)); Trailer* trailer = (Trailer*) (((addr_t) this) - sizeof(Trailer));
return trailer->GetChunk(); return trailer->GetChunk();
} }
Chunk* Chunk::RightNeighbor() Chunk* Chunk::RightNeighbor()
{ {
return (Chunk*) (((addr_t) this) + size); return (Chunk*) (((addr_t) this) + size);
} }
Chunk* Trailer::GetChunk() Chunk* Trailer::GetChunk()
{ {
return (Chunk*) (((addr_t) this) + sizeof(Trailer) - size); return (Chunk*) (((addr_t) this) + sizeof(Trailer) - size);
} }
bool Chunk::IsSane() bool Chunk::IsSane()
{ {
if ( !IsGoodHeapPointer(this, sizeof(*this)) ) if ( !IsGoodHeapPointer(this, sizeof(*this)) )
return false; return false;
if ( !size ) { return false; } if ( !size ) { return false; }
@ -361,10 +357,10 @@ namespace Maxsi
} }
} }
return true; return true;
} }
void InsertChunk(Chunk* chunk) static void InsertChunk(Chunk* chunk)
{ {
// Insert the chunk into the right bin. // Insert the chunk into the right bin.
size_t binindex = BSR(chunk->size); size_t binindex = BSR(chunk->size);
chunk->GetTrailer()->prevunused = NULL; chunk->GetTrailer()->prevunused = NULL;
@ -377,10 +373,10 @@ namespace Maxsi
bins[binindex] = chunk; bins[binindex] = chunk;
bincontainschunks |= (1UL << binindex); bincontainschunks |= (1UL << binindex);
assert(chunk->IsSane()); assert(chunk->IsSane());
} }
bool ValidateHeap() static bool ValidateHeap()
{ {
bool foundbin[NUMBINS]; bool foundbin[NUMBINS];
for ( size_t i = 0; i < NUMBINS; i++ ) { foundbin[i] = false; } for ( size_t i = 0; i < NUMBINS; i++ ) { foundbin[i] = false; }
@ -415,14 +411,14 @@ namespace Maxsi
} }
return true; return true;
} }
// //
// This is where the actual memory allocation algorithm starts. // This is where the actual memory allocation algorithm starts.
// //
void Init() extern "C" void _init_heap()
{ {
heapstart = GetHeapStart(); heapstart = GetHeapStart();
heapmaxsize = GetHeapMaxSize(); heapmaxsize = GetHeapMaxSize();
heapsize = 0; heapsize = 0;
@ -433,18 +429,13 @@ namespace Maxsi
#ifdef SORTIX_KERNEL #ifdef SORTIX_KERNEL
heaplock = Sortix::KTHREAD_MUTEX_INITIALIZER; heaplock = Sortix::KTHREAD_MUTEX_INITIALIZER;
#endif #endif
} }
extern "C" void _init_heap() // Attempts to expand the wilderness such that it contains at least
{ // bytesneeded bytes. This is done by mapping new pages onto into the
Init(); // virtual address-space.
} static bool ExpandWilderness(size_t bytesneeded)
{
// Attempts to expand the wilderness such that it contains at least
// bytesneeded bytes. This is done by mapping new pages onto into the
// virtual address-space.
bool ExpandWilderness(size_t bytesneeded)
{
if ( bytesneeded <= wildernesssize ) { return true; } if ( bytesneeded <= wildernesssize ) { return true; }
bytesneeded -= wildernesssize; bytesneeded -= wildernesssize;
@ -475,10 +466,10 @@ namespace Maxsi
wilderness = newwilderness; wilderness = newwilderness;
return true; return true;
} }
extern "C" void* malloc(size_t size) extern "C" void* malloc(size_t size)
{ {
#ifdef SORTIX_KERNEL #ifdef SORTIX_KERNEL
Sortix::ScopedLock scopedlock(&heaplock); Sortix::ScopedLock scopedlock(&heaplock);
#endif #endif
@ -585,29 +576,29 @@ namespace Maxsi
addr_t result = ((addr_t) chunk) + sizeof(Chunk); addr_t result = ((addr_t) chunk) + sizeof(Chunk);
return (void*) result; return (void*) result;
} }
bool IsLeftmostChunk(Chunk* chunk) static bool IsLeftmostChunk(Chunk* chunk)
{ {
#ifdef HEAP_GROWS_DOWNWARDS #ifdef HEAP_GROWS_DOWNWARDS
return (addr_t) chunk <= wilderness + wildernesssize; return (addr_t) chunk <= wilderness + wildernesssize;
#else #else
return heapstart <= (addr_t) chunk; return heapstart <= (addr_t) chunk;
#endif #endif
} }
bool IsRightmostChunk(Chunk* chunk) static bool IsRightmostChunk(Chunk* chunk)
{ {
#ifdef HEAP_GROWS_DOWNWARDS #ifdef HEAP_GROWS_DOWNWARDS
return heapstart <= (addr_t) chunk + chunk->size; return heapstart <= (addr_t) chunk + chunk->size;
#else #else
return heapstart + heapsize <= (addr_t) chunk + chunk->size; return heapstart + heapsize <= (addr_t) chunk + chunk->size;
#endif #endif
} }
// Removes a chunk from its bin. // Removes a chunk from its bin.
void UnlinkChunk(Chunk* chunk) static void UnlinkChunk(Chunk* chunk)
{ {
assert(chunk->IsSane()); assert(chunk->IsSane());
Trailer* trailer = chunk->GetTrailer(); Trailer* trailer = chunk->GetTrailer();
if ( trailer->prevunused ) if ( trailer->prevunused )
@ -633,11 +624,11 @@ namespace Maxsi
if ( !bins[binindex] ) { bincontainschunks ^= 1UL << binindex; } if ( !bins[binindex] ) { bincontainschunks ^= 1UL << binindex; }
else { assert(bins[binindex]->IsSane()); } else { assert(bins[binindex]->IsSane()); }
} }
} }
// Transforms a chunk and its neighbors into a single chunk if possible. // Transforms a chunk and its neighbors into a single chunk if possible.
void UnifyNeighbors(Chunk** chunk) static void UnifyNeighbors(Chunk** chunk)
{ {
if ( !IsLeftmostChunk(*chunk) ) if ( !IsLeftmostChunk(*chunk) )
{ {
Chunk* neighbor = (*chunk)->LeftNeighbor(); Chunk* neighbor = (*chunk)->LeftNeighbor();
@ -662,10 +653,10 @@ namespace Maxsi
(*chunk)->GetTrailer()->size = (*chunk)->size; (*chunk)->GetTrailer()->size = (*chunk)->size;
} }
} }
} }
extern "C" void free(void* addr) extern "C" void free(void* addr)
{ {
#ifdef SORTIX_KERNEL #ifdef SORTIX_KERNEL
Sortix::ScopedLock scopedlock(&heaplock); Sortix::ScopedLock scopedlock(&heaplock);
#endif #endif
@ -700,20 +691,20 @@ namespace Maxsi
#if 2 <= PARANOIA #if 2 <= PARANOIA
assert(ValidateHeap()); assert(ValidateHeap());
#endif #endif
} }
extern "C" void* calloc(size_t nmemb, size_t size) extern "C" void* calloc(size_t nmemb, size_t size)
{ {
size_t total = nmemb * size; size_t total = nmemb * size;
void* result = malloc(total); void* result = malloc(total);
if ( !result ) { return NULL; } if ( !result ) { return NULL; }
memset(result, 0, total); memset(result, 0, total);
return result; return result;
} }
// TODO: Implement this function properly. // TODO: Implement this function properly.
extern "C" void* realloc(void* ptr, size_t size) extern "C" void* realloc(void* ptr, size_t size)
{ {
if ( !ptr ) { return malloc(size); } if ( !ptr ) { return malloc(size); }
Chunk* chunk = (Chunk*) ((addr_t) ptr - sizeof(Chunk)); Chunk* chunk = (Chunk*) ((addr_t) ptr - sizeof(Chunk));
assert(chunk->IsUsed()); assert(chunk->IsUsed());
@ -725,6 +716,4 @@ namespace Maxsi
memcpy(newptr, ptr, allocsize); memcpy(newptr, ptr, allocsize);
free(ptr); free(ptr);
return newptr; return newptr;
}
}
} }