On Tuesday, 6 August 2013 at 14:27:32 UTC, Adam D. Ruppe wrote:
and there's a gc proxy in the code but idk how to use it.

I have this little piece of hack that uses the proxy to disable GC allocations at runtime. It's not tested well, so it probably has some issues, but maybe it's a start for someone. See the unittest for how to use.

CODE:

import std.exception: assertThrown;
import std.traits: ParameterTypeTuple, ReturnType;

static import core.memory;

/*NOTE: Deriving from Throwable instead of Exception, because with Exception
catch(GCUsedWhenForbidden) doesn't work (dmd 2.063). */
class GCUsedWhenForbidden : Throwable
{
this(string gcProcName, string file = __FILE__, size_t line = __LINE__)
        {
                super(gcProcName, file, line);
        }
}

struct GC
{
        static auto opDispatch(string n, A ...)(A args)
        {
                mixin("return core.memory.GC." ~ n ~ "(args);");
        }
        private static Proxy proxy;
        static this()
        {
                foreach(name; __traits(allMembers, Proxy))
                        makeDie!name();
        }
        private shared static uint forbidCount = 0;
        static void forbidUse()
        {
                if(forbidCount++ == 0) actuallyForbidUse;
        }
        private static void actuallyForbidUse()
        {
                makeNop!"gc_addRange"();
                gc_setProxy(&proxy);
                makeDie!"gc_addRange"();
        }
        static void allowUse()
        {
                if(--forbidCount == 0) actuallyAllowUse;
        }
        private static void actuallyAllowUse()
        {
                makeNop!"gc_removeRange"();
                gc_clrProxy();
                makeDie!"gc_removeRange"();
        }
        private static auto proxyMember(string name)()
        {
                mixin("return &proxy." ~ name ~ ";");
        }
        private static makeNop(string name)()
        {
                *proxyMember!name = &nop!(typeof(*proxyMember!name));
        }
        private static makeDie(string name)()
        {
                *proxyMember!name = &die!(typeof(*proxyMember!name), name);
        }
}
unittest
{
        int[] h = new int[1];
        
        GC.forbidUse; // 1
        assertThrown!GCUsedWhenForbidden(new int[1]);
        
        GC.forbidUse; // 2
        assertThrown!GCUsedWhenForbidden(new int[1]);
        
        GC.allowUse; // 1
        assertThrown!GCUsedWhenForbidden(new int[1]);
        
        GC.allowUse; // 0
        h = new int[1]; // now, GC can be used again
}

private extern(C) void nop(T)(ParameterTypeTuple!T) {}
private extern(C) ReturnType!T die(T, string name)(ParameterTypeTuple!T)
{
        GC.actuallyAllowUse;
        scope(exit) GC.actuallyForbidUse;
        throw new GCUsedWhenForbidden(name);
}

//NOTE: copied from druntime/src/gc/gc.d
private struct BlkInfo
{
        void*  base;
        size_t size;
        uint   attr;
}
//NOTE: copied from druntime/src/gc/proxy.d
private struct Proxy
{
        extern(C)
        {
                void function() gc_enable;
                void function() gc_disable;
                void function() gc_collect;
                void function() gc_minimize;

                uint function(void*) gc_getAttr;
                uint function(void*, uint) gc_setAttr;
                uint function(void*, uint) gc_clrAttr;

                void*   function(size_t, uint) gc_malloc;
                BlkInfo function(size_t, uint) gc_qalloc;
                void*   function(size_t, uint) gc_calloc;
                void*   function(void*, size_t, uint ba) gc_realloc;
                size_t  function(void*, size_t, size_t) gc_extend;
                size_t  function(size_t) gc_reserve;
                void    function(void*) gc_free;

                void*   function(void*) gc_addrOf;
                size_t  function(void*) gc_sizeOf;

                BlkInfo function(void*) gc_query;

                void function(void*) gc_addRoot;
                void function(void*, size_t) gc_addRange;

                void function(void*) gc_removeRoot;
                void function(void*) gc_removeRange;
        }
}
//NOTE: copied from druntime/src/gc/proxy.d
private extern(C) void gc_setProxy(Proxy*);
private extern(C) void gc_clrProxy();


Reply via email to