+
+/* ============================ C Public Interface ======================== */
+
+
+private int _termCleanupLevel=1;
+
+extern (C):
+
+/// sets the cleanup level done by gc
+/// 0: none
+/// 1: fullCollect
+/// 2: fullCollect ignoring stack roots (might crash daemonThreads)
+/// result !=0 if the value was invalid
+int gc_setTermCleanupLevel(int cLevel)
+{
+ if (cLevel<0 || cLevel>2) return cLevel;
+ _termCleanupLevel=cLevel;
+ return 0;
+}
+
+/// returns the cleanup level done by gc
+int gc_getTermCleanupLevel()
+{
+ return _termCleanupLevel;
+}
+
+void gc_init()
+{
+ scope (exit) assert (Invariant());
+ gc = cast(GC*) cstdlib.calloc(1, GC.sizeof);
+ *gc = GC.init;
+ initialize();
+ version (DigitalMars) version(OSX) {
+ _d_osx_image_init();
+ }
+ // NOTE: The GC must initialize the thread library
+ // before its first collection.
+ thread_init();
+}
+
+void gc_term()
+{
+ assert (Invariant());
+ if (_termCleanupLevel<1) {
+ // no cleanup
+ } else if (_termCleanupLevel==2){
+ // a more complete cleanup
+ // NOTE: There may be daemons threads still running when this routine is
+ // called. If so, cleaning memory out from under then is a good
+ // way to make them crash horribly.
+ // Often this probably doesn't matter much since the app is
+ // supposed to be shutting down anyway, but for example tests might
+ // crash (and be considerd failed even if the test was ok).
+ // thus this is not the default and should be enabled by
+ // I'm disabling cleanup for now until I can think about it some
+ // more.
+ //
+ // 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
+ return locked!(void, () {
+ fullcollectshell();
+ })();
+ }
+}
+
+void gc_enable()
+{
+ return locked!(void, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ assert (gc.disabled > 0);
+ gc.disabled--;
+ })();
+}
+
+void gc_disable()
+{
+ return locked!(void, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ gc.disabled++;
+ })();
+}
+
+void gc_collect()
+{
+ return locked!(void, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ fullcollectshell();
+ })();
+}
+
+
+void gc_minimize()
+{
+ return locked!(void, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ minimize();
+ })();
+}
+
+uint gc_getAttr(void* 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);
+ })();
+}
+
+uint gc_setAttr(void* p, uint attrs)
+{
+ 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;
+ })();
+}
+
+uint gc_clrAttr(void* p, uint attrs)
+{
+ 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;
+ })();
+}
+
+void* gc_malloc(size_t size, uint attrs = 0,
+ PointerMap ptrmap = PointerMap.init)
+{
+ if (size == 0)
+ return null;
+ return locked!(void*, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ return malloc(size, attrs, ptrmap.bits.ptr);
+ })();
+}
+
+void* gc_calloc(size_t size, uint attrs = 0,
+ PointerMap ptrmap = PointerMap.init)
+{
+ if (size == 0)
+ return null;
+ return locked!(void*, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ return calloc(size, attrs, ptrmap.bits.ptr);
+ })();
+}
+
+void* gc_realloc(void* p, size_t size, uint attrs = 0,
+ PointerMap ptrmap = PointerMap.init)
+{
+ return locked!(void*, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ return realloc(p, size, attrs, ptrmap.bits.ptr);
+ })();
+}
+
+size_t gc_extend(void* p, size_t min_size, size_t max_size)
+{
+ return locked!(size_t, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ return extend(p, min_size, max_size);
+ })();
+}
+
+size_t gc_reserve(size_t size)
+{
+ if (size == 0)
+ return 0;
+ return locked!(size_t, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ return reserve(size);
+ })();
+}
+
+void gc_free(void* p)
+{
+ if (p is null)
+ return;
+ return locked!(void, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ free(p);
+ })();
+}
+
+void* gc_addrOf(void* 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);
+ })();
+}
+
+size_t gc_sizeOf(void* p)
+{
+ if (p is null)
+ return 0;
+ return locked!(size_t, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ return sizeOf(p);
+ })();
+}
+
+BlkInfo gc_query(void* 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.
+GCStats gc_stats()
+{
+ return locked!(GCStats, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ return getStats();
+ })();
+}
+
+void gc_addRoot(void* p)
+{
+ if (p is null)
+ return;
+ return locked!(void, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ if (gc.roots.append(p) is null)
+ onOutOfMemoryError();
+ })();
+}
+
+void gc_addRange(void* p, size_t size)
+{
+ 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();
+ })();
+}
+
+void gc_removeRoot(void* p)
+{
+ if (p is null)
+ return;
+ return locked!(void, () {
+ assert (Invariant()); scope (exit) assert (Invariant());
+ bool r = gc.roots.remove(p);
+ assert (r);
+ })();
+}
+
+void gc_removeRange(void* 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);
+ })();
+}
+
+void* gc_weakpointerCreate(Object r)
+{
+ // weakpointers do their own locking
+ return weakpointerCreate(r);
+}
+
+void gc_weakpointerDestroy(void* wp)
+{
+ // weakpointers do their own locking
+ weakpointerDestroy(wp);
+}
+
+Object gc_weakpointerGet(void* wp)
+{
+ // weakpointers do their own locking
+ return weakpointerGet(wp);
+}
+
+