2 * AcessOS Microkernel Version
13 #define HEAP_INIT_SIZE 0x8000 // 32 KiB
14 #define BLOCK_SIZE (sizeof(void*))*8 // 8 Machine Words
15 #define COMPACT_HEAP 0 // Use 4 byte header?
18 #define MAGIC_FOOT 0x2ACE5505
19 #define MAGIC_FREE 0xACE55000
20 #define MAGIC_USED 0x862B0505 // MAGIC_FOOT ^ MAGIC_FREE
23 void Heap_Install(void);
24 void *Heap_Extend(int Bytes);
25 void *Heap_Merge(tHeapHead *Head);
26 void *malloc(size_t Bytes);
29 void Heap_Stats(void);
37 void Heap_Install(void)
39 gHeapStart = (void*)MM_KHEAP_BASE;
40 gHeapEnd = (void*)MM_KHEAP_BASE;
41 Heap_Extend(HEAP_INIT_SIZE);
45 * \fn void *Heap_Extend(int Bytes)
46 * \brief Extend the size of the heap
48 void *Heap_Extend(int Bytes)
51 tHeapHead *head = gHeapEnd;
55 if( (tVAddr)gHeapEnd == MM_KHEAP_MAX )
59 if( (tVAddr)gHeapEnd + ((Bytes+0xFFF)&~0xFFF) > MM_KHEAP_MAX ) {
60 Bytes = MM_KHEAP_MAX - (tVAddr)gHeapEnd;
64 // Heap expands in pages
65 for(i=0;i<(Bytes+0xFFF)>>12;i++)
66 MM_Allocate( (tVAddr)gHeapEnd+(i<<12) );
72 head->Size = (Bytes+0xFFF)&~0xFFF;
73 head->Magic = MAGIC_FREE;
74 foot = (void*)( (Uint)gHeapEnd - sizeof(tHeapFoot) );
76 foot->Magic = MAGIC_FOOT;
78 return Heap_Merge(head); // Merge with previous block
82 * \fn void *Heap_Merge(tHeapHead *Head)
83 * \brief Merges two ajacent heap blocks
85 void *Heap_Merge(tHeapHead *Head)
91 //Log("Heap_Merge: (Head=%p)", Head);
93 thisFoot = (void*)( (Uint)Head + Head->Size - sizeof(tHeapFoot) );
94 if((Uint)thisFoot > (Uint)gHeapEnd) return NULL;
97 foot = (void*)( (Uint)Head - sizeof(tHeapFoot) );
98 if( ((Uint)foot < (Uint)gHeapEnd && (Uint)foot > (Uint)gHeapStart)
99 && foot->Head->Magic == MAGIC_FREE) {
100 foot->Head->Size += Head->Size; // Increase size
101 thisFoot->Head = foot->Head; // Change backlink
102 Head->Magic = 0; // Clear old head
104 Head = foot->Head; // Save new head address
105 foot->Head = NULL; // Clear central footer
109 // Merge Right (Upwards)
110 head = (void*)( (Uint)Head + Head->Size );
111 if((Uint)head < (Uint)gHeapEnd && head->Magic == MAGIC_FREE)
113 Head->Size += head->Size;
114 foot = (void*)( (Uint)Head + Head->Size - sizeof(tHeapFoot) );
115 foot->Head = Head; // Update Backlink
116 thisFoot->Head = NULL; // Clear old footer
118 head->Size = 0; // Clear old header
122 // Return new address
127 * \fn void *malloc(size_t Bytes)
128 * \brief Allocate memory from the heap
130 void *malloc(size_t Bytes)
132 tHeapHead *head, *newhead;
133 tHeapFoot *foot, *newfoot;
134 tHeapHead *best = NULL;
135 Uint bestSize = 0; // Speed hack
138 Bytes = (Bytes + sizeof(tHeapHead) + sizeof(tHeapFoot) + BLOCK_SIZE-1) & ~(BLOCK_SIZE-1);
144 for( head = gHeapStart;
145 (Uint)head < (Uint)gHeapEnd;
146 head = (void*)((Uint)head + head->Size)
150 if( head->Size & (BLOCK_SIZE-1) ) {
151 RELEASE(&glHeap); // Release spinlock
153 Log_Warning("Heap", "Size of heap address %p is invalid not aligned (0x%x)", head, head->Size);
159 // Check if allocated
160 if(head->Magic == MAGIC_USED) continue;
162 if(head->Magic != MAGIC_FREE) {
163 RELEASE(&glHeap); // Release spinlock
165 Log_Warning("Heap", "Magic of heap address %p is invalid (0x%x)", head, head->Magic);
172 if(head->Size < Bytes) continue;
175 if(head->Size == Bytes) {
176 head->Magic = MAGIC_USED;
177 RELEASE(&glHeap); // Release spinlock
179 Log("[Heap ] Malloc'd %p (%i bytes), returning to %p", head->Data, head->Size, __builtin_return_address(0));
187 bestSize = head->Size;
190 // or check if the block is the best size
191 if(bestSize > head->Size) {
193 bestSize = head->Size;
198 // If no block large enough is found, create one
201 best = Heap_Extend( Bytes );
204 RELEASE(&glHeap); // Release spinlock
208 if(best->Size == Bytes) {
209 best->Magic = MAGIC_USED; // Mark block as used
210 RELEASE(&glHeap); // Release spinlock
212 Log("[Heap ] Malloc'd %p (%i bytes), returning to %p", best->Data, best->Size, __builtin_return_address(0));
219 newhead = (void*)( (Uint)best + Bytes );
220 newfoot = (void*)( (Uint)best + Bytes - sizeof(tHeapFoot) );
221 foot = (void*)( (Uint)best + best->Size - sizeof(tHeapFoot) );
223 newfoot->Head = best; // Create new footer
224 newfoot->Magic = MAGIC_FOOT;
225 newhead->Size = best->Size - Bytes; // Create new header
226 newhead->Magic = MAGIC_FREE;
227 foot->Head = newhead; // Update backlink in old footer
228 best->Size = Bytes; // Update size in old header
229 best->Magic = MAGIC_USED; // Mark block as used
231 RELEASE(&glHeap); // Release spinlock
233 Log("[Heap ] Malloc'd %p (%i bytes), returning to %p", best->Data, best->Size, __builtin_return_address(0));
239 * \fn void free(void *Ptr)
240 * \brief Free an allocated memory block
248 Log_Log("Heap", "free: Ptr = %p", Ptr);
249 Log_Log("Heap", "free: Returns to %p", __builtin_return_address(0));
253 if( (Uint)Ptr & (sizeof(Uint)-1) ) {
254 Log_Warning("Heap", "free - Passed a non-aligned address (%p)", Ptr);
259 if((Uint)Ptr < (Uint)gHeapStart || (Uint)Ptr > (Uint)gHeapEnd)
261 Log_Warning("Heap", "free - Passed a non-heap address (%p < %p < %p)\n",
262 gHeapStart, Ptr, gHeapEnd);
266 // Check memory block - Header
267 head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
268 if(head->Magic == MAGIC_FREE) {
269 Log_Warning("Heap", "free - Passed a freed block (%p) by %p", head, __builtin_return_address(0));
272 if(head->Magic != MAGIC_USED) {
273 Log_Warning("Heap", "free - Magic value is invalid (%p, 0x%x)\n", head, head->Magic);
277 // Check memory block - Footer
278 foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
279 if(foot->Head != head) {
280 Log_Warning("Heap", "free - Footer backlink is incorrect (%p, 0x%x)\n", head, foot->Head);
283 if(foot->Magic != MAGIC_FOOT) {
284 Log_Warning("Heap", "free - Footer magic is invalid (%p, %p = 0x%x)\n", head, &foot->Magic, foot->Magic);
292 head->Magic = MAGIC_FREE;
302 void *realloc(void *__ptr, size_t __size)
304 tHeapHead *head = (void*)( (Uint)__ptr-8 );
307 Uint newSize = (__size + sizeof(tHeapFoot)+sizeof(tHeapHead)+BLOCK_SIZE-1)&~(BLOCK_SIZE-1);
309 // Check for reallocating NULL
310 if(__ptr == NULL) return malloc(__size);
312 // Check if resize is needed
313 if(newSize <= head->Size) return __ptr;
315 // Check if next block is free
316 nextHead = (void*)( (Uint)head + head->Size );
318 // Extend into next block
319 if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
321 Uint size = nextHead->Size + head->Size;
322 foot = (void*)( (Uint)nextHead + nextHead->Size - sizeof(tHeapFoot) );
324 if(size == newSize) {
325 head->Size = newSize;
331 // Create a new heap block
332 nextHead = (void*)( (Uint)head + newSize );
333 nextHead->Size = size - newSize;
334 nextHead->Magic = MAGIC_FREE;
335 foot->Head = nextHead; // Edit 2nd footer
336 head->Size = newSize; // Edit first header
338 foot = (void*)( (Uint)head + newSize - sizeof(tHeapFoot) );
340 foot->Magic = MAGIC_FOOT;
345 foot = (void*)( (Uint)head - sizeof(tHeapFoot) );
346 nextHead = foot->Head;
347 if(nextHead->Magic == MAGIC_FREE && nextHead->Size+head->Size >= newSize)
349 Uint size = nextHead->Size + head->Size;
350 // Inexact fit, split things up
354 Warning("[Heap ] TODO: Space efficient realloc when new size is smaller");
361 // Set 1st (new/lower) header
362 nextHead->Magic = MAGIC_USED;
363 nextHead->Size = newSize;
364 // Get 2nd (old) footer
365 foot = (void*)( (Uint)nextHead + newSize );
366 foot->Head = nextHead;
367 // Save old data size
368 oldDataSize = head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead);
373 memcpy(nextHead->Data, __ptr, oldDataSize);
375 return nextHead->Data;
377 // On to the expensive then
381 nextHead = malloc( __size );
387 head->Size - sizeof(tHeapFoot) - sizeof(tHeapHead)
392 return nextHead->Data;
396 * \fn void *calloc(size_t num, size_t size)
397 * \brief Allocate and Zero a buffer in memory
398 * \param num Number of elements
399 * \param size Size of each element
401 void *calloc(size_t num, size_t size)
403 void *ret = malloc(num*size);
404 if(ret == NULL) return NULL;
406 memset( ret, 0, num*size );
412 * \fn int IsHeap(void *Ptr)
413 * \brief Checks if an address is a heap pointer
415 int IsHeap(void *Ptr)
418 if((Uint)Ptr < (Uint)gHeapStart) return 0;
419 if((Uint)Ptr > (Uint)gHeapEnd) return 0;
420 if((Uint)Ptr & (sizeof(Uint)-1)) return 0;
422 head = (void*)( (Uint)Ptr - sizeof(tHeapHead) );
423 if(head->Magic != MAGIC_USED && head->Magic != MAGIC_FREE)
436 while( (Uint)head < (Uint)gHeapEnd )
438 foot = (void*)( (Uint)head + head->Size - sizeof(tHeapFoot) );
439 Log_Log("Heap", "%p (0x%x): 0x%08lx 0x%lx",
440 head, MM_GetPhysAddr((Uint)head), head->Size, head->Magic);
441 Log_Log("Heap", "%p 0x%lx", foot->Head, foot->Magic);
444 // Sanity Check Header
445 if(head->Size == 0) {
446 Log_Warning("Heap", "HALTED - Size is zero");
449 if(head->Size & (BLOCK_SIZE-1)) {
450 Log_Warning("Heap", "HALTED - Size is malaligned");
453 if(head->Magic != MAGIC_FREE && head->Magic != MAGIC_USED) {
454 Log_Warning("Heap", "HALTED - Head Magic is Bad");
459 if(foot->Magic != MAGIC_FOOT) {
460 Log_Warning("Heap", "HALTED - Foot Magic is Bad");
463 if(head != foot->Head) {
464 Log_Warning("Heap", "HALTED - Footer backlink is invalid");
468 // All OK? Go to next
469 head = foot->NextHead;
475 void Heap_Stats(void)
482 int maxAlloc=0, minAlloc=-1;
483 int avgAlloc, frag, overhead;
485 for(head = gHeapStart;
486 (Uint)head < (Uint)gHeapEnd;
487 head = (void*)( (Uint)head + head->Size )
491 totalBytes += head->Size;
492 if( head->Magic == MAGIC_FREE )
495 freeBytes += head->Size;
498 if(maxAlloc < head->Size) maxAlloc = head->Size;
499 if(minAlloc == -1 || minAlloc > head->Size)
500 minAlloc = head->Size;
504 Log_Log("Heap", "%i blocks (0x%x bytes)", nBlocks, totalBytes);
505 Log_Log("Heap", "%i free blocks (0x%x bytes)", nFree, freeBytes);
506 frag = (nFree-1)*10000/nBlocks;
507 Log_Log("Heap", "%i.%02i%% Heap Fragmentation", frag/100, frag%100);
508 avgAlloc = (totalBytes-freeBytes)/(nBlocks-nFree);
509 overhead = (sizeof(tHeapFoot)+sizeof(tHeapHead))*10000/avgAlloc;
510 Log_Log("Heap", "Average allocation: %i bytes, Average Overhead: %i.%02i%%",
511 avgAlloc, overhead/100, overhead%100
513 Log_Log("Heap", "Smallest Block: %i bytes, Largest: %i bytes",
516 // Scan and get distribution
522 } sizeCounts[nBlocks];
525 memset(sizeCounts, 0, nBlocks*sizeof(sizeCounts[0]));
527 for(head = gHeapStart;
528 (Uint)head < (Uint)gHeapEnd;
529 head = (void*)( (Uint)head + head->Size )
532 for( i = 0; i < nBlocks; i ++ ) {
533 if( sizeCounts[i].Size == 0 )
535 if( sizeCounts[i].Size == head->Size )
538 // Should never reach this part (in a non-concurrent case)
539 if( i == nBlocks ) continue;
540 sizeCounts[i].Size = head->Size;
541 sizeCounts[i].Count ++;
543 //Log("Heap_Stats: %i %p - 0x%x bytes (%s) (%i)", nBlocks, head,
544 // head->Size, (head->Magic==MAGIC_FREE?"FREE":"used"), i
546 //Log("Heap_Stats: sizeCounts[%i] = {Size:0x%x, Count: %i}", i,
547 // sizeCounts[i].Size, sizeCounts[i].Count);
551 for( i = 0; i < nBlocks && sizeCounts[i].Count; i ++ )
553 Log("Heap_Stats: 0x%x - %i blocks",
554 sizeCounts[i].Size, sizeCounts[i].Count