inline void *MSmall::AllocK(int k) { LOG("AllocK " << (int)k); Page *page = work[k]->next; for(;;) { ASSERT(page->klass == k); FreeLink *p = page->freelist; if(p) { page->freelist = p->next; ++page->active; return p; } if(page->free > page->Begin()) { // Try swapping with freelist void *p = page->free; page->free -= page->sz; ++page->active; return p; } if(page->next != page) { page->active = 255; page->Unlink(); page->Link(full[k]); page = work[k]->next; } else { page = empty[k]->next; if(page->next == page) { if(emptypages) { emptypages--; for(int i = 0; i < 16; i++) { // try inverse direction page = empty[i]->next; if(page->next != page) { page->Unlink(); break; } } ASSERT(page->next != page); } else // remote delete should be here! page = (Page *)AllocRaw4KB(); page->Format(k); ASSERT(page->klass == k); } else { ASSERT(emptypages > 0); page->Unlink(); emptypages--; ASSERT(page->klass == k); } page->Link(work[k]); ASSERT(page->klass == k); } } }
void *Heap::AllocK(int k) { LLOG("AllocK " << k); if(!initialized) Init(); Page *page = work[k]->next; for(;;) { ASSERT(page->klass == k); FreeLink *p = page->freelist; if(p) { LLOG("AllocK allocating from " << (void *)page << " " << (void *)p); page->freelist = p->next; ++page->active; return p; } LLOG("AllocK - page exhausted " << k << " page: " << (void *)page); if(page->next != page) { LLOG("Moving " << (void *)page << " to full"); page->Unlink(); page->Link(full[k]); page = work[k]->next; } if(page->next == page) page = WorkPage(k); } }
void Heap::Shutdown() { LLOG("Shutdown"); Mutex::Lock __(mutex); Init(); FreeRemoteRaw(); for(int i = 0; i < NKLASS; i++) { LLOG("Free cache " << i); FreeLink *l = cache[i]; while(l) { FreeLink *h = l; l = l->next; FreeDirect(h); } while(full[i]->next != full[i]) { Page *p = full[i]->next; p->Unlink(); p->heap = &aux; p->Link(aux.full[i]); LLOG("Orphan full " << (void *)p); } while(work[i]->next != work[i]) { Page *p = work[i]->next; p->Unlink(); p->heap = &aux; p->Link(p->freelist ? aux.work[i] : aux.full[i]); LLOG("Orphan work " << (void *)p); } if(empty[i]) { ASSERT(empty[i]->freelist); ASSERT(empty[i]->active == 0); empty[i]->heap = &aux; empty[i]->next = aux.empty[i]; aux.empty[i] = empty[i]; LLOG("Orphan empty " << (void *)empty[i]); } } while(large != large->next) { Header *bh = (Header *)((byte *)large->next + LARGEHDRSZ); LLOG("Orphan large block " << (void *)large->next << " size: " << bh->size); if(bh->size == MAXBLOCK && bh->free) MoveToEmpty(large->next, bh); else MoveLarge(&aux, large->next); } memset(this, 0, sizeof(Heap)); }
Heap::Page *Heap::WorkPage(int k) // get a new empty workpage { LLOG("AllocK - next work not available " << k << " empty: " << (void *)empty[k]); Page *page = empty[k]; // hot empty page of the same klass empty[k] = NULL; if(!page) { // try to reacquire pages freed remotely LLOG("AllocK - trying FreeRemote"); FreeRemote(); if(work[k]->freelist) { // partially free page found LLOG("AllocK - work available after FreeRemote " << k); return work[k]; } page = empty[k]; // hot empty page empty[k] = NULL; } if(!page) for(int i = 0; i < NKLASS; i++) // Try hot local page of different klass if(empty[i]) { LLOG("AllocK - free page available for reformatting " << k); page = empty[i]; empty[i] = NULL; page->Format(k); break; } if(!page) { // Attempt to find page in global storage of free pages Mutex::Lock __(mutex); aux.FreeRemoteRaw(); if(aux.work[k]->next != aux.work[k]) { // Try page of the same klass first page = aux.work[k]->next; page->Unlink(); page->heap = this; LLOG("AllocK - adopting aux page " << k << " page: " << (void *)page << ", free " << (void *)page->freelist); } if(!page && aux.empty[k]) { // Try hot empty page of the same klass page = aux.empty[k]; aux.empty[k] = page->next; LLOG("AllocK - empty aux page available of the same format " << k << " page: " << (void *)page << ", free " << (void *)page->freelist); } if(!page) for(int i = 0; i < NKLASS; i++) // Finally try to to find hot page of different klass if(aux.empty[i]) { page = aux.empty[i]; aux.empty[i] = page->next; page->Format(k); LLOG("AllocK - empty aux page available for reformatting " << k << " page: " << (void *)page << ", free " << (void *)page->freelist); break; } if(!page) { // Not free memory was found, ask system for the new page page = (Page *)AllocRaw4KB(Ksz(k)); LLOG("AllocK - allocated new system page " << (void *)page << " " << k); page->Format(k); } page->heap = this; } page->Link(work[k]); ASSERT(page->klass == k); return page; }