Designing with the GC out of mind

anonymous anonymous at example.com
Tue Aug 6 10:17:47 PDT 2013


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();




More information about the Digitalmars-d mailing list