X-Git-Url: https://git.ucc.asn.au/?a=blobdiff_plain;f=Kernel%2Fheap.c;h=4c0232e0eaaabbdc0fb8e3240e33b5338c879968;hb=05e8b329edc7c55eec967c3caba1982c173025e3;hp=682391877870d19d9e6b059139180bd16cc8697c;hpb=f119d0e5b18b7286d04fc536a94e0f96e3c51714;p=tpg%2Facess2.git diff --git a/Kernel/heap.c b/Kernel/heap.c index 68239187..4c0232e0 100644 --- a/Kernel/heap.c +++ b/Kernel/heap.c @@ -2,39 +2,45 @@ * AcessOS Microkernel Version * heap.c */ -#include +#include #include -#include +#include #define WARNINGS 1 +#define DEBUG_TRACE 0 // === CONSTANTS === -#define HEAP_BASE 0xE0800000 -#define HEAP_MAX 0xF0000000 // 120MiB, Plenty #define HEAP_INIT_SIZE 0x8000 // 32 KiB -#define BLOCK_SIZE (sizeof(void*)) // 8 Machine Words +#define MIN_SIZE (sizeof(void*))*8 // 8 Machine Words +#define POW2_SIZES 0 #define COMPACT_HEAP 0 // Use 4 byte header? #define FIRST_FIT 0 -#define MAGIC_FOOT 0x2ACE5505 -#define MAGIC_FREE 0xACE55000 -#define MAGIC_USED 0x862B0505 // MAGIC_FOOT ^ MAGIC_FREE +//#define MAGIC_FOOT 0x2ACE5505 +//#define MAGIC_FREE 0xACE55000 +//#define MAGIC_USED 0x862B0505 // MAGIC_FOOT ^ MAGIC_FREE +#define MAGIC_FOOT 0x544F4F46 // 'FOOT' +#define MAGIC_FREE 0x45455246 // 'FREE' +#define MAGIC_USED 0x44455355 // 'USED' // === PROTOTYPES === -void Heap_Install(); +void Heap_Install(void); void *Heap_Extend(int Bytes); void *Heap_Merge(tHeapHead *Head); -void *malloc(size_t Bytes); -void free(void *Ptr); -void Heap_Dump(); +void *Heap_Allocate(const char *File, int Line, size_t Bytes); +void *Heap_AllocateZero(const char *File, int Line, size_t Bytes); +void *Heap_Reallocate(const char *File, int Line, void *Ptr, size_t Bytes); +void Heap_Deallocate(void *Ptr); +void Heap_Dump(void); +void Heap_Stats(void); // === GLOBALS === - int giHeapSpinlock; +tMutex glHeap; void *gHeapStart; void *gHeapEnd; // === CODE === -void Heap_Install() +void Heap_Install(void) { gHeapStart = (void*)MM_KHEAP_BASE; gHeapEnd = (void*)MM_KHEAP_BASE; @@ -52,18 +58,18 @@ void *Heap_Extend(int Bytes) tHeapFoot *foot; // Bounds Check - if( (Uint)gHeapEnd == MM_KHEAP_MAX ) + if( (tVAddr)gHeapEnd == MM_KHEAP_MAX ) return NULL; // Bounds Check - if( (Uint)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) { - Bytes = MM_KHEAP_MAX - (Uint)gHeapEnd; + if( (tVAddr)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) { + Bytes = MM_KHEAP_MAX - (tVAddr)gHeapEnd; return NULL; } // Heap expands in pages for(i=0;i<(Bytes+0xFFF)>>12;i++) - MM_Allocate( (Uint)gHeapEnd+(i<<12) ); + MM_Allocate( (tVAddr)gHeapEnd+(i<<12) ); // Increas heap end gHeapEnd += i << 12; @@ -75,7 +81,6 @@ void *Heap_Extend(int Bytes) foot->Head = head; foot->Magic = MAGIC_FOOT; - //Log(" Heap_Extend: head = %p", head); return Heap_Merge(head); // Merge with previous block } @@ -96,7 +101,7 @@ void *Heap_Merge(tHeapHead *Head) // Merge Left (Down) foot = (void*)( (Uint)Head - sizeof(tHeapFoot) ); - if( ((Uint)foot < (Uint)gHeapEnd && (Uint)foot > HEAP_BASE) + if( ((Uint)foot < (Uint)gHeapEnd && (Uint)foot > (Uint)gHeapStart) && foot->Head->Magic == MAGIC_FREE) { foot->Head->Size += Head->Size; // Increase size thisFoot->Head = foot->Head; // Change backlink @@ -125,10 +130,12 @@ void *Heap_Merge(tHeapHead *Head) } /** - * \fn void *malloc(size_t Bytes) * \brief Allocate memory from the heap + * \param File Allocating source file + * \param Line Source line + * \param Bytes Size of region to allocate */ -void *malloc(size_t Bytes) +void *Heap_Allocate(const char *File, int Line, size_t Bytes) { tHeapHead *head, *newhead; tHeapFoot *foot, *newfoot; @@ -136,10 +143,15 @@ void *malloc(size_t Bytes) Uint bestSize = 0; // Speed hack // Get required size - Bytes = (Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot) + BLOCK_SIZE-1) & ~(BLOCK_SIZE-1); + #if POW2_SIZES + Bytes = Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot); + Bytes = 1UUL << LOG2(Bytes); + #else + Bytes = (Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot) + MIN_SIZE-1) & ~(MIN_SIZE-1); + #endif // Lock Heap - LOCK(&giHeapSpinlock); + Mutex_Acquire(&glHeap); // Traverse Heap for( head = gHeapStart; @@ -148,9 +160,14 @@ void *malloc(size_t Bytes) ) { // Alignment Check - if( head->Size & (BLOCK_SIZE-1) ) { + #if POW2_SIZES + if( head->Size != 1UUL << LOG2(head->Size) ) { + #else + if( head->Size & (MIN_SIZE-1) ) { + #endif + Mutex_Release(&glHeap); // Release spinlock #if WARNINGS - Warning("Size of heap address %p is invalid not aligned (0x%x)", head, head->Size); + Log_Warning("Heap", "Size of heap address %p is invalid not aligned (0x%x)", head, head->Size); Heap_Dump(); #endif return NULL; @@ -160,11 +177,11 @@ void *malloc(size_t Bytes) if(head->Magic == MAGIC_USED) continue; // Error check if(head->Magic != MAGIC_FREE) { + Mutex_Release(&glHeap); // Release spinlock #if WARNINGS - Warning("Magic of heap address %p is invalid (0x%x)", head, head->Magic); + Log_Warning("Heap", "Magic of heap address %p is invalid (0x%x)", head, head->Magic); Heap_Dump(); #endif - RELEASE(&giHeapSpinlock); // Release spinlock return NULL; } @@ -174,9 +191,13 @@ void *malloc(size_t Bytes) // Perfect fit if(head->Size == Bytes) { head->Magic = MAGIC_USED; - RELEASE(&giHeapSpinlock); // Release spinlock - LOG("RETURN %p", best->Data); - return best->Data; + head->File = File; + head->Line = Line; + Mutex_Release(&glHeap); // Release spinlock + #if DEBUG_TRACE + Log("[Heap ] Malloc'd %p (%i bytes), returning to %p", head->Data, head->Size, __builtin_return_address(0)); + #endif + return head->Data; } // Break out of loop @@ -199,13 +220,18 @@ void *malloc(size_t Bytes) best = Heap_Extend( Bytes ); // Check for errors if(!best) { - RELEASE(&giHeapSpinlock); // Release spinlock + Mutex_Release(&glHeap); // Release spinlock return NULL; } // Check size if(best->Size == Bytes) { - RELEASE(&giHeapSpinlock); // Release spinlock - LOG("RETURN %p", best->Data); + best->Magic = MAGIC_USED; // Mark block as used + best->File = File; + best->Line = Line; + Mutex_Release(&glHeap); // Release spinlock + #if DEBUG_TRACE + Log("[Heap ] Malloc'd %p (%i bytes), returning to %p", best->Data, best->Size, __builtin_return_address(0)); + #endif return best->Data; } } @@ -222,82 +248,102 @@ void *malloc(size_t Bytes) foot->Head = newhead; // Update backlink in old footer best->Size = Bytes; // Update size in old header best->Magic = MAGIC_USED; // Mark block as used - - RELEASE(&giHeapSpinlock); // Release spinlock - LOG("RETURN %p", best->Data); + best->File = File; + best->Line = Line; + + Mutex_Release(&glHeap); // Release spinlock + #if DEBUG_TRACE + Log_Debug("Heap", "newhead(%p)->Size = 0x%x", newhead, newhead->Size); + Log_Debug("Heap", "Malloc'd %p (0x%x bytes), returning to %s:%i", + best->Data, best->Size, File, Line); + #endif return best->Data; } /** - * \fn void free(void *Ptr) + * \fn void Heap_Deallocate(void *Ptr) * \brief Free an allocated memory block */ -void free(void *Ptr) +void Heap_Deallocate(void *Ptr) { tHeapHead *head; tHeapFoot *foot; - LOG("Ptr = %p", Ptr); - LOG("Returns to %p", __builtin_return_address(0)); + #if DEBUG_TRACE + Log_Log("Heap", "free: Ptr = %p", Ptr); + Log_Log("Heap", "free: Returns to %p", __builtin_return_address(0)); + #endif // Alignment Check if( (Uint)Ptr & (sizeof(Uint)-1) ) { - Warning("free - Passed a non-aligned address (%p)\n", Ptr); + Log_Warning("Heap", "free - Passed a non-aligned address (%p)", Ptr); return; } // Sanity check if((Uint)Ptr < (Uint)gHeapStart || (Uint)Ptr > (Uint)gHeapEnd) { - Warning("free - Passed a non-heap address (%p)\n", Ptr); + Log_Warning("Heap", "free - Passed a non-heap address (%p < %p < %p)\n", + gHeapStart, Ptr, gHeapEnd); return; } // Check memory block - Header head = (void*)( (Uint)Ptr - sizeof(tHeapHead) ); if(head->Magic == MAGIC_FREE) { - Warning("free - Passed a freed block (%p)\n", head); + Log_Warning("Heap", "free - Passed a freed block (%p) by %p", head, __builtin_return_address(0)); return; } if(head->Magic != MAGIC_USED) { - Warning("free - Magic value is invalid (%p, 0x%x)\n", head, head->Magic); + Log_Warning("Heap", "free - Magic value is invalid (%p, 0x%x)", head, head->Magic); + Log_Notice("Heap", "Allocated %s:%i", head->File, head->Line); return; } // Check memory block - Footer foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) ); if(foot->Head != head) { - Warning("free - Footer backlink is incorrect (%p, 0x%x)\n", head, foot->Head); + Log_Warning("Heap", "free - Footer backlink is incorrect (%p, 0x%x)", head, foot->Head); + Log_Notice("Heap", "Allocated %s:%i", head->File, head->Line); return; } if(foot->Magic != MAGIC_FOOT) { - Warning("free - Footer magic is invalid (%p, 0x%x)\n", head, foot->Magic); + Log_Warning("Heap", "free - Footer magic is invalid (%p, %p = 0x%x)", head, &foot->Magic, foot->Magic); + Log_Notice("Heap", "Allocated %s:%i", head->File, head->Line); return; } // Lock - LOCK( &giHeapSpinlock ); + Mutex_Acquire( &glHeap ); // Mark as free head->Magic = MAGIC_FREE; + head->File = NULL; + head->Line = 0; + head->ValidSize = 0; // Merge blocks Heap_Merge( head ); // Release - RELEASE( &giHeapSpinlock ); + Mutex_Release( &glHeap ); } /** + * \brief Increase/Decrease the size of an allocation + * \param File Calling File + * \param Line Calling Line + * \param __ptr Old memory + * \param __size New Size */ -void *realloc(void *__ptr, size_t __size) +void *Heap_Reallocate(const char *File, int Line, void *__ptr, size_t __size) { tHeapHead *head = (void*)( (Uint)__ptr-8 ); tHeapHead *nextHead; tHeapFoot *foot; - Uint newSize = (__size + sizeof(tHeapFoot)+sizeof(tHeapHead)+BLOCK_SIZE-1)&~(BLOCK_SIZE-1); + Uint newSize = (__size + sizeof(tHeapFoot)+sizeof(tHeapHead)+MIN_SIZE-1)&~(MIN_SIZE-1); // Check for reallocating NULL - if(__ptr == NULL) return malloc(__size); + if(__ptr == NULL) return Heap_Allocate(File, Line, __size); // Check if resize is needed if(newSize <= head->Size) return __ptr; @@ -313,6 +359,9 @@ void *realloc(void *__ptr, size_t __size) // Exact Fit if(size == newSize) { head->Size = newSize; + head->ValidSize = __size; + head->File = File; + head->Line = Line; foot->Head = head; nextHead->Magic = 0; nextHead->Size = 0; @@ -324,6 +373,9 @@ void *realloc(void *__ptr, size_t __size) nextHead->Magic = MAGIC_FREE; foot->Head = nextHead; // Edit 2nd footer head->Size = newSize; // Edit first header + head->File = File; + head->Line = Line; + head->ValidSize = __size; // Create new footer foot = (void*)( (Uint)head + newSize - sizeof(tHeapFoot) ); foot->Head = head; @@ -337,13 +389,23 @@ void *realloc(void *__ptr, size_t __size) if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize) { Uint size = nextHead->Size + head->Size; + // Inexact fit, split things up + if(size > newSize) + { + // TODO + Warning("[Heap ] TODO: Space efficient realloc when new size is smaller"); + } + // Exact fit - if(size == newSize) + if(size >= newSize) { Uint oldDataSize; // Set 1st (new/lower) header nextHead->Magic = MAGIC_USED; nextHead->Size = newSize; + nextHead->File = File; + nextHead->Line = Line; + nextHead->ValidSize = __size; // Get 2nd (old) footer foot = (void*)( (Uint)nextHead + newSize ); foot->Head = nextHead; @@ -352,22 +414,59 @@ void *realloc(void *__ptr, size_t __size) // Clear old header head->Size = 0; head->Magic = 0; + // Copy data memcpy(nextHead->Data, __ptr, oldDataSize); + // Return + return nextHead->Data; } + // On to the expensive then } - return NULL; + // Well, darn + nextHead = Heap_Allocate( File, Line, __size ); + nextHead -= 1; + nextHead->File = File; + nextHead->Line = Line; + nextHead->ValidSize = __size; + + memcpy( + nextHead->Data, + __ptr, + head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead) + ); + + free(__ptr); + + return nextHead->Data; +} + +/** + * \fn void *Heap_AllocateZero(const char *File, int Line, size_t Bytes) + * \brief Allocate and Zero a buffer in memory + * \param File Allocating file + * \param Line Line of allocation + * \param Bytes Size of the allocation + */ +void *Heap_AllocateZero(const char *File, int Line, size_t Bytes) +{ + void *ret = Heap_Allocate(File, Line, Bytes); + if(ret == NULL) return NULL; + + memset( ret, 0, Bytes ); + + return ret; } /** - * \fn int IsHeap(void *Ptr) - * \brief Checks if an address is a heap address + * \fn int Heap_IsHeapAddr(void *Ptr) + * \brief Checks if an address is a heap pointer */ -int IsHeap(void *Ptr) +int Heap_IsHeapAddr(void *Ptr) { tHeapHead *head; if((Uint)Ptr < (Uint)gHeapStart) return 0; if((Uint)Ptr > (Uint)gHeapEnd) return 0; + if((Uint)Ptr & (sizeof(Uint)-1)) return 0; head = (void*)( (Uint)Ptr - sizeof(tHeapHead) ); if(head->Magic != MAGIC_USED && head->Magic != MAGIC_FREE) @@ -377,45 +476,208 @@ int IsHeap(void *Ptr) } #if WARNINGS -void Heap_Dump() +void Heap_Dump(void) { - tHeapHead *head; + tHeapHead *head, *badHead; tHeapFoot *foot; head = gHeapStart; while( (Uint)head < (Uint)gHeapEnd ) { foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) ); - Log("%p (0x%x): 0x%08lx 0x%lx", head, MM_GetPhysAddr((Uint)head), head->Size, head->Magic); - Log("%p 0x%lx", foot->Head, foot->Magic); - Log(""); + Log_Log("Heap", "%p (0x%llx): 0x%08lx (%i) %4C", + head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic); + Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic); + if(head->File) { + Log_Log("Heap", "%sowned by %s:%i", + (head->Magic==MAGIC_FREE?"was ":""), head->File, head->Line); + } + Log_Log("Heap", ""); // Sanity Check Header if(head->Size == 0) { - Log("HALTED - Size is zero"); + Log_Warning("Heap", "HALTED - Size is zero"); break; } - if(head->Size & (BLOCK_SIZE-1)) { - Log("HALTED - Size is malaligned"); + if(head->Size & (MIN_SIZE-1)) { + Log_Warning("Heap", "HALTED - Size is malaligned"); break; } if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) { - Log("HALTED - Head Magic is Bad"); + Log_Warning("Heap", "HALTED - Head Magic is Bad"); break; } // Check footer if(foot->Magic != MAGIC_FOOT) { - Log("HALTED - Foot Magic is Bad"); + Log_Warning("Heap", "HALTED - Foot Magic is Bad"); break; } if(head != foot->Head) { - Log("HALTED - Footer backlink is invalid"); + Log_Warning("Heap", "HALTED - Footer backlink is invalid"); break; } // All OK? Go to next head = foot->NextHead; } + + // Check for a bad return + if( (tVAddr)head >= (tVAddr)gHeapEnd ) + return ; + + badHead = head; + + Log_Log("Heap", "==== Going Backwards ==== (from %p)", badHead); + + // Work backwards + foot = (void*)( (tVAddr)gHeapEnd - sizeof(tHeapFoot) ); + head = foot->Head; + while( (tVAddr)head >= (tVAddr)badHead ) + { + Log_Log("Heap", "%p (0x%llx): 0x%08lx %i %4C", + head, MM_GetPhysAddr((Uint)head), head->Size, head->ValidSize, &head->Magic); + Log_Log("Heap", "%p %4C", foot->Head, &foot->Magic); + if(head->File) + Log_Log("Heap", "%sowned by %s:%i", + (head->Magic!=MAGIC_USED?"was ":""), + head->File, head->Line); + Log_Log("Heap", ""); + + // Sanity Check Header + if(head->Size == 0) { + Log_Warning("Heap", "HALTED - Size is zero"); + break; + } + if(head->Size & (MIN_SIZE-1)) { + Log_Warning("Heap", " - Size is malaligned (&0x%x)", ~(MIN_SIZE-1)); + break ; + } + if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) { + Log_Warning("Heap", "HALTED - Head Magic is Bad"); + break; + } + + // Check footer + if(foot->Magic != MAGIC_FOOT) { + Log_Warning("Heap", "HALTED - Foot Magic is Bad"); + break; + } + if(head != foot->Head) { + Log_Warning("Heap", "HALTED - Footer backlink is invalid"); + break; + } + + if(head == badHead) break; + + foot = (void*)( (tVAddr)head - sizeof(tHeapFoot) ); + head = foot->Head; + Log_Debug("Heap", "head=%p", head); + } +} +#endif + +#if 1 +void Heap_Stats(void) +{ + tHeapHead *head; + int nBlocks = 0; + int nFree = 0; + int totalBytes = 0; + int freeBytes = 0; + int maxAlloc=0, minAlloc=-1; + int avgAlloc, frag, overhead; + + for(head = gHeapStart; + (Uint)head < (Uint)gHeapEnd; + head = (void*)( (Uint)head + head->Size ) + ) + { + nBlocks ++; + totalBytes += head->Size; + if( head->Magic == MAGIC_FREE ) + { + nFree ++; + freeBytes += head->Size; + } + else if( head->Magic == MAGIC_USED) { + if(maxAlloc < head->Size) maxAlloc = head->Size; + if(minAlloc == -1 || minAlloc > head->Size) + minAlloc = head->Size; + } + else { + Log_Warning("Heap", "Magic on %p invalid, skipping remainder of heap", head); + break; + } + + // Print the block info? + #if 1 + Log_Debug("Heap", "%p - 0x%x Owned by %s:%i", + head, head->Size, head->File, head->Line); + #endif + } + + Log_Log("Heap", "%i blocks (0x%x bytes)", nBlocks, totalBytes); + Log_Log("Heap", "%i free blocks (0x%x bytes)", nFree, freeBytes); + frag = (nFree-1)*10000/nBlocks; + Log_Log("Heap", "%i.%02i%% Heap Fragmentation", frag/100, frag%100); + avgAlloc = (totalBytes-freeBytes)/(nBlocks-nFree); + overhead = (sizeof(tHeapFoot)+sizeof(tHeapHead))*10000/avgAlloc; + Log_Log("Heap", "Average allocation: %i bytes, Average Overhead: %i.%02i%%", + avgAlloc, overhead/100, overhead%100 + ); + Log_Log("Heap", "Smallest Block: %i bytes, Largest: %i bytes", + minAlloc, maxAlloc); + + // Scan and get distribution + #if 1 + { + struct { + Uint Size; + Uint Count; + } sizeCounts[nBlocks]; + int i; + + memset(sizeCounts, 0, nBlocks*sizeof(sizeCounts[0])); + + for(head = gHeapStart; + (Uint)head < (Uint)gHeapEnd; + head = (void*)( (Uint)head + head->Size ) + ) + { + for( i = 0; i < nBlocks; i ++ ) { + if( sizeCounts[i].Size == 0 ) + break; + if( sizeCounts[i].Size == head->Size ) + break; + } + // Should never reach this part (in a non-concurrent case) + if( i == nBlocks ) continue; + sizeCounts[i].Size = head->Size; + sizeCounts[i].Count ++; + #if 1 + //Log("Heap_Stats: %i %p - 0x%x bytes (%s) (%i)", nBlocks, head, + // head->Size, (head->Magic==MAGIC_FREE?"FREE":"used"), i + // ); + //Log("Heap_Stats: sizeCounts[%i] = {Size:0x%x, Count: %i}", i, + // sizeCounts[i].Size, sizeCounts[i].Count); + #endif + } + + for( i = 0; i < nBlocks && sizeCounts[i].Count; i ++ ) + { + Log("Heap_Stats: 0x%x - %i blocks", + sizeCounts[i].Size, sizeCounts[i].Count + ); + } + } + #endif } #endif + +// === EXPORTS === +EXPORT(Heap_Allocate); +EXPORT(Heap_AllocateZero); +EXPORT(Heap_Reallocate); +EXPORT(Heap_Deallocate); +EXPORT(Heap_IsHeapAddr);