//debug = PRINTF; // turn on printf's
//debug = COLLECT_PRINTF; // turn on printf's
-//debug = THREADINVARIANT; // check thread integrity
//debug = LOGGING; // log allocations / frees
//debug = MEMSTOMP; // stomp on memory
//debug = SENTINEL; // add underrun/overrrun protection
version = STACKGROWSDOWN; // growing the stack means subtracting from the stack pointer
// (use for Intel X86 CPUs)
// else growing the stack means adding to the stack pointer
-version = MULTI_THREADED; // produce multithreaded version
/***************************************************/
import gc.bits;
import gc.stats;
import gc.alloc;
+import gc.libc;
-import cstdlib = tango.stdc.stdlib : calloc, free, malloc, realloc;
-import cstring = tango.stdc.string : memcpy, memmove, memset;
-
-debug(THREADINVARIANT) import tango.stdc.posix.pthread;
-debug(PRINTF) import tango.stdc.posix.pthread : pthread_self, pthread_t;
-debug import tango.stdc.stdio : printf;
version (GNU)
{
extern (C) void rt_scanStaticData( scanFn scan );
- version (MULTI_THREADED)
- {
- extern (C) bool thread_needLock();
- extern (C) void thread_suspendAll();
- extern (C) void thread_resumeAll();
+ extern (C) bool thread_needLock();
+ extern (C) void thread_suspendAll();
+ extern (C) void thread_resumeAll();
- extern (C) void thread_scanAll( scanFn fn, void* curStackTop = null );
- }
+ extern (C) void thread_scanAll( scanFn fn, void* curStackTop = null );
extern (C) void onOutOfMemoryError();
void Dtor()
{
if (data)
- cstdlib.free(data);
+ .free(data);
data = null;
}
assert(dim + nentries <= allocdim);
if (!data)
{
- data = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof);
+ data = cast(Log*) .malloc(allocdim * Log.sizeof);
if (!data && allocdim)
onOutOfMemoryError();
}
else
{ Log *newdata;
- newdata = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof);
+ newdata = cast(Log*) .malloc(allocdim * Log.sizeof);
if (!newdata && allocdim)
onOutOfMemoryError();
- cstring.memcpy(newdata, data, dim * Log.sizeof);
- cstdlib.free(data);
+ .memcpy(newdata, data, dim * Log.sizeof);
+ .free(data);
data = newdata;
}
}
void remove(size_t i)
{
- cstring.memmove(data + i, data + i + 1, (dim - i) * Log.sizeof);
+ .memmove(data + i, data + i + 1, (dim - i) * Log.sizeof);
dim--;
}
{
reserve(from.dim - dim);
assert(from.dim <= allocdim);
- cstring.memcpy(data, from.data, from.dim * Log.sizeof);
+ .memcpy(data, from.data, from.dim * Log.sizeof);
dim = from.dim;
}
}
void initialize()
{
gcLock = GCLock.classinfo;
- gcx = cast(Gcx*)cstdlib.calloc(1, Gcx.sizeof);
+ gcx = cast(Gcx*) .calloc(1, Gcx.sizeof);
if (!gcx)
onOutOfMemoryError();
gcx.initialize();
void Dtor()
{
- version (linux)
- {
- //debug(PRINTF) printf("Thread %x ", pthread_self());
- //debug(PRINTF) printf("GC.Dtor()\n");
- }
-
if (gcx)
{
gcx.Dtor();
- cstdlib.free(gcx);
+ .free(gcx);
gcx = null;
}
}
- invariant
- {
- if (gcx)
- {
- gcx.thread_Invariant();
- }
- }
-
-
/**
*
*/
//debug(PRINTF) printf("GC::malloc(size = %d, gcx = %p)\n", size, gcx);
assert(gcx);
- //debug(PRINTF) printf("gcx.self = %x, pthread_self() = %x\n", gcx.self, pthread_self());
size += SENTINEL_EXTRA;
// Return next item from free list
gcx.bucket[bin] = (cast(List*)p).next;
if( !(bits & BlkAttr.NO_SCAN) )
- cstring.memset(p + size, 0, binsize[bin] - size);
+ .memset(p + size, 0, binsize[bin] - size);
//debug(PRINTF) printf("\tmalloc => %x\n", p);
- debug (MEMSTOMP) cstring.memset(p, 0xF0, size);
+ debug (MEMSTOMP) .memset(p, 0xF0, size);
}
else
{
//debug(PRINTF) printf("calloc: %x len %d\n", p, len);
void *p = mallocNoSync(size, bits);
- cstring.memset(p, 0, size);
+ .memset(p, 0, size);
return p;
}
if (psize < size)
size = psize;
//debug(PRINTF) printf("\tcopying %d bytes\n",size);
- cstring.memcpy(p2, p, size);
+ .memcpy(p2, p, size);
p = p2;
}
}
{ // Shrink in place
synchronized (gcLock)
{
- debug (MEMSTOMP) cstring.memset(p + size, 0xF2, psize - size);
+ debug (MEMSTOMP) .memset(p + size, 0xF2, psize - size);
pool.freePages(pagenum + newsz, psz - newsz);
}
return p;
{
if (i == pagenum + newsz)
{
- debug (MEMSTOMP) cstring.memset(p + psize, 0xF0, size - psize);
- cstring.memset(&pool.pagetable[pagenum + psz], B_PAGEPLUS, newsz - psz);
+ debug (MEMSTOMP) .memset(p + psize, 0xF0, size - psize);
+ .memset(&pool.pagetable[pagenum + psz], B_PAGEPLUS, newsz - psz);
return p;
}
- if (i == pool.ncommitted)
+ if (i == pool.npages)
{
- auto u = pool.extendPages(pagenum + newsz - pool.ncommitted);
- if (u == OPFAIL)
- break;
- i = pagenum + newsz;
- continue;
+ break;
}
if (pool.pagetable[i] != B_FREE)
break;
if (psize < size)
size = psize;
//debug(PRINTF) printf("\tcopying %d bytes\n",size);
- cstring.memcpy(p2, p, size);
+ .memcpy(p2, p, size);
p = p2;
}
}
for (sz = 0; sz < maxsz; sz++)
{
auto i = pagenum + psz + sz;
- if (i == pool.ncommitted)
+ if (i == pool.npages)
break;
if (pool.pagetable[i] != B_FREE)
{ if (sz < minsz)
break;
}
}
- if (sz >= minsz)
- {
- }
- else if (pagenum + psz + sz == pool.ncommitted)
- {
- auto u = pool.extendPages(minsz - sz);
- if (u == OPFAIL)
- return 0;
- sz = minsz;
- }
- else
+ if (sz < minsz)
return 0;
- debug (MEMSTOMP) cstring.memset(p + psize, 0xF0, (psz + sz) * PAGESIZE - psize);
- cstring.memset(pool.pagetable + pagenum + psz, B_PAGEPLUS, sz);
+ debug (MEMSTOMP) .memset(p + psize, 0xF0, (psz + sz) * PAGESIZE - psize);
+ .memset(pool.pagetable + pagenum + psz, B_PAGEPLUS, sz);
gcx.p_cache = null;
gcx.size_cache = 0;
return (psz + sz) * PAGESIZE;
// Free pages
npages = 1;
n = pagenum;
- while (++n < pool.ncommitted && pool.pagetable[n] == B_PAGEPLUS)
+ while (++n < pool.npages && pool.pagetable[n] == B_PAGEPLUS)
npages++;
- debug (MEMSTOMP) cstring.memset(p, 0xF2, npages * PAGESIZE);
+ debug (MEMSTOMP) .memset(p, 0xF2, npages * PAGESIZE);
pool.freePages(pagenum, npages);
}
else
{ // Add to free list
List *list = cast(List*)p;
- debug (MEMSTOMP) cstring.memset(p, 0xF2, binsize[bin]);
+ debug (MEMSTOMP) .memset(p, 0xF2, binsize[bin]);
list.next = gcx.bucket[bin];
gcx.bucket[bin] = list;
size_t bsize = 0;
//debug(PRINTF) printf("getStats()\n");
- cstring.memset(&stats, 0, GCStats.sizeof);
+ .memset(&stats, 0, GCStats.sizeof);
for (n = 0; n < gcx.npools; n++)
{ Pool *pool = gcx.pooltable[n];
- psize += pool.ncommitted * PAGESIZE;
- for (size_t j = 0; j < pool.ncommitted; j++)
+ psize += pool.npages * PAGESIZE;
+ for (size_t j = 0; j < pool.npages; j++)
{
Bins bin = cast(Bins)pool.pagetable[j];
if (bin == B_FREE)
enum
{ PAGESIZE = 4096,
- COMMITSIZE = (4096*16),
POOLSIZE = (4096*256),
}
B_PAGE, // start of large alloc
B_PAGEPLUS, // continuation of large alloc
B_FREE, // free page
- B_UNCOMMITTED, // memory not committed for this page
B_MAX
}
struct Gcx
{
- debug (THREADINVARIANT)
- {
- pthread_t self;
- void thread_Invariant()
- {
- if (self != pthread_self())
- printf("thread_Invariant(): gcx = %x, self = %x, pthread_self() = %x\n", this, self, pthread_self());
- assert(self == pthread_self());
- }
- }
- else
- {
- void thread_Invariant() { }
- }
void *p_cache;
size_t size_cache;
(cast(byte*)this)[0 .. Gcx.sizeof] = 0;
stackBottom = cast(char*)&dummy;
log_init();
- debug (THREADINVARIANT)
- self = pthread_self();
//printf("gcx = %p, self = %x\n", this, self);
inited = 1;
}
{ Pool *pool = pooltable[i];
pool.Dtor();
- cstdlib.free(pool);
+ .free(pool);
}
if (pooltable)
- cstdlib.free(pooltable);
+ .free(pooltable);
if (roots)
- cstdlib.free(roots);
+ .free(roots);
if (ranges)
- cstdlib.free(ranges);
+ .free(ranges);
}
//printf("Gcx.invariant(): this = %p\n", this);
size_t i;
- // Assure we're called on the right thread
- debug (THREADINVARIANT) assert(self == pthread_self());
-
for (i = 0; i < npools; i++)
{ Pool *pool = pooltable[i];
size_t newdim = rootdim * 2 + 16;
void** newroots;
- newroots = cast(void**)cstdlib.malloc(newdim * newroots[0].sizeof);
+ newroots = cast(void**) .malloc(newdim * newroots[0].sizeof);
if (!newroots)
onOutOfMemoryError();
if (roots)
- { cstring.memcpy(newroots, roots, nroots * newroots[0].sizeof);
- cstdlib.free(roots);
+ { .memcpy(newroots, roots, nroots * newroots[0].sizeof);
+ .free(roots);
}
roots = newroots;
rootdim = newdim;
if (roots[i] == p)
{
nroots--;
- cstring.memmove(roots + i, roots + i + 1, (nroots - i) * roots[0].sizeof);
+ .memmove(roots + i, roots + i + 1, (nroots - i) * roots[0].sizeof);
return;
}
}
*/
void addRange(void *pbot, void *ptop)
{
- debug(PRINTF) printf("Thread %x ", pthread_self());
- debug(PRINTF) printf("%x.Gcx::addRange(%x, %x), nranges = %d\n", this, pbot, ptop, nranges);
+ debug (PRINTF) printf("%x.Gcx::addRange(%x, %x), nranges = %d\n", this,
+ pbot, ptop, nranges);
if (nranges == rangedim)
{
size_t newdim = rangedim * 2 + 16;
Range *newranges;
- newranges = cast(Range*)cstdlib.malloc(newdim * newranges[0].sizeof);
+ newranges = cast(Range*) .malloc(newdim * newranges[0].sizeof);
if (!newranges)
onOutOfMemoryError();
if (ranges)
- { cstring.memcpy(newranges, ranges, nranges * newranges[0].sizeof);
- cstdlib.free(ranges);
+ { .memcpy(newranges, ranges, nranges * newranges[0].sizeof);
+ .free(ranges);
}
ranges = newranges;
rangedim = newdim;
*/
void removeRange(void *pbot)
{
- debug(PRINTF) printf("Thread %x ", pthread_self());
- debug(PRINTF) printf("%x.Gcx.removeRange(%x), nranges = %d\n", this, pbot, nranges);
+ debug (PRINTF) printf("%x.Gcx.removeRange(%x), nranges = %d\n", this,
+ pbot, nranges);
for (size_t i = nranges; i--;)
{
if (ranges[i].pbot == pbot)
{
nranges--;
- cstring.memmove(ranges + i, ranges + i + 1, (nranges - i) * ranges[0].sizeof);
+ .memmove(ranges + i, ranges + i + 1, (nranges - i) * ranges[0].sizeof);
return;
}
}
}
else
{
- // we are in a B_FREE or B_UNCOMMITTED page
+ // we are in a B_FREE page
return null;
}
}
bin = cast(Bins)pool.pagetable[pagenum];
size = binsize[bin];
if (bin == B_PAGE)
- { size_t npages = pool.ncommitted;
+ {
ubyte* pt;
size_t i;
pt = &pool.pagetable[0];
- for (i = pagenum + 1; i < npages; i++)
+ for (i = pagenum + 1; i < pool.npages; i++)
{
if (pt[i] != B_PAGEPLUS)
break;
info.size = binsize[bin];
if (bin == B_PAGE)
- { size_t npages = pool.ncommitted;
+ {
ubyte* pt;
size_t i;
pt = &pool.pagetable[0];
- for (i = pn + 1; i < npages; i++)
+ for (i = pn + 1; i < pool.npages; i++)
{
if (pt[i] != B_PAGEPLUS)
break;
size_t npages = (size + PAGESIZE - 1) / PAGESIZE;
Pool* pool = newPool(npages);
- if (!pool || pool.extendPages(npages) == OPFAIL)
+ if (!pool)
return 0;
- return pool.ncommitted * PAGESIZE;
+ return pool.npages * PAGESIZE;
}
size_t n;
size_t pn;
Pool* pool;
- size_t ncommitted;
for (n = 0; n < npools; n++)
{
pool = pooltable[n];
- ncommitted = pool.ncommitted;
- for (pn = 0; pn < ncommitted; pn++)
+ for (pn = 0; pn < pool.npages; pn++)
{
if (cast(Bins)pool.pagetable[pn] != B_FREE)
break;
}
- if (pn < ncommitted)
+ if (pn < pool.npages)
{
n++;
continue;
}
pool.Dtor();
- cstdlib.free(pool);
- cstring.memmove(pooltable + n,
+ .free(pool);
+ .memmove(pooltable + n,
pooltable + n + 1,
(--npools - n) * (Pool*).sizeof);
minAddr = pooltable[0].baseAddr;
L1:
pool.pagetable[pn] = B_PAGE;
if (npages > 1)
- cstring.memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1);
+ .memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1);
p = pool.baseAddr + pn * PAGESIZE;
- cstring.memset(cast(char *)p + size, 0, npages * PAGESIZE - size);
- debug (MEMSTOMP) cstring.memset(p, 0xF1, size);
+ .memset(cast(char *)p + size, 0, npages * PAGESIZE - size);
+ debug (MEMSTOMP) .memset(p, 0xF1, size);
//debug(PRINTF) printf("\tp = %x\n", p);
return p;
//debug(PRINTF) printf("************Gcx::newPool(npages = %d)****************\n", npages);
- // Round up to COMMITSIZE pages
- npages = (npages + (COMMITSIZE/PAGESIZE) - 1) & ~(COMMITSIZE/PAGESIZE - 1);
-
// Minimum of POOLSIZE
if (npages < POOLSIZE/PAGESIZE)
npages = POOLSIZE/PAGESIZE;
npages = n;
}
- pool = cast(Pool *)cstdlib.calloc(1, Pool.sizeof);
+ pool = cast(Pool *) .calloc(1, Pool.sizeof);
if (pool)
{
pool.initialize(npages);
goto Lerr;
newnpools = npools + 1;
- newpooltable = cast(Pool **)cstdlib.realloc(pooltable, newnpools * (Pool *).sizeof);
+ newpooltable = cast(Pool **) .realloc(pooltable, newnpools * (Pool *).sizeof);
if (!newpooltable)
goto Lerr;
if (pool.opCmp(newpooltable[i]) < 0)
break;
}
- cstring.memmove(newpooltable + i + 1, newpooltable + i, (npools - i) * (Pool *).sizeof);
+ .memmove(newpooltable + i + 1, newpooltable + i, (npools - i) * (Pool *).sizeof);
newpooltable[i] = pool;
pooltable = newpooltable;
Lerr:
pool.Dtor();
- cstdlib.free(pool);
+ .free(pool);
return null;
}
}
else
{
- // Don't mark bits in B_FREE or B_UNCOMMITTED pages
+ // Don't mark bits in B_FREE pages
continue;
}
rt_scanStaticData( &mark );
- version (MULTI_THREADED)
- {
- if (!noStack)
- {
- // Scan stacks and registers for each paused thread
- thread_scanAll( &mark, stackTop );
- }
- }
- else
+ if (!noStack)
{
- if (!noStack)
- {
- // Scan stack for main thread
- debug(PRINTF) printf(" scan stack bot = %x, top = %x\n", stackTop, stackBottom);
- version (STACKGROWSDOWN)
- mark(stackTop, stackBottom);
- else
- mark(stackBottom, stackTop);
- }
+ // Scan stacks and registers for each paused thread
+ thread_scanAll( &mark, stackTop );
}
// Scan roots[]
pn--;
}
u = 1;
- while (pn + u < pool.ncommitted && pool.pagetable[pn + u] == B_PAGEPLUS)
+ while (pn + u < pool.npages && pool.pagetable[pn + u] == B_PAGEPLUS)
u++;
mark(o, o + u * PAGESIZE);
}
size_t freed = 0;
for (n = 0; n < npools; n++)
{ size_t pn;
- size_t ncommitted;
uint* bbase;
pool = pooltable[n];
bbase = pool.mark.base();
- ncommitted = pool.ncommitted;
- for (pn = 0; pn < ncommitted; pn++, bbase += PAGESIZE / (32 * 16))
+ for (pn = 0; pn < pool.npages; pn++, bbase += PAGESIZE / (32 * 16))
{
Bins bin = cast(Bins)pool.pagetable[pn];
//debug(PRINTF) printf("\tcollecting %x\n", list);
log_free(sentinel_add(list));
- debug (MEMSTOMP) cstring.memset(p, 0xF3, size);
+ debug (MEMSTOMP) .memset(p, 0xF3, size);
}
pool.pagetable[pn] = B_FREE;
freed += PAGESIZE;
debug(PRINTF) printf("\tcollecting %x\n", list);
log_free(sentinel_add(list));
- debug (MEMSTOMP) cstring.memset(p, 0xF3, size);
+ debug (MEMSTOMP) .memset(p, 0xF3, size);
freed += size;
}
log_free(sentinel_add(p));
pool.pagetable[pn] = B_FREE;
freedpages++;
- debug (MEMSTOMP) cstring.memset(p, 0xF3, PAGESIZE);
- while (pn + 1 < ncommitted && pool.pagetable[pn + 1] == B_PAGEPLUS)
+ debug (MEMSTOMP) .memset(p, 0xF3, PAGESIZE);
+ while (pn + 1 < pool.npages && pool.pagetable[pn + 1] == B_PAGEPLUS)
{
pn++;
pool.pagetable[pn] = B_FREE;
debug (MEMSTOMP)
{ p += PAGESIZE;
- cstring.memset(p, 0xF3, PAGESIZE);
+ .memset(p, 0xF3, PAGESIZE);
}
}
}
size_t recoveredpages = 0;
for (n = 0; n < npools; n++)
{ size_t pn;
- size_t ncommitted;
pool = pooltable[n];
- ncommitted = pool.ncommitted;
- for (pn = 0; pn < ncommitted; pn++)
+ for (pn = 0; pn < pool.npages; pn++)
{
Bins bin = cast(Bins)pool.pagetable[pn];
size_t biti;
GCBits noscan; // entries that should not be scanned
size_t npages;
- size_t ncommitted; // ncommitted <= npages
ubyte* pagetable;
freebits.alloc(cast(size_t)poolsize / 16);
noscan.alloc(cast(size_t)poolsize / 16);
- pagetable = cast(ubyte*)cstdlib.malloc(npages);
+ pagetable = cast(ubyte*) .malloc(npages);
if (!pagetable)
onOutOfMemoryError();
- cstring.memset(pagetable, B_UNCOMMITTED, npages);
+ .memset(pagetable, B_FREE, npages);
this.npages = npages;
- ncommitted = 0;
}
{
int result;
- if (ncommitted)
- {
- result = os_mem_decommit(baseAddr, 0, ncommitted * PAGESIZE);
- assert(result == 0);
- ncommitted = 0;
- }
-
if (npages)
{
result = os_mem_unmap(baseAddr, npages * PAGESIZE);
- assert(result == 0);
+ assert(result);
npages = 0;
}
topAddr = null;
}
if (pagetable)
- cstdlib.free(pagetable);
+ .free(pagetable);
mark.Dtor();
scan.Dtor();
//if (baseAddr + npages * PAGESIZE != topAddr)
//printf("baseAddr = %p, npages = %d, topAddr = %p\n", baseAddr, npages, topAddr);
assert(baseAddr + npages * PAGESIZE == topAddr);
- assert(ncommitted <= npages);
}
for (size_t i = 0; i < npages; i++)
//debug(PRINTF) printf("Pool::allocPages(n = %d)\n", n);
n2 = n;
- for (i = 0; i < ncommitted; i++)
+ for (i = 0; i < npages; i++)
{
if (pagetable[i] == B_FREE)
{
else
n2 = n;
}
- return extendPages(n);
- }
-
- /**
- * Extend Pool by n pages.
- * Returns OPFAIL on failure.
- */
- size_t extendPages(size_t n)
- {
- //debug(PRINTF) printf("Pool::extendPages(n = %d)\n", n);
- if (ncommitted + n <= npages)
- {
- size_t tocommit;
-
- tocommit = (n + (COMMITSIZE/PAGESIZE) - 1) & ~(COMMITSIZE/PAGESIZE - 1);
- if (ncommitted + tocommit > npages)
- tocommit = npages - ncommitted;
- //debug(PRINTF) printf("\tlooking to commit %d more pages\n", tocommit);
- //fflush(stdout);
- if (os_mem_commit(baseAddr, ncommitted * PAGESIZE, tocommit * PAGESIZE) == 0)
- {
- cstring.memset(pagetable + ncommitted, B_FREE, tocommit);
- auto i = ncommitted;
- ncommitted += tocommit;
-
- while (i && pagetable[i - 1] == B_FREE)
- i--;
-
- return i;
- }
- //debug(PRINTF) printf("\tfailed to commit %d pages\n", tocommit);
- }
-
return OPFAIL;
}
*/
void freePages(size_t pagenum, size_t npages)
{
- cstring.memset(&pagetable[pagenum], B_FREE, npages);
+ .memset(&pagetable[pagenum], B_FREE, npages);
}