static boolean getmoreblocks(int sz) { void *page; int bpp; int ind; struct freeblock *e; struct pageinfo *pi; int i; FPRINTF((stderr, "getmoreblocks(%d)\n", sz)); if (sz < 1 || sz > PAGETHRESHHOLD) return FALSE; FPRINTF((stderr, "getmoreblocks(%d), size is valid\n", sz)); page = allocpages(1); /* get a page */ if (page == NULL) return FALSE; FPRINTF((stderr, "getmoreblocks(%d), got new page\n", sz)); /* fill out pageinfo for this page */ bpp = (BYTESPERPAGE - sizeof (struct pageinfo)) / sz; ind = sz / MINBLOCK; e = (struct freeblock *)((char *)page + sizeof (struct pageinfo)); pi = (struct pageinfo *)page; pi->blocksize = sz; pi->numblocks = bpp; pi->block = e; pi->link = g.blockmap[ind]; g.blockmap[ind] = pi; bpp--; for (i = 0; i < bpp; i++, e = e->link) e->link = (struct freeblock *)((char *)e + sz); e->link = NULL; #ifdef DO_GC CLEARBITMAP(pi->refbits); ind = PAGENUM(pi); if (ind >= MAXPAGES) crash("getmoreblocks(): out of space for new pages"); SETBIT(g.ourpages, ind); #endif return TRUE; }
int _mmfree(int _free_addr, unsigned long long* pgbitmap){ if( _free_addr==-1) return -1; CLEARBITMAP(_free_addr, pgbitmap); return 0; }
void * malloc(size_t sz) { int nsz; int ind, i; struct pageinfo *ppi; struct pageinfo *pi; void *ptr; if (!initialized) init(); if (sz >= PAGETHRESHHOLD - sizeof (struct pageinfo)) { /* block is bigger than threshhold so allocate whole pages */ int pgs = (sz + sizeof (struct pageinfo)+BYTESPERPAGE - 1) / BYTESPERPAGE; void *base = allocpages(pgs); FPRINTF((stderr, "malloc(%d), large block\n", sz)); if (base == NULL) return NULL; pi = (struct pageinfo *)base; pi->blocksize = -1; pi->numblocks = 0; pi->count = pgs; pi->link = NULL; base = (char *)base + sizeof (struct pageinfo); if (g.clearblocks) memset(base, 0, pgs * BYTESPERPAGE - sizeof (struct pageinfo)); #ifdef DO_GC CLEARBITMAP(pi->refbits); ind = PAGENUM(pi); if (ind + pgs >= MAXPAGES) crash("malloc(): out of space for new pages"); SETBIT(g.ourpages, ind); /* all following pages are marked as part of a big block for GC */ for (ind++, i = 1; i < pgs; i++, ind++) CLEARBIT(g.ourpages, ind); #endif return base; } /* search page list for a free block of our size */ nsz = g.sizemap[sz]; if (nsz < sz) nsz = sz; FPRINTF((stderr, "malloc(%d), small block, sz = %d\n", sz, nsz)); ind = nsz / MINBLOCK; ppi = NULL; pi = g.blockmap[ind]; /* search pages with blocks of the given size */ for (; pi != NULL && pi->block == NULL; pi = pi->link) ppi = pi; if (pi == NULL) { if (!getmoreblocks(nsz)) { FPRINTF((stderr, "malloc(%d), no more small blocks\n", sz)); return NULL; } /* this works since getmoreblocks always sticks new pages */ /* at the front of the list */ pi = g.blockmap[ind]; ppi = NULL; } if (ppi != NULL) { /* move page with free blocks to the head of the list so we save time on the next call for this block size. */ ppi->link = pi->link; pi->link = g.blockmap[ind]; g.blockmap[ind] = pi; } ptr = pi->block; pi->block = pi->block->link; pi->count++; if (g.clearblocks) memset(ptr, 0, nsz); FPRINTF((stderr, "malloc(%d), nsz=%d small block=%p\n", sz, nsz, ptr)); return (void *)ptr; }
/* garbage collect using mark & sweep */ void garbagecollect() { static jmp_buf jmp; long stacktop; /* to get the top of stack */ int i, numpgs; struct pageinfo *page; size_t totfree; int arenasz, expandcnt; if (g.ingc || g.heaphigh == NULL) return; g.ingc = TRUE; /* ref bits should already be cleared since we clear them upon return to avoid doing an extra pass over all of memory */ /* this does not go in our "gc" struct as we really do want it searched */ memset(jmp, 0, sizeof jmp); setjmp(jmp); totfree = 0; /* set ref bits of referenced blocks */ gcmarkregion(STACKSTART, STACKEND); for (i = 0; i < g.numregions; i++) { if (g.regions[i].start == NULL) continue; gcmarkregion(g.regions[i].start, g.regions[i].end); } numpgs = PAGENUM(g.heaphigh); page = g.heaplow; /* release unused memory */ for (i = PAGENUM(page); i < numpgs; i++, page = (struct pageinfo *)((char *)page + BYTESPERPAGE)) { if (i >= MAXPAGES) crash("garbagecollect(): out of space for new pages"); if (!GETBIT(g.ourpages, i)) continue; if (page->blocksize == -1) { if (page->refbits[0]) page->refbits[0] = 0; else freepages(page, page->count); } else if (page->blocksize > 0) { int j; int freed = 0; page->block = NULL; for (j = 0; j < page->numblocks; j++) if (!GETBIT(page->refbits, j)) { struct freeblock *e = (struct freeblock *) ((char *)page + sizeof (struct pageinfo)+ page->blocksize * j); if (g.clearfree) memset(e, 0, page->blocksize); e->link = page->block; page->block = e; freed++; } CLEARBITMAP(page->refbits); if (freed == page->numblocks) freeblockspage(page); else { page->count = page->numblocks - freed; totfree += freed * page->blocksize; } } } /* rebuildfreelist(); */ g.ingc = FALSE; totfree += g.numfreepages * BYTESPERPAGE; arenasz = ((char *)g.heaphigh - (char *)g.heaplow) / BYTESPERPAGE; expandcnt = arenasz * g.percent; expandcnt /= 100; if (g.freepagelist == NULL) { /* if garbage collection didn't yield a page then allow */ /* heap to grow by g.page or g.percent which ever is larger. */ g.pagecount = (g.pages > expandcnt ? g.pages : expandcnt); } else { /* if garbage collection yielded less than g.percent of the heap */ /* then give the heap some extra growing room. */ expandcnt -= totfree / BYTESPERPAGE; expandcnt -= g.numfreepages; if (g.pagecount < expandcnt) g.pagecount = expandcnt; if (g.pagecount <= 0) g.pagecount = 16; } return; }