#include "Malloc.h" #ifdef V5 //#define HEAPDBG #define ATIMING(x) #define BTIMING(x) void HeapPanic(const char *text, void *pos, int size) { RLOG("\n\n" << text << "\n"); HexDump(VppLog(), pos, size, 64); Panic(text); } #ifdef HEAPDBG void FreeFill(dword *ptr, int count) { //DUMP((void *)ptr); //DUMP((void *)(ptr + count)); while(count--) *ptr++ = 0x65657246; } void FreeCheck(dword *ptr, int count) { int c = count; while(c--) if(*ptr++ != 0x65657246) HeapPanic("Writes to freed blocks detected", ptr, sizeof(dword) * count); } void *MSmall::CheckFree(void *p, int k) { Page *page = (Page *)((uintptr_t)p & ~(uintptr_t)4095); ASSERT((byte *)page + sizeof(Page) <= (byte *)p && (byte *)p < (byte *)page + 4096); ASSERT((4096 - ((uintptr_t)p & (uintptr_t)4095)) % Ksz(k) == 0); ASSERT(page->klass == k); #ifdef CPU_64 FreeCheck((dword *)p + 2, (Ksz(k) >> 2) - 2); #else FreeCheck((dword *)p + 1, (Ksz(k) >> 2) - 1); #endif return p; } void MSmall::FillFree(void *ptr, int k) { #ifdef HEAPDBG #ifdef CPU_64 FreeFill((dword *)ptr + 2, (Ksz(k) >> 2) - 2); #else FreeFill((dword *)ptr + 1, (Ksz(k) >> 2) - 1); #endif #endif } #else inline void FreeFill(dword *ptr, int count) {} inline void FreeCheck(dword *ptr, int count) {} inline void *MSmall::CheckFree(void *p, int k) { return p; } inline void MSmall::FillFree(void *ptr, int k) {} #endif MSmall::Page *MSmall::global_empty[16]; StaticMutex MSmall::global_lock; inline void MSmall::Page::Format(int k) { #ifdef HEAPDBG FreeFill((dword *)Begin(), (dword *)End() - (dword *)Begin()); #endif klass = k; active = 0; int sz = Ksz(k); byte *ptr = End() - sz; byte *bg = Begin(); FreeLink *l = NULL; while(ptr > bg) { ((FreeLink *)ptr)->next = l; l = (FreeLink *)ptr; ptr -= sz; } freelist = l; } void MSmall::Init() { for(int i = 0; i < 16; i++) { int sz = Ksz(i); empty[i] = NULL; full[i]->LinkSelf(); work[i]->LinkSelf(); work[i]->freelist = NULL; work[i]->klass = i; } } inline void *MSmall::AllocK(int k) { Page *page = work[k]->next; if(!page) { Init(); page = work[k]->next; } for(;;) { ASSERT(page->klass == k); FreeLink *p = page->freelist; if(p) { CheckFree(p, k); page->freelist = p->next; ++page->active; return p; } if(page->next != page) { BTIMING("NextWork"); page->Unlink(); page->Link(full[k]); page = work[k]->next; } else { BTIMING("EmptyWork"); page = empty[k]; empty[k] = NULL; if(!page) { BTIMING("global get"); Mutex::Lock __(global_lock); // Put remote free here!!! if(global_empty[k]) { page = global_empty[k]; global_empty[k] = page->next; } else { for(int i = 0; i < 16; i++) // try inverse direction if(global_empty[i]) { page = global_empty[i]; global_empty[i] = page->next; break; } if(!page) for(int i = 0; i < 16; i++) // try inverse direction if(empty[i]) { page = empty[i]; empty[i] = NULL; break; } if(!page) page = (Page *)AllocRaw4KB(); page->Format(k); } ASSERT(page->klass == k); } page->Link(work[k]); ASSERT(page->klass == k); } } } inline void MSmall::FreeK(void *ptr, Page *page, int k) { ASSERT((4096 - ((uintptr_t)ptr & (uintptr_t)4095)) % Ksz(k) == 0); FillFree(ptr, k); if(page->freelist) ((FreeLink *)ptr)->next = page->freelist; else { BTIMING("FromFull"); page->Unlink(); page->Link(work[k]); ((FreeLink *)ptr)->next = NULL; } page->freelist = (FreeLink *)ptr; if(--page->active == 0) { BTIMING("FreeEmpty"); page->Unlink(); if(empty[k]) { BTIMING("global free"); Mutex::Lock __(global_lock); empty[k]->next = global_empty[k]; global_empty[k] = empty[k]; } empty[k] = page; } } void *MSmall::Alloc(size_t sz) { if(sz <= 256) { ATIMING("Small alloc"); int k = ((int)sz + (sz == 0) - 1) >> 4; sHeapStat(k); // DUMP(Ksz(k)); return CheckFree(AllocK(k), k); } return LAlloc(sz); } void MSmall::Free(void *ptr) { if(!ptr) return; if(((dword)(uintptr_t)ptr) & 8) LFree(ptr); else { ATIMING("Small free"); Page *page = (Page *)((uintptr_t)ptr & ~(uintptr_t)4095); int k = page->klass; FreeK(ptr, page, k); } } void MSmall::Check() { for(int i = 0; i < 16; i++) { Page *p = work[i]->next; while(p != work[i]) { FreeLink *l = p->freelist; while(l) { CheckFree(l, p->klass & 15); l = l->next; } p = p->next; } /* p = sFull[i]->next; while(p != sFull[i]) { ASSERT(p->free <= 4096); ASSERT((((MPage *)((uintptr_t)p & ~(uintptr_t)4095))->klass & 15) == i); ASSERT(p->count == (4096 - 32) / Ksz(i)); p = p->next; }*/ } } thread__ MSmall heap; #endif