Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions changelog/gc_registry.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
User supplied garbage collectors can now be linked with the runtime

A GC registry has been implemented that allows to add
garbage collector implementations by just linking them into
the binary. See the
$(LINK2 $(ROOT_DIR)spec/garbage.html#gc_registry, documentation)
for details.
3 changes: 2 additions & 1 deletion mak/SRCS
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,11 @@ SRCS=\
src\gc\bits.d \
src\gc\config.d \
src\gc\gcinterface.d \
src\gc\impl\conservative\gc.d \
src\gc\os.d \
src\gc\pooltable.d \
src\gc\proxy.d \
src\gc\impl\conservative\gc.d \
src\gc\registry.d \
src\gc\impl\manual\gc.d \
src\gc\impl\proto\gc.d \
\
Expand Down
16 changes: 12 additions & 4 deletions src/gc/config.d
Original file line number Diff line number Diff line change
Expand Up @@ -34,19 +34,27 @@ struct Config

void help() @nogc nothrow
{
string s = "GC options are specified as whitespace separated assignments:
import gc.registry : registeredGCFactories;

printf("GC options are specified as white space separated assignments:
disable:0|1 - start disabled (%d)
profile:0|1|2 - enable profiling with summary when terminating program (%d)
gc:conservative|precise|manual - select gc implementation (default = conservative)
gc:".ptr, disable, profile);
foreach (i, entry; registeredGCFactories)
{
if (i) printf("|");
printf("%.*s", cast(int) entry.name.length, entry.name.ptr);
}
printf(" - select gc implementation (default = conservative)

initReserve:N - initial memory to reserve in MB (%lld)
minPoolSize:N - initial and minimum pool size in MB (%lld)
maxPoolSize:N - maximum pool size in MB (%lld)
incPoolSize:N - pool size increment MB (%lld)
heapSizeFactor:N - targeted heap size to used memory ratio (%g)
cleanup:none|collect|finalize - how to treat live objects when terminating (collect)
";
printf(s.ptr, disable, profile, cast(long)initReserve, cast(long)minPoolSize,
".ptr,
cast(long)initReserve, cast(long)minPoolSize,
cast(long)maxPoolSize, cast(long)incPoolSize, heapSizeFactor);
}

Expand Down
6 changes: 0 additions & 6 deletions src/gc/gcinterface.d
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,6 @@ struct Range

interface GC
{

/*
*
*/
void Dtor();

/**
*
*/
Expand Down
77 changes: 40 additions & 37 deletions src/gc/impl/conservative/gc.d
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,42 @@ alias GC gc_t;

/* ============================ GC =============================== */

// register GC in C constructor (_STI_)
extern(C) pragma(crt_constructor) void _d_register_conservative_gc()
{
import gc.registry;
registerGCFactory("conservative", &initialize);
}

extern(C) pragma(crt_constructor) void _d_register_precise_gc()
{
import gc.registry;
registerGCFactory("precise", &initialize_precise);
}

private GC initialize()
{
import core.stdc.string: memcpy;

auto p = cstdlib.malloc(__traits(classInstanceSize, ConservativeGC));

if (!p)
onOutOfMemoryErrorNoGC();

auto init = typeid(ConservativeGC).initializer();
assert(init.length == __traits(classInstanceSize, ConservativeGC));
auto instance = cast(ConservativeGC) memcpy(p, init.ptr, init.length);
instance.__ctor();

return instance;
}

private GC initialize_precise()
{
ConservativeGC.isPrecise = true;
return initialize();
}

class ConservativeGC : GC
{
// For passing to debug code (not thread safe)
Expand All @@ -124,42 +160,6 @@ class ConservativeGC : GC
gcLock.lock();
}


static void initialize(ref GC gc)
{
import core.stdc.string: memcpy;

if ((config.gc != "precise") && (config.gc != "conservative"))
return;

if (config.gc == "precise")
isPrecise = true;

auto p = cstdlib.malloc(__traits(classInstanceSize,ConservativeGC));

if (!p)
onOutOfMemoryErrorNoGC();

auto init = typeid(ConservativeGC).initializer();
assert(init.length == __traits(classInstanceSize, ConservativeGC));
auto instance = cast(ConservativeGC) memcpy(p, init.ptr, init.length);
instance.__ctor();

gc = instance;
}


static void finalize(ref GC gc)
{
if ((config.gc != "precise") && (config.gc != "conservative"))
return;

auto instance = cast(ConservativeGC) gc;
instance.Dtor();
cstdlib.free(cast(void*)instance);
}


this()
{
//config is assumed to have already been initialized
Expand All @@ -176,7 +176,7 @@ class ConservativeGC : GC
}


void Dtor()
~this()
{
version (linux)
{
Expand All @@ -190,6 +190,9 @@ class ConservativeGC : GC
cstdlib.free(gcx);
gcx = null;
}
// TODO: cannot free as memory is overwritten and
// the monitor is still read in rt_finalize (called by destroy)
// cstdlib.free(cast(void*) this);
}


Expand Down
53 changes: 25 additions & 28 deletions src/gc/impl/manual/gc.d
Original file line number Diff line number Diff line change
Expand Up @@ -35,46 +35,43 @@ static import core.memory;

extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc; /* dmd @@@BUG11461@@@ */

class ManualGC : GC
// register GC in C constructor (_STI_)
extern(C) pragma(crt_constructor) void _d_register_manual_gc()
{
__gshared Array!Root roots;
__gshared Array!Range ranges;

static void initialize(ref GC gc)
{
import core.stdc.string;
import gc.registry;
registerGCFactory("manual", &initialize);
}

if (config.gc != "manual")
return;
private GC initialize()
{
import core.stdc.string: memcpy;

auto p = cstdlib.malloc(__traits(classInstanceSize, ManualGC));
if (!p)
onOutOfMemoryError();
auto p = cstdlib.malloc(__traits(classInstanceSize, ManualGC));
if (!p)
onOutOfMemoryError();

auto init = typeid(ManualGC).initializer();
assert(init.length == __traits(classInstanceSize, ManualGC));
auto instance = cast(ManualGC) memcpy(p, init.ptr, init.length);
instance.__ctor();
auto init = typeid(ManualGC).initializer();
assert(init.length == __traits(classInstanceSize, ManualGC));
auto instance = cast(ManualGC) memcpy(p, init.ptr, init.length);
instance.__ctor();

gc = instance;
}

static void finalize(ref GC gc)
{
if (config.gc != "manual")
return;
return instance;
}

auto instance = cast(ManualGC) gc;
instance.Dtor();
cstdlib.free(cast(void*) instance);
}
class ManualGC : GC
{
Array!Root roots;
Array!Range ranges;

this()
{
}

void Dtor()
~this()
{
// TODO: cannot free as memory is overwritten and
// the monitor is still read in rt_finalize (called by destroy)
// cstdlib.free(cast(void*) this);
}

void enable()
Expand Down
33 changes: 22 additions & 11 deletions src/gc/proxy.d
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
*/
module gc.proxy;

import gc.impl.conservative.gc;
import gc.impl.manual.gc;
import gc.impl.proto.gc;
import gc.config;
import gc.gcinterface;
import gc.registry : createGCInstance;

static import core.memory;

Expand All @@ -36,17 +35,31 @@ private

extern (C)
{
// do not import GC modules, they might add a dependency to this whole module
void _d_register_conservative_gc();
void _d_register_manual_gc();

// if you don't want to include the default GCs, replace during link by another implementation
void* register_default_gcs()
{
pragma(inline, false);
// do not call, they register implicitly through pragma(crt_constructor)
// avoid being optimized away
auto reg1 = &_d_register_conservative_gc;
auto reg2 = &_d_register_manual_gc;
return reg1 < reg2 ? reg1 : reg2;
}

void gc_init()
{
instanceLock.lock();
if (!isInstanceInit)
{
auto protoInstance = instance;
register_default_gcs();
config.initialize();
ManualGC.initialize(instance);
ConservativeGC.initialize(instance);

if (instance is protoInstance)
auto protoInstance = instance;
auto newInstance = createGCInstance(config.gc);
if (newInstance is null)
{
import core.stdc.stdio : fprintf, stderr;
import core.stdc.stdlib : exit;
Expand All @@ -58,7 +71,7 @@ extern (C)
// Shouldn't get here.
assert(0);
}

instance = newInstance;
// Transfer all ranges and roots to the real GC.
(cast(ProtoGC) protoInstance).term();
isInstanceInit = true;
Expand Down Expand Up @@ -108,9 +121,7 @@ extern (C)
instance.runFinalizers((cast(ubyte*)null)[0 .. size_t.max]);
break;
}

ManualGC.finalize(instance);
ConservativeGC.finalize(instance);
destroy(instance);
}
}

Expand Down
Loading