1*360d4974SIngo Weinhold /* 2*360d4974SIngo Weinhold * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de 3*360d4974SIngo Weinhold * Distributed under the terms of the MIT License. 4*360d4974SIngo Weinhold */ 5*360d4974SIngo Weinhold 6*360d4974SIngo Weinhold #include <debug_heap.h> 7*360d4974SIngo Weinhold 8*360d4974SIngo Weinhold #include <new> 9*360d4974SIngo Weinhold 10*360d4974SIngo Weinhold #include <util/AutoLock.h> 11*360d4974SIngo Weinhold 12*360d4974SIngo Weinhold 13*360d4974SIngo Weinhold #define INITIAL_HEAP_SIZE B_PAGE_SIZE 14*360d4974SIngo Weinhold 15*360d4974SIngo Weinhold static char sInitialHeap[INITIAL_HEAP_SIZE]; 16*360d4974SIngo Weinhold static void* sHeapBase = sInitialHeap; 17*360d4974SIngo Weinhold static size_t sHeapSize = INITIAL_HEAP_SIZE; 18*360d4974SIngo Weinhold 19*360d4974SIngo Weinhold const kdebug_alloc_t kdebug_alloc = {}; 20*360d4974SIngo Weinhold 21*360d4974SIngo Weinhold 22*360d4974SIngo Weinhold struct allocation_header { 23*360d4974SIngo Weinhold uint32 size : 31; // size in allocation_header units 24*360d4974SIngo Weinhold bool free : 1; 25*360d4974SIngo Weinhold uint32 previous; 26*360d4974SIngo Weinhold }; 27*360d4974SIngo Weinhold 28*360d4974SIngo Weinhold struct free_entry : allocation_header { 29*360d4974SIngo Weinhold uint32 previous_free; 30*360d4974SIngo Weinhold uint32 next_free; 31*360d4974SIngo Weinhold }; 32*360d4974SIngo Weinhold 33*360d4974SIngo Weinhold 34*360d4974SIngo Weinhold struct DebugAllocPool { 35*360d4974SIngo Weinhold void Init(void* heap, size_t heapSize) 36*360d4974SIngo Weinhold { 37*360d4974SIngo Weinhold fParent = NULL; 38*360d4974SIngo Weinhold fChild = NULL; 39*360d4974SIngo Weinhold 40*360d4974SIngo Weinhold uint32 size = heapSize / 8; 41*360d4974SIngo Weinhold fBase = (allocation_header*)heap - 1; 42*360d4974SIngo Weinhold fEnd = size + 1; 43*360d4974SIngo Weinhold fFirstFree = 0; 44*360d4974SIngo Weinhold fLastFree = 0; 45*360d4974SIngo Weinhold 46*360d4974SIngo Weinhold // add free entry spanning the whole area 47*360d4974SIngo Weinhold fBase[1].size = size - 1; 48*360d4974SIngo Weinhold fBase[1].previous = 0; 49*360d4974SIngo Weinhold _InsertFreeEntry(1); 50*360d4974SIngo Weinhold } 51*360d4974SIngo Weinhold 52*360d4974SIngo Weinhold DebugAllocPool* CreateChildPool() 53*360d4974SIngo Weinhold { 54*360d4974SIngo Weinhold // do we already have a child pool? 55*360d4974SIngo Weinhold if (fChild != NULL) 56*360d4974SIngo Weinhold return NULL; 57*360d4974SIngo Weinhold 58*360d4974SIngo Weinhold // create the pool object 59*360d4974SIngo Weinhold DebugAllocPool* pool 60*360d4974SIngo Weinhold = (DebugAllocPool*)Allocate(sizeof(DebugAllocPool)); 61*360d4974SIngo Weinhold if (pool == NULL) 62*360d4974SIngo Weinhold return NULL; 63*360d4974SIngo Weinhold 64*360d4974SIngo Weinhold // do we have enough free space? 65*360d4974SIngo Weinhold if (fLastFree == 0 || fBase[fLastFree].size < 2) { 66*360d4974SIngo Weinhold Free(pool); 67*360d4974SIngo Weinhold return NULL; 68*360d4974SIngo Weinhold } 69*360d4974SIngo Weinhold 70*360d4974SIngo Weinhold allocation_header* header = &fBase[fLastFree]; 71*360d4974SIngo Weinhold _RemoveFreeEntry(fLastFree); 72*360d4974SIngo Weinhold 73*360d4974SIngo Weinhold pool->Init(header + 1, header->size * 8); 74*360d4974SIngo Weinhold pool->fParent = this; 75*360d4974SIngo Weinhold 76*360d4974SIngo Weinhold return fChild = pool; 77*360d4974SIngo Weinhold } 78*360d4974SIngo Weinhold 79*360d4974SIngo Weinhold void Destroy() 80*360d4974SIngo Weinhold { 81*360d4974SIngo Weinhold if (fParent != NULL) { 82*360d4974SIngo Weinhold fParent->fChild = NULL; 83*360d4974SIngo Weinhold fParent->Free(fBase + 1); 84*360d4974SIngo Weinhold } 85*360d4974SIngo Weinhold } 86*360d4974SIngo Weinhold 87*360d4974SIngo Weinhold DebugAllocPool* Parent() const 88*360d4974SIngo Weinhold { 89*360d4974SIngo Weinhold return fParent; 90*360d4974SIngo Weinhold } 91*360d4974SIngo Weinhold 92*360d4974SIngo Weinhold void* Allocate(size_t size) 93*360d4974SIngo Weinhold { 94*360d4974SIngo Weinhold size = (size + 7) / 8; 95*360d4974SIngo Weinhold uint32 index = fFirstFree; 96*360d4974SIngo Weinhold while (index != 0 && fBase[index].size < size) 97*360d4974SIngo Weinhold index = ((free_entry*)&fBase[index])->next_free; 98*360d4974SIngo Weinhold 99*360d4974SIngo Weinhold if (index == 0) 100*360d4974SIngo Weinhold return NULL; 101*360d4974SIngo Weinhold 102*360d4974SIngo Weinhold _RemoveFreeEntry(index); 103*360d4974SIngo Weinhold 104*360d4974SIngo Weinhold // if the entry is big enough, we split it 105*360d4974SIngo Weinhold if (fBase[index].size - size >= 2) { 106*360d4974SIngo Weinhold uint32 next = index + 1 + size; 107*360d4974SIngo Weinhold uint32 nextNext = index + 1 + fBase[index].size; 108*360d4974SIngo Weinhold fBase[next].size = fBase[index].size - size - 1; 109*360d4974SIngo Weinhold fBase[next].previous = index; 110*360d4974SIngo Weinhold fBase[index].size = size; 111*360d4974SIngo Weinhold _InsertFreeEntry(next); 112*360d4974SIngo Weinhold 113*360d4974SIngo Weinhold if (nextNext < fEnd) 114*360d4974SIngo Weinhold fBase[nextNext].previous = next; 115*360d4974SIngo Weinhold } 116*360d4974SIngo Weinhold 117*360d4974SIngo Weinhold return &fBase[index + 1]; 118*360d4974SIngo Weinhold } 119*360d4974SIngo Weinhold 120*360d4974SIngo Weinhold void Free(void* address) 121*360d4974SIngo Weinhold { 122*360d4974SIngo Weinhold // check address 123*360d4974SIngo Weinhold if (((addr_t)address & 7) != 0 || address <= fBase + 1 124*360d4974SIngo Weinhold || address >= fBase + fEnd) { 125*360d4974SIngo Weinhold kprintf("DebugAllocator::Free(%p): bad address\n", address); 126*360d4974SIngo Weinhold return; 127*360d4974SIngo Weinhold } 128*360d4974SIngo Weinhold 129*360d4974SIngo Weinhold // get header 130*360d4974SIngo Weinhold allocation_header* header = (allocation_header*)address - 1; 131*360d4974SIngo Weinhold uint32 index = header - fBase; 132*360d4974SIngo Weinhold if (header->free) { 133*360d4974SIngo Weinhold kprintf("DebugAllocator::Free(%p): double free\n", address); 134*360d4974SIngo Weinhold return; 135*360d4974SIngo Weinhold } 136*360d4974SIngo Weinhold 137*360d4974SIngo Weinhold uint32 next = index + 1 + header->size; 138*360d4974SIngo Weinhold 139*360d4974SIngo Weinhold // join with previous, if possible 140*360d4974SIngo Weinhold if (index > 1 && fBase[header->previous].free) { 141*360d4974SIngo Weinhold uint32 previous = header->previous; 142*360d4974SIngo Weinhold _RemoveFreeEntry(previous); 143*360d4974SIngo Weinhold 144*360d4974SIngo Weinhold fBase[previous].size += 1 + header->size; 145*360d4974SIngo Weinhold fBase[next].previous = previous; 146*360d4974SIngo Weinhold 147*360d4974SIngo Weinhold index = previous; 148*360d4974SIngo Weinhold header = fBase + index; 149*360d4974SIngo Weinhold } 150*360d4974SIngo Weinhold 151*360d4974SIngo Weinhold // join with next, if possible 152*360d4974SIngo Weinhold if (next < fEnd && fBase[next].free) { 153*360d4974SIngo Weinhold _RemoveFreeEntry(next); 154*360d4974SIngo Weinhold 155*360d4974SIngo Weinhold header->size += 1 + fBase[next].size; 156*360d4974SIngo Weinhold 157*360d4974SIngo Weinhold uint32 nextNext = index + 1 + header->size; 158*360d4974SIngo Weinhold if (nextNext < fEnd) 159*360d4974SIngo Weinhold fBase[nextNext].previous = index; 160*360d4974SIngo Weinhold } 161*360d4974SIngo Weinhold 162*360d4974SIngo Weinhold _InsertFreeEntry(index); 163*360d4974SIngo Weinhold } 164*360d4974SIngo Weinhold 165*360d4974SIngo Weinhold private: 166*360d4974SIngo Weinhold void _InsertFreeEntry(uint32 index) 167*360d4974SIngo Weinhold { 168*360d4974SIngo Weinhold // find the insertion point -- list is sorted by ascending size 169*360d4974SIngo Weinhold uint32 size = fBase[index].size; 170*360d4974SIngo Weinhold uint32 next = fFirstFree; 171*360d4974SIngo Weinhold while (next != 0 && size > fBase[next].size) 172*360d4974SIngo Weinhold next = ((free_entry*)&fBase[next])->next_free; 173*360d4974SIngo Weinhold 174*360d4974SIngo Weinhold // insert 175*360d4974SIngo Weinhold uint32 previous; 176*360d4974SIngo Weinhold if (next != 0) { 177*360d4974SIngo Weinhold previous = ((free_entry*)&fBase[next])->previous_free; 178*360d4974SIngo Weinhold ((free_entry*)&fBase[next])->previous_free = index; 179*360d4974SIngo Weinhold } else { 180*360d4974SIngo Weinhold previous = fLastFree; 181*360d4974SIngo Weinhold fLastFree = index; 182*360d4974SIngo Weinhold } 183*360d4974SIngo Weinhold 184*360d4974SIngo Weinhold if (previous != 0) 185*360d4974SIngo Weinhold ((free_entry*)&fBase[previous])->next_free = index; 186*360d4974SIngo Weinhold else 187*360d4974SIngo Weinhold fFirstFree = index; 188*360d4974SIngo Weinhold 189*360d4974SIngo Weinhold ((free_entry*)&fBase[index])->previous_free = previous; 190*360d4974SIngo Weinhold ((free_entry*)&fBase[index])->next_free = next; 191*360d4974SIngo Weinhold 192*360d4974SIngo Weinhold fBase[index].free = true; 193*360d4974SIngo Weinhold } 194*360d4974SIngo Weinhold 195*360d4974SIngo Weinhold void _RemoveFreeEntry(uint32 index) 196*360d4974SIngo Weinhold { 197*360d4974SIngo Weinhold uint32 previous = ((free_entry*)&fBase[index])->previous_free; 198*360d4974SIngo Weinhold uint32 next = ((free_entry*)&fBase[index])->next_free; 199*360d4974SIngo Weinhold 200*360d4974SIngo Weinhold if (previous != 0) 201*360d4974SIngo Weinhold ((free_entry*)&fBase[previous])->next_free = next; 202*360d4974SIngo Weinhold else 203*360d4974SIngo Weinhold fFirstFree = next; 204*360d4974SIngo Weinhold 205*360d4974SIngo Weinhold if (next != 0) 206*360d4974SIngo Weinhold ((free_entry*)&fBase[next])->previous_free = previous; 207*360d4974SIngo Weinhold else 208*360d4974SIngo Weinhold fLastFree = previous; 209*360d4974SIngo Weinhold 210*360d4974SIngo Weinhold fBase[index].free = false; 211*360d4974SIngo Weinhold } 212*360d4974SIngo Weinhold 213*360d4974SIngo Weinhold private: 214*360d4974SIngo Weinhold DebugAllocPool* fParent; 215*360d4974SIngo Weinhold DebugAllocPool* fChild; 216*360d4974SIngo Weinhold allocation_header* fBase; // actually base - 1, so that index 0 is 217*360d4974SIngo Weinhold // invalid 218*360d4974SIngo Weinhold uint32 fEnd; 219*360d4974SIngo Weinhold uint32 fFirstFree; 220*360d4974SIngo Weinhold uint32 fLastFree; 221*360d4974SIngo Weinhold }; 222*360d4974SIngo Weinhold 223*360d4974SIngo Weinhold 224*360d4974SIngo Weinhold static DebugAllocPool* sCurrentPool; 225*360d4974SIngo Weinhold static DebugAllocPool sInitialPool; 226*360d4974SIngo Weinhold 227*360d4974SIngo Weinhold 228*360d4974SIngo Weinhold debug_alloc_pool* 229*360d4974SIngo Weinhold create_debug_alloc_pool() 230*360d4974SIngo Weinhold { 231*360d4974SIngo Weinhold if (sCurrentPool == NULL) { 232*360d4974SIngo Weinhold sInitialPool.Init(sHeapBase, sHeapSize); 233*360d4974SIngo Weinhold sCurrentPool = &sInitialPool; 234*360d4974SIngo Weinhold return sCurrentPool; 235*360d4974SIngo Weinhold } 236*360d4974SIngo Weinhold 237*360d4974SIngo Weinhold DebugAllocPool* pool = sCurrentPool->CreateChildPool(); 238*360d4974SIngo Weinhold if (pool == NULL) 239*360d4974SIngo Weinhold return NULL; 240*360d4974SIngo Weinhold 241*360d4974SIngo Weinhold sCurrentPool = pool; 242*360d4974SIngo Weinhold return sCurrentPool; 243*360d4974SIngo Weinhold } 244*360d4974SIngo Weinhold 245*360d4974SIngo Weinhold 246*360d4974SIngo Weinhold void 247*360d4974SIngo Weinhold delete_debug_alloc_pool(debug_alloc_pool* pool) 248*360d4974SIngo Weinhold { 249*360d4974SIngo Weinhold if (pool == NULL || sCurrentPool == NULL) 250*360d4974SIngo Weinhold return; 251*360d4974SIngo Weinhold 252*360d4974SIngo Weinhold // find the pool in the hierarchy 253*360d4974SIngo Weinhold DebugAllocPool* otherPool = sCurrentPool; 254*360d4974SIngo Weinhold while (otherPool != NULL && otherPool != pool) 255*360d4974SIngo Weinhold otherPool = otherPool->Parent(); 256*360d4974SIngo Weinhold 257*360d4974SIngo Weinhold if (otherPool == NULL) 258*360d4974SIngo Weinhold return; 259*360d4974SIngo Weinhold 260*360d4974SIngo Weinhold // destroy the pool 261*360d4974SIngo Weinhold sCurrentPool = pool->Parent(); 262*360d4974SIngo Weinhold pool->Destroy(); 263*360d4974SIngo Weinhold 264*360d4974SIngo Weinhold if (pool != &sInitialPool) 265*360d4974SIngo Weinhold debug_free(pool); 266*360d4974SIngo Weinhold } 267*360d4974SIngo Weinhold 268*360d4974SIngo Weinhold 269*360d4974SIngo Weinhold void* 270*360d4974SIngo Weinhold debug_malloc(size_t size) 271*360d4974SIngo Weinhold { 272*360d4974SIngo Weinhold if (sCurrentPool == NULL) 273*360d4974SIngo Weinhold return NULL; 274*360d4974SIngo Weinhold 275*360d4974SIngo Weinhold return sCurrentPool->Allocate(size); 276*360d4974SIngo Weinhold } 277*360d4974SIngo Weinhold 278*360d4974SIngo Weinhold 279*360d4974SIngo Weinhold void 280*360d4974SIngo Weinhold debug_free(void* address) 281*360d4974SIngo Weinhold { 282*360d4974SIngo Weinhold if (address != NULL && sCurrentPool != NULL) 283*360d4974SIngo Weinhold sCurrentPool->Free(address); 284*360d4974SIngo Weinhold } 285*360d4974SIngo Weinhold 286*360d4974SIngo Weinhold 287*360d4974SIngo Weinhold void 288*360d4974SIngo Weinhold debug_heap_init() 289*360d4974SIngo Weinhold { 290*360d4974SIngo Weinhold // create the heap area 291*360d4974SIngo Weinhold void* base; 292*360d4974SIngo Weinhold area_id area = create_area("kdebug heap", (void**)&base, 293*360d4974SIngo Weinhold B_ANY_KERNEL_ADDRESS, KDEBUG_HEAP, B_FULL_LOCK, 294*360d4974SIngo Weinhold B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); 295*360d4974SIngo Weinhold if (area < 0) 296*360d4974SIngo Weinhold return; 297*360d4974SIngo Weinhold 298*360d4974SIngo Weinhold // switch from the small static buffer to the area 299*360d4974SIngo Weinhold InterruptsLocker locker; 300*360d4974SIngo Weinhold sHeapBase = base; 301*360d4974SIngo Weinhold sHeapSize = KDEBUG_HEAP; 302*360d4974SIngo Weinhold } 303