X-Git-Url: https://git.llucax.com/software/dgc/cdgc.git/blobdiff_plain/67f00b96c70725ee445641a158a97fe4f6e735d3..b5e1601adc7b579e9d2366aa2529b07ee6f47fe3:/rt/gc/cdgc/gc.d diff --git a/rt/gc/cdgc/gc.d b/rt/gc/cdgc/gc.d index dbcd518..267b42f 100644 --- a/rt/gc/cdgc/gc.d +++ b/rt/gc/cdgc/gc.d @@ -99,32 +99,29 @@ package bool has_pointermap(uint attrs) private { - - extern (C) void* rt_stackBottom(); - extern (C) void* rt_stackTop(); - - extern (C) void rt_finalize( void* p, bool det = true ); - alias void delegate(Object) DEvent; - extern (C) void rt_attachDisposeEvent(Object h, DEvent e); - extern (C) bool rt_detachDisposeEvent(Object h, DEvent e); - - alias void delegate( void*, void* ) scanFn; + enum { OPFAIL = ~cast(size_t)0 } - extern (C) void rt_scanStaticData( scanFn scan ); - - extern (C) bool thread_needLock(); - extern (C) void thread_suspendAll(); - extern (C) void thread_resumeAll(); + extern (C) + { + version (DigitalMars) version(OSX) + oid _d_osx_image_init(); - extern (C) void thread_scanAll( scanFn fn, void* curStackTop = null ); + void* rt_stackBottom(); + void* rt_stackTop(); + void rt_finalize( void* p, bool det = true ); + void rt_attachDisposeEvent(Object h, DEvent e); + bool rt_detachDisposeEvent(Object h, DEvent e); + void rt_scanStaticData( scanFn scan ); - extern (C) void onOutOfMemoryError(); + void thread_init(); + bool thread_needLock(); + void thread_suspendAll(); + void thread_resumeAll(); + void thread_scanAll( scanFn fn, void* curStackTop = null ); - enum - { - OPFAIL = ~cast(size_t)0 + void onOutOfMemoryError(); } } @@ -218,6 +215,15 @@ struct GC Stats stats; } +// call locked if necessary +private T locked(T, alias Code)() +{ + if (thread_needLock()) + synchronized (gc.lock) return Code(); + else + return Code(); +} + private GC* gc; bool Invariant() @@ -283,144 +289,21 @@ Pool *findPool(void *p) /** - * Find base address of block containing pointer p. - * Returns null if not a gc'd pointer - */ -void* findBase(void *p) -{ - Pool *pool; - - pool = findPool(p); - if (pool) - { - size_t offset = cast(size_t)(p - pool.baseAddr); - size_t pn = offset / PAGESIZE; - Bins bin = cast(Bins)pool.pagetable[pn]; - - // Adjust bit to be at start of allocated memory block - if (bin <= B_PAGE) - { - return pool.baseAddr + (offset & notbinsize[bin]); - } - else if (bin == B_PAGEPLUS) - { - do - { - --pn, offset -= PAGESIZE; - } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS); - - return pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1))); - } - else - { - // we are in a B_FREE page - return null; - } - } - return null; -} - - -/** - * Find size of pointer p. - * Returns 0 if not a gc'd pointer - */ -size_t findSize(void *p) -{ - Pool* pool; - size_t size = 0; - - pool = findPool(p); - if (pool) - { - size_t pagenum; - Bins bin; - - pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE; - bin = cast(Bins)pool.pagetable[pagenum]; - size = binsize[bin]; - if (bin == B_PAGE) - { - ubyte* pt; - size_t i; - - pt = &pool.pagetable[0]; - for (i = pagenum + 1; i < pool.npages; i++) - { - if (pt[i] != B_PAGEPLUS) - break; - } - size = (i - pagenum) * PAGESIZE; - } - } - return size; -} - - -/** - * + * Determine the base address of the block containing p. If p is not a gc + * allocated pointer, return null. */ BlkInfo getInfo(void* p) { - Pool* pool; + assert (p !is null); + Pool* pool = findPool(p); + if (pool is null) + return BlkInfo.init; BlkInfo info; - - pool = findPool(p); - if (pool) - { - size_t offset = cast(size_t)(p - pool.baseAddr); - size_t pn = offset / PAGESIZE; - Bins bin = cast(Bins)pool.pagetable[pn]; - - //////////////////////////////////////////////////////////////////// - // findAddr - //////////////////////////////////////////////////////////////////// - - if (bin <= B_PAGE) - { - info.base = pool.baseAddr + (offset & notbinsize[bin]); - } - else if (bin == B_PAGEPLUS) - { - do - { - --pn, offset -= PAGESIZE; - } - while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS); - - info.base = pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1))); - - // fix bin for use by size calc below - bin = cast(Bins)pool.pagetable[pn]; - } - - //////////////////////////////////////////////////////////////////// - // findSize - //////////////////////////////////////////////////////////////////// - - info.size = binsize[bin]; - if (bin == B_PAGE) - { - ubyte* pt; - size_t i; - - pt = &pool.pagetable[0]; - for (i = pn + 1; i < pool.npages; i++) - { - if (pt[i] != B_PAGEPLUS) - break; - } - info.size = (i - pn) * PAGESIZE; - } - - //////////////////////////////////////////////////////////////////// - // getAttr - //////////////////////////////////////////////////////////////////// - - info.attr = getAttr(pool, cast(size_t)(offset / 16)); - if (!(info.attr & BlkAttr.NO_SCAN)) - info.size -= (size_t*).sizeof; // bitmask - } + info.base = pool.findBase(p); + info.size = pool.findSize(info.base); + info.attr = getAttr(pool, cast(size_t)(info.base - pool.baseAddr) / 16u); + if (!opts.options.conservative && !(info.attr & BlkAttr.NO_SCAN)) + info.size -= size_t.sizeof; // PointerMap bitmask return info; } @@ -477,7 +360,7 @@ static Bins findBin(size_t size) * Mark all memory in the pool as B_FREE. * Return the actual number of bytes reserved or 0 on error. */ -size_t reserveNoSync(size_t size) +size_t reserve(size_t size) { assert(size != 0); size_t npages = (size + PAGESIZE - 1) / PAGESIZE; @@ -492,7 +375,7 @@ size_t reserveNoSync(size_t size) /** * Minimizes physical memory usage by returning free pools to the OS. */ -void minimizeNoSync() +void minimize() { size_t n; size_t pn; @@ -1276,172 +1159,10 @@ void initialize() } -/** - * - */ -void enable() -{ - if (!thread_needLock()) - { - assert(gc.disabled > 0); - gc.disabled--; - } - else synchronized (gc.lock) - { - assert(gc.disabled > 0); - gc.disabled--; - } -} - - -/** - * - */ -void disable() -{ - if (!thread_needLock()) - { - gc.disabled++; - } - else synchronized (gc.lock) - { - gc.disabled++; - } -} - - -/** - * - */ -uint getAttr(void* p) -{ - if (!p) - { - return 0; - } - - uint go() - { - Pool* pool = findPool(p); - uint old_attrs = 0; - - if (pool) - { - auto bit_i = cast(size_t)(p - pool.baseAddr) / 16; - - old_attrs = getAttr(pool, bit_i); - } - return old_attrs; - } - - if (!thread_needLock()) - { - return go(); - } - else synchronized (gc.lock) - { - return go(); - } -} - - -/** - * - */ -uint setAttr(void* p, uint mask) -{ - if (!p) - { - return 0; - } - - uint go() - { - Pool* pool = findPool(p); - uint old_attrs = 0; - - if (pool) - { - auto bit_i = cast(size_t)(p - pool.baseAddr) / 16; - - old_attrs = getAttr(pool, bit_i); - setAttr(pool, bit_i, mask); - } - return old_attrs; - } - - if (!thread_needLock()) - { - return go(); - } - else synchronized (gc.lock) - { - return go(); - } -} - - -/** - * - */ -uint clrAttr(void* p, uint mask) -{ - if (!p) - { - return 0; - } - - uint go() - { - Pool* pool = findPool(p); - uint old_attrs = 0; - - if (pool) - { - auto bit_i = cast(size_t)(p - pool.baseAddr) / 16; - - old_attrs = getAttr(pool, bit_i); - clrAttr(pool, bit_i, mask); - } - return old_attrs; - } - - if (!thread_needLock()) - { - return go(); - } - else synchronized (gc.lock) - { - return go(); - } -} - - -/** - * - */ -void *malloc(size_t size, uint attrs, PointerMap ptrmap) -{ - if (!size) - { - return null; - } - - if (!thread_needLock()) - { - return mallocNoSync(size, attrs, ptrmap.bits.ptr); - } - else synchronized (gc.lock) - { - return mallocNoSync(size, attrs, ptrmap.bits.ptr); - } -} - - // // // -private void *mallocNoSync(size_t size, uint attrs, size_t* pm_bitmask) +private void *malloc(size_t size, uint attrs, size_t* pm_bitmask) { assert(size != 0); @@ -1549,73 +1270,36 @@ private void *mallocNoSync(size_t size, uint attrs, size_t* pm_bitmask) } -/** - * - */ -void *calloc(size_t size, uint attrs, PointerMap ptrmap) -{ - if (!size) - { - return null; - } - - if (!thread_needLock()) - { - return callocNoSync(size, attrs, ptrmap.bits.ptr); - } - else synchronized (gc.lock) - { - return callocNoSync(size, attrs, ptrmap.bits.ptr); - } -} - - // // // -private void *callocNoSync(size_t size, uint attrs, size_t* pm_bitmask) +private void *calloc(size_t size, uint attrs, size_t* pm_bitmask) { assert(size != 0); - void *p = mallocNoSync(size, attrs, pm_bitmask); + void *p = malloc(size, attrs, pm_bitmask); memset(p, 0, size); return p; } -/** - * - */ -void *realloc(void *p, size_t size, uint attrs, PointerMap ptrmap) -{ - if (!thread_needLock()) - { - return reallocNoSync(p, size, attrs, ptrmap.bits.ptr); - } - else synchronized (gc.lock) - { - return reallocNoSync(p, size, attrs, ptrmap.bits.ptr); - } -} - - // // // -private void *reallocNoSync(void *p, size_t size, uint attrs, +private void *realloc(void *p, size_t size, uint attrs, size_t* pm_bitmask) { if (!size) { if (p) { - freeNoSync(p); + free(p); p = null; } } else if (!p) { - p = mallocNoSync(size, attrs, pm_bitmask); + p = malloc(size, attrs, pm_bitmask); } else { @@ -1632,8 +1316,8 @@ private void *reallocNoSync(void *p, size_t size, uint attrs, else attrs = getAttr(pool, bit_i); - void* blk_base_addr = findBase(p); - size_t blk_size = findSize(p); + void* blk_base_addr = pool.findBase(p); + size_t blk_size = pool.findSize(p); bool has_pm = has_pointermap(attrs); size_t pm_bitmask_size = 0; if (has_pm) { @@ -1652,7 +1336,7 @@ private void *reallocNoSync(void *p, size_t size, uint attrs, size_t sentinel_stored_size = *sentinel_size(p); if (sentinel_stored_size != size) { - void* p2 = mallocNoSync(size, attrs, pm_bitmask); + void* p2 = malloc(size, attrs, pm_bitmask); if (sentinel_stored_size < size) size = sentinel_stored_size; cstring.memcpy(p2, p, size); @@ -1674,13 +1358,10 @@ private void *reallocNoSync(void *p, size_t size, uint attrs, if (newsz < psz) { // Shrink in place - synchronized (gc.lock) - { - if (opts.options.mem_stomp) - memset(p + size - pm_bitmask_size, 0xF2, - blk_size - size - pm_bitmask_size); - pool.freePages(pagenum + newsz, psz - newsz); - } + if (opts.options.mem_stomp) + memset(p + size - pm_bitmask_size, 0xF2, + blk_size - size - pm_bitmask_size); + pool.freePages(pagenum + newsz, psz - newsz); if (has_pm) { auto end_of_blk = cast(size_t**)( blk_base_addr + (PAGESIZE * newsz) - @@ -1692,35 +1373,32 @@ private void *reallocNoSync(void *p, size_t size, uint attrs, else if (pagenum + newsz <= pool.npages) { // Attempt to expand in place - synchronized (gc.lock) + for (size_t i = pagenum + psz; 1;) { - for (size_t i = pagenum + psz; 1;) + if (i == pagenum + newsz) { - if (i == pagenum + newsz) - { - if (opts.options.mem_stomp) - memset(p + blk_size - pm_bitmask_size, - 0xF0, size - blk_size - - pm_bitmask_size); - memset(pool.pagetable + pagenum + - psz, B_PAGEPLUS, newsz - psz); - if (has_pm) { - auto end_of_blk = cast(size_t**)( - blk_base_addr + - (PAGESIZE * newsz) - - pm_bitmask_size); - *end_of_blk = pm_bitmask; - } - return p; + if (opts.options.mem_stomp) + memset(p + blk_size - pm_bitmask_size, + 0xF0, size - blk_size + - pm_bitmask_size); + memset(pool.pagetable + pagenum + + psz, B_PAGEPLUS, newsz - psz); + if (has_pm) { + auto end_of_blk = cast(size_t**)( + blk_base_addr + + (PAGESIZE * newsz) - + pm_bitmask_size); + *end_of_blk = pm_bitmask; } - if (i == pool.npages) - { - break; - } - if (pool.pagetable[i] != B_FREE) - break; - i++; + return p; + } + if (i == pool.npages) + { + break; } + if (pool.pagetable[i] != B_FREE) + break; + i++; } } } @@ -1729,7 +1407,7 @@ private void *reallocNoSync(void *p, size_t size, uint attrs, { size -= pm_bitmask_size; blk_size -= pm_bitmask_size; - void* p2 = mallocNoSync(size, attrs, pm_bitmask); + void* p2 = malloc(size, attrs, pm_bitmask); if (blk_size < size) size = blk_size; cstring.memcpy(p2, p, size); @@ -1743,30 +1421,14 @@ private void *reallocNoSync(void *p, size_t size, uint attrs, /** * Attempt to in-place enlarge the memory block pointed to by p by at least - * minbytes beyond its current capacity, up to a maximum of maxsize. This + * min_size beyond its current capacity, up to a maximum of max_size. This * does not attempt to move the memory block (like realloc() does). * * Returns: * 0 if could not extend p, * total size of entire memory block if successful. */ -size_t extend(void* p, size_t minsize, size_t maxsize) -{ - if (!thread_needLock()) - { - return extendNoSync(p, minsize, maxsize); - } - else synchronized (gc.lock) - { - return extendNoSync(p, minsize, maxsize); - } -} - - -// -// -// -private size_t extendNoSync(void* p, size_t minsize, size_t maxsize) +private size_t extend(void* p, size_t minsize, size_t maxsize) in { assert( minsize <= maxsize ); @@ -1784,8 +1446,8 @@ body auto bit_i = cast(size_t)(p - pool.baseAddr) / 16; uint attrs = getAttr(pool, bit_i); - void* blk_base_addr = findBase(p); - size_t blk_size = findSize(p); + void* blk_base_addr = pool.findBase(p); + size_t blk_size = pool.findSize(p); bool has_pm = has_pointermap(attrs); size_t* pm_bitmask = null; size_t pm_bitmask_size = 0; @@ -1843,52 +1505,10 @@ body } -/** - * - */ -size_t reserve(size_t size) -{ - if (!size) - { - return 0; - } - - if (!thread_needLock()) - { - return reserveNoSync(size); - } - else synchronized (gc.lock) - { - return reserveNoSync(size); - } -} - - -/** - * - */ -void free(void *p) -{ - if (!p) - { - return; - } - - if (!thread_needLock()) - { - return freeNoSync(p); - } - else synchronized (gc.lock) - { - return freeNoSync(p); - } -} - - // // // -private void freeNoSync(void *p) +private void free(void *p) { assert (p); @@ -1935,68 +1555,11 @@ private void freeNoSync(void *p) } -/** - * Determine the base address of the block containing p. If p is not a gc - * allocated pointer, return null. - */ -void* addrOf(void *p) -{ - if (!p) - { - return null; - } - - if (!thread_needLock()) - { - return addrOfNoSync(p); - } - else synchronized (gc.lock) - { - return addrOfNoSync(p); - } -} - - -// -// -// -void* addrOfNoSync(void *p) -{ - if (!p) - { - return null; - } - - return findBase(p); -} - - /** * Determine the allocated size of pointer p. If p is an interior pointer * or not a gc allocated pointer, return 0. */ -size_t sizeOf(void *p) -{ - if (!p) - { - return 0; - } - - if (!thread_needLock()) - { - return sizeOfNoSync(p); - } - else synchronized (gc.lock) - { - return sizeOfNoSync(p); - } -} - - -// -// -// -private size_t sizeOfNoSync(void *p) +private size_t sizeOf(void *p) { assert (p); @@ -2010,7 +1573,7 @@ private size_t sizeOfNoSync(void *p) auto biti = cast(size_t)(p - pool.baseAddr) / 16; uint attrs = getAttr(pool, biti); - size_t size = findSize(p); + size_t size = pool.findSize(p); size_t pm_bitmask_size = 0; if (has_pointermap(attrs)) pm_bitmask_size = size_t.sizeof; @@ -2043,67 +1606,12 @@ private size_t sizeOfNoSync(void *p) } -/** - * Determine the base address of the block containing p. If p is not a gc - * allocated pointer, return null. - */ -BlkInfo query(void *p) -{ - if (!p) - { - BlkInfo i; - return i; - } - - if (!thread_needLock()) - { - return queryNoSync(p); - } - else synchronized (gc.lock) - { - return queryNoSync(p); - } -} - - -// -// -// -BlkInfo queryNoSync(void *p) -{ - assert(p); - - return getInfo(p); -} - - /** * Verify that pointer p: * 1) belongs to this memory pool * 2) points to the start of an allocated piece of memory * 3) is not on a free list */ -void check(void *p) -{ - if (!p) - { - return; - } - - if (!thread_needLock()) - { - checkNoSync(p); - } - else synchronized (gc.lock) - { - checkNoSync(p); - } -} - - -// -// -// private void checkNoSync(void *p) { assert(p); @@ -2168,180 +1676,13 @@ private void setStackBottom(void *p) } -/** - * add p to list of roots - */ -void addRoot(void *p) -{ - if (!p) - { - return; - } - - if (!thread_needLock()) - { - if (gc.roots.append(p) is null) - onOutOfMemoryError(); - } - else synchronized (gc.lock) - { - if (gc.roots.append(p) is null) - onOutOfMemoryError(); - } -} - - -/** - * remove p from list of roots - */ -void removeRoot(void *p) -{ - if (!p) - { - return; - } - - bool r; - if (!thread_needLock()) - { - r = gc.roots.remove(p); - } - else synchronized (gc.lock) - { - r = gc.roots.remove(p); - } - assert (r); -} - - -/** - * add range to scan for roots - */ -void addRange(void *p, size_t sz) -{ - if (!p || !sz) - { - return; - } - - if (!thread_needLock()) - { - if (gc.ranges.append(Range(p, p+sz)) is null) - onOutOfMemoryError(); - } - else synchronized (gc.lock) - { - if (gc.ranges.append(Range(p, p+sz)) is null) - onOutOfMemoryError(); - } -} - - -/** - * remove range - */ -void removeRange(void *p) -{ - if (!p) - { - return; - } - - bool r; - if (!thread_needLock()) - { - r = gc.ranges.remove(Range(p, null)); - } - else synchronized (gc.lock) - { - r = gc.ranges.remove(Range(p, null)); - } - assert (r); -} - - -/** - * do full garbage collection - */ -void fullCollect() -{ - - if (!thread_needLock()) - { - fullcollectshell(); - } - else synchronized (gc.lock) - { - fullcollectshell(); - } - - version (none) - { - GCStats stats; - getStats(stats); - } - -} - - -/** - * do full garbage collection ignoring roots - */ -void fullCollectNoStack() -{ - if (!thread_needLock()) - { - gc.no_stack++; - fullcollectshell(); - gc.no_stack--; - } - else synchronized (gc.lock) - { - gc.no_stack++; - fullcollectshell(); - gc.no_stack--; - } -} - - -/** - * minimize free space usage - */ -void minimize() -{ - if (!thread_needLock()) - { - minimizeNoSync(); - } - else synchronized (gc.lock) - { - minimizeNoSync(); - } -} - - /** * Retrieve statistics about garbage collection. * Useful for debugging and tuning. */ -void getStats(out GCStats stats) -{ - if (!thread_needLock()) - { - getStatsNoSync(stats); - } - else synchronized (gc.lock) - { - getStatsNoSync(stats); - } -} - - -// -// -// -private void getStatsNoSync(out GCStats stats) +private GCStats getStats() { + GCStats stats; size_t psize = 0; size_t usize = 0; size_t flsize = 0; @@ -2349,8 +1690,6 @@ private void getStatsNoSync(out GCStats stats) size_t n; size_t bsize = 0; - memset(&stats, 0, GCStats.sizeof); - for (n = 0; n < gc.pools.length; n++) { Pool* pool = gc.pools[n]; @@ -2378,19 +1717,11 @@ private void getStatsNoSync(out GCStats stats) stats.poolsize = psize; stats.usedsize = bsize - flsize; stats.freelistsize = flsize; + return stats; } /******************* weak-reference support *********************/ -// call locked if necessary -private T locked(T)(in T delegate() code) -{ - if (thread_needLock) - synchronized(gc.lock) return code(); - else - return code(); -} - private struct WeakPointer { Object reference; @@ -2401,7 +1732,9 @@ private struct WeakPointer // lock for memory consistency (parallel readers) // also ensures that weakpointerDestroy can be called while another // thread is freeing the reference with "delete" - locked!(void)({ reference = null; }); + return locked!(void, () { + reference = null; + })(); } } @@ -2438,10 +1771,10 @@ void weakpointerDestroy( void* p ) auto wp = cast(WeakPointer*)p; // must be extra careful about the GC or parallel threads // finalizing the reference at the same time - locked!(void)({ - if (wp.reference) - rt_detachDisposeEvent(wp.reference, &wp.ondestroy); - }); + return locked!(void, () { + if (wp.reference) + rt_detachDisposeEvent(wp.reference, &wp.ondestroy); + })(); cstdlib.free(wp); } } @@ -2459,9 +1792,9 @@ Object weakpointerGet( void* p ) // that'd require core.sync.Atomic and lots of care about memory // consistency it's an optional optimization see // http://dsource.org/projects/tango/browser/trunk/user/tango/core/Lifetime.d?rev=5100#L158 - return locked!(Object)({ - return (cast(WeakPointer*)p).reference; - }); + return locked!(Object, () { + return (cast(WeakPointer*)p).reference; + })(); } } @@ -2604,6 +1937,47 @@ struct Pool } + /** + * Find base address of block containing pointer p. + * Returns null if the pointer doesn't belong to this pool + */ + void* findBase(void *p) + { + size_t offset = cast(size_t)(p - this.baseAddr); + size_t pagenum = offset / PAGESIZE; + Bins bin = cast(Bins)this.pagetable[pagenum]; + // Adjust bit to be at start of allocated memory block + if (bin <= B_PAGE) + return this.baseAddr + (offset & notbinsize[bin]); + if (bin == B_PAGEPLUS) { + do { + --pagenum, offset -= PAGESIZE; + } while (cast(Bins)this.pagetable[pagenum] == B_PAGEPLUS); + return this.baseAddr + (offset & (offset.max ^ (PAGESIZE-1))); + } + // we are in a B_FREE page + return null; + } + + + /** + * Find size of pointer p. + * Returns 0 if p doesn't belong to this pool if if it's block size is less + * than a PAGE. + */ + size_t findSize(void *p) + { + size_t pagenum = cast(size_t)(p - this.baseAddr) / PAGESIZE; + Bins bin = cast(Bins)this.pagetable[pagenum]; + if (bin != B_PAGE) + return binsize[bin]; + for (size_t i = pagenum + 1; i < this.npages; i++) + if (this.pagetable[i] != B_PAGEPLUS) + return (i - pagenum) * PAGESIZE; + return (this.npages - pagenum) * PAGESIZE; + } + + /** * Used for sorting pools */ @@ -2663,27 +2037,27 @@ void *sentinel_sub(void *p) private int _termCleanupLevel=1; +extern (C): + /// sets the cleanup level done by gc -/// (0: none, 1: fullCollect, 2: fullCollectNoStack (might crash daemonThreads)) +/// 0: none +/// 1: fullCollect +/// 2: fullCollect ignoring stack roots (might crash daemonThreads) /// result !=0 if the value was invalid -extern (C) int gc_setTermCleanupLevel(int cLevel){ +int gc_setTermCleanupLevel(int cLevel) +{ if (cLevel<0 || cLevel>2) return cLevel; _termCleanupLevel=cLevel; return 0; } /// returns the cleanup level done by gc -extern (C) int gc_getTermCleanupLevel(){ +int gc_getTermCleanupLevel() +{ return _termCleanupLevel; } -version (DigitalMars) version(OSX) { - extern(C) void _d_osx_image_init(); -} - -extern (C) void thread_init(); - -extern (C) void gc_init() +void gc_init() { scope (exit) assert (Invariant()); gc = cast(GC*) cstdlib.calloc(1, GC.sizeof); @@ -2697,7 +2071,7 @@ extern (C) void gc_init() thread_init(); } -extern (C) void gc_term() +void gc_term() { assert (Invariant()); if (_termCleanupLevel<1) { @@ -2714,163 +2088,262 @@ extern (C) void gc_term() // I'm disabling cleanup for now until I can think about it some // more. // - fullCollectNoStack(); // not really a 'collect all' -- still scans - // static data area, roots, and ranges. + // not really a 'collect all' -- still scans static data area, roots, + // and ranges. + return locked!(void, () { + gc.no_stack++; + fullcollectshell(); + gc.no_stack--; + })(); } else { // default (safe) clenup - fullCollect(); + return locked!(void, () { + fullcollectshell(); + })(); } } -extern (C) void gc_enable() +void gc_enable() { - assert (Invariant()); scope (exit) assert (Invariant()); - enable(); + return locked!(void, () { + assert (Invariant()); scope (exit) assert (Invariant()); + assert (gc.disabled > 0); + gc.disabled--; + })(); } -extern (C) void gc_disable() +void gc_disable() { - assert (Invariant()); scope (exit) assert (Invariant()); - disable(); + return locked!(void, () { + assert (Invariant()); scope (exit) assert (Invariant()); + gc.disabled++; + })(); } -extern (C) void gc_collect() +void gc_collect() { - assert (Invariant()); scope (exit) assert (Invariant()); - fullCollect(); + return locked!(void, () { + assert (Invariant()); scope (exit) assert (Invariant()); + fullcollectshell(); + })(); } -extern (C) void gc_minimize() +void gc_minimize() { - assert (Invariant()); scope (exit) assert (Invariant()); - minimize(); + return locked!(void, () { + assert (Invariant()); scope (exit) assert (Invariant()); + minimize(); + })(); } -extern (C) uint gc_getAttr( void* p ) +uint gc_getAttr(void* p) { - assert (Invariant()); scope (exit) assert (Invariant()); - return getAttr(p); + if (p is null) + return 0; + return locked!(uint, () { + assert (Invariant()); scope (exit) assert (Invariant()); + Pool* pool = findPool(p); + if (pool is null) + return 0u; + auto bit_i = cast(size_t)(p - pool.baseAddr) / 16; + return getAttr(pool, bit_i); + })(); } -extern (C) uint gc_setAttr( void* p, uint a ) +uint gc_setAttr(void* p, uint attrs) { - assert (Invariant()); scope (exit) assert (Invariant()); - return setAttr(p, a); + if (p is null) + return 0; + return locked!(uint, () { + assert (Invariant()); scope (exit) assert (Invariant()); + Pool* pool = findPool(p); + if (pool is null) + return 0u; + auto bit_i = cast(size_t)(p - pool.baseAddr) / 16; + uint old_attrs = getAttr(pool, bit_i); + setAttr(pool, bit_i, attrs); + return old_attrs; + })(); } -extern (C) uint gc_clrAttr( void* p, uint a ) +uint gc_clrAttr(void* p, uint attrs) { - assert (Invariant()); scope (exit) assert (Invariant()); - return clrAttr(p, a); + if (p is null) + return 0; + return locked!(uint, () { + assert (Invariant()); scope (exit) assert (Invariant()); + Pool* pool = findPool(p); + if (pool is null) + return 0u; + auto bit_i = cast(size_t)(p - pool.baseAddr) / 16; + uint old_attrs = getAttr(pool, bit_i); + clrAttr(pool, bit_i, attrs); + return old_attrs; + })(); } -extern (C) void* gc_malloc(size_t sz, uint attrs = 0, +void* gc_malloc(size_t size, uint attrs = 0, PointerMap ptrmap = PointerMap.init) { - assert (Invariant()); scope (exit) assert (Invariant()); - return malloc(sz, attrs, ptrmap); + if (size == 0) + return null; + return locked!(void*, () { + assert (Invariant()); scope (exit) assert (Invariant()); + return malloc(size, attrs, ptrmap.bits.ptr); + })(); } -extern (C) void* gc_calloc(size_t sz, uint attrs = 0, +void* gc_calloc(size_t size, uint attrs = 0, PointerMap ptrmap = PointerMap.init) { - assert (Invariant()); scope (exit) assert (Invariant()); - return calloc(sz, attrs, ptrmap); + if (size == 0) + return null; + return locked!(void*, () { + assert (Invariant()); scope (exit) assert (Invariant()); + return calloc(size, attrs, ptrmap.bits.ptr); + })(); } -extern (C) void* gc_realloc(void* p, size_t sz, uint attrs = 0, +void* gc_realloc(void* p, size_t size, uint attrs = 0, PointerMap ptrmap = PointerMap.init) { - assert (Invariant()); scope (exit) assert (Invariant()); - return realloc(p, sz, attrs, ptrmap); + return locked!(void*, () { + assert (Invariant()); scope (exit) assert (Invariant()); + return realloc(p, size, attrs, ptrmap.bits.ptr); + })(); } -extern (C) size_t gc_extend( void* p, size_t mx, size_t sz ) +size_t gc_extend(void* p, size_t min_size, size_t max_size) { - assert (Invariant()); scope (exit) assert (Invariant()); - return extend(p, mx, sz); + return locked!(size_t, () { + assert (Invariant()); scope (exit) assert (Invariant()); + return extend(p, min_size, max_size); + })(); } -extern (C) size_t gc_reserve( size_t sz ) +size_t gc_reserve(size_t size) { - assert (Invariant()); scope (exit) assert (Invariant()); - return reserve(sz); + if (size == 0) + return 0; + return locked!(size_t, () { + assert (Invariant()); scope (exit) assert (Invariant()); + return reserve(size); + })(); } -extern (C) void gc_free( void* p ) +void gc_free(void* p) { - assert (Invariant()); scope (exit) assert (Invariant()); - free(p); + if (p is null) + return; + return locked!(void, () { + assert (Invariant()); scope (exit) assert (Invariant()); + free(p); + })(); } -extern (C) void* gc_addrOf( void* p ) +void* gc_addrOf(void* p) { - assert (Invariant()); scope (exit) assert (Invariant()); - return addrOf(p); + if (p is null) + return null; + return locked!(void*, () { + assert (Invariant()); scope (exit) assert (Invariant()); + Pool* pool = findPool(p); + if (pool is null) + return null; + return pool.findBase(p); + })(); } -extern (C) size_t gc_sizeOf( void* p ) +size_t gc_sizeOf(void* p) { - assert (Invariant()); scope (exit) assert (Invariant()); - return sizeOf(p); + if (p is null) + return 0; + return locked!(size_t, () { + assert (Invariant()); scope (exit) assert (Invariant()); + return sizeOf(p); + })(); } -extern (C) BlkInfo gc_query( void* p ) +BlkInfo gc_query(void* p) { - assert (Invariant()); scope (exit) assert (Invariant()); - return query(p); + if (p is null) + return BlkInfo.init; + return locked!(BlkInfo, () { + assert (Invariant()); scope (exit) assert (Invariant()); + return getInfo(p); + })(); } // NOTE: This routine is experimental. The stats or function name may change // before it is made officially available. -extern (C) GCStats gc_stats() +GCStats gc_stats() { - assert (Invariant()); scope (exit) assert (Invariant()); - GCStats stats = void; - getStats(stats); - return stats; + return locked!(GCStats, () { + assert (Invariant()); scope (exit) assert (Invariant()); + return getStats(); + })(); } -extern (C) void gc_addRoot( void* p ) +void gc_addRoot(void* p) { - assert (Invariant()); scope (exit) assert (Invariant()); - addRoot(p); + if (p is null) + return; + return locked!(void, () { + assert (Invariant()); scope (exit) assert (Invariant()); + if (gc.roots.append(p) is null) + onOutOfMemoryError(); + })(); } -extern (C) void gc_addRange( void* p, size_t sz ) +void gc_addRange(void* p, size_t size) { - assert (Invariant()); scope (exit) assert (Invariant()); - addRange(p, sz); + if (p is null || size == 0) + return; + return locked!(void, () { + assert (Invariant()); scope (exit) assert (Invariant()); + if (gc.ranges.append(Range(p, p + size)) is null) + onOutOfMemoryError(); + })(); } -extern (C) void gc_removeRoot( void *p ) +void gc_removeRoot(void* p) { - assert (Invariant()); scope (exit) assert (Invariant()); - removeRoot(p); + if (p is null) + return; + return locked!(void, () { + assert (Invariant()); scope (exit) assert (Invariant()); + bool r = gc.roots.remove(p); + assert (r); + })(); } -extern (C) void gc_removeRange( void *p ) +void gc_removeRange(void* p) { - assert (Invariant()); scope (exit) assert (Invariant()); - removeRange(p); + if (p is null) + return; + return locked!(void, () { + assert (Invariant()); scope (exit) assert (Invariant()); + bool r = gc.ranges.remove(Range(p, null)); + assert (r); + })(); } -extern (C) void* gc_weakpointerCreate( Object r ) +void* gc_weakpointerCreate(Object r) { - assert (Invariant()); scope (exit) assert (Invariant()); + // weakpointers do their own locking return weakpointerCreate(r); } -extern (C) void gc_weakpointerDestroy( void* wp ) +void gc_weakpointerDestroy(void* wp) { - assert (Invariant()); scope (exit) assert (Invariant()); + // weakpointers do their own locking weakpointerDestroy(wp); } -extern (C) Object gc_weakpointerGet( void* wp ) +Object gc_weakpointerGet(void* wp) { - assert (Invariant()); scope (exit) assert (Invariant()); + // weakpointers do their own locking return weakpointerGet(wp); }