Skip to content
This repository has been archived by the owner on Oct 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #1924 from MartinNowak/open_gc_registry
Browse files Browse the repository at this point in the history
implement open GC registry
merged-on-behalf-of: unknown
  • Loading branch information
dlang-bot authored Feb 15, 2019
2 parents d773dd4 + ee0c82c commit 1dcbd74
Show file tree
Hide file tree
Showing 12 changed files with 411 additions and 89 deletions.
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

0 comments on commit 1dcbd74

Please sign in to comment.