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

Commit 1dcbd74

Browse files
authored
Merge pull request #1924 from MartinNowak/open_gc_registry
implement open GC registry merged-on-behalf-of: unknown
2 parents d773dd4 + ee0c82c commit 1dcbd74

File tree

12 files changed

+411
-89
lines changed

12 files changed

+411
-89
lines changed

changelog/gc_registry.dd

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
User supplied garbage collectors can now be linked with the runtime
2+
3+
A GC registry has been implemented that allows to add
4+
garbage collector implementations by just linking them into
5+
the binary. See the
6+
$(LINK2 $(ROOT_DIR)spec/garbage.html#gc_registry, documentation)
7+
for details.

mak/SRCS

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,10 +390,11 @@ SRCS=\
390390
src\gc\bits.d \
391391
src\gc\config.d \
392392
src\gc\gcinterface.d \
393+
src\gc\impl\conservative\gc.d \
393394
src\gc\os.d \
394395
src\gc\pooltable.d \
395396
src\gc\proxy.d \
396-
src\gc\impl\conservative\gc.d \
397+
src\gc\registry.d \
397398
src\gc\impl\manual\gc.d \
398399
src\gc\impl\proto\gc.d \
399400
\

src/gc/config.d

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,27 @@ struct Config
3434

3535
void help() @nogc nothrow
3636
{
37-
string s = "GC options are specified as whitespace separated assignments:
37+
import gc.registry : registeredGCFactories;
38+
39+
printf("GC options are specified as white space separated assignments:
3840
disable:0|1 - start disabled (%d)
3941
profile:0|1|2 - enable profiling with summary when terminating program (%d)
40-
gc:conservative|precise|manual - select gc implementation (default = conservative)
42+
gc:".ptr, disable, profile);
43+
foreach (i, entry; registeredGCFactories)
44+
{
45+
if (i) printf("|");
46+
printf("%.*s", cast(int) entry.name.length, entry.name.ptr);
47+
}
48+
printf(" - select gc implementation (default = conservative)
4149
4250
initReserve:N - initial memory to reserve in MB (%lld)
4351
minPoolSize:N - initial and minimum pool size in MB (%lld)
4452
maxPoolSize:N - maximum pool size in MB (%lld)
4553
incPoolSize:N - pool size increment MB (%lld)
4654
heapSizeFactor:N - targeted heap size to used memory ratio (%g)
4755
cleanup:none|collect|finalize - how to treat live objects when terminating (collect)
48-
";
49-
printf(s.ptr, disable, profile, cast(long)initReserve, cast(long)minPoolSize,
56+
".ptr,
57+
cast(long)initReserve, cast(long)minPoolSize,
5058
cast(long)maxPoolSize, cast(long)incPoolSize, heapSizeFactor);
5159
}
5260

src/gc/gcinterface.d

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,6 @@ struct Range
3838

3939
interface GC
4040
{
41-
42-
/*
43-
*
44-
*/
45-
void Dtor();
46-
4741
/**
4842
*
4943
*/

src/gc/impl/conservative/gc.d

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,42 @@ alias GC gc_t;
103103

104104
/* ============================ GC =============================== */
105105

106+
// register GC in C constructor (_STI_)
107+
extern(C) pragma(crt_constructor) void _d_register_conservative_gc()
108+
{
109+
import gc.registry;
110+
registerGCFactory("conservative", &initialize);
111+
}
112+
113+
extern(C) pragma(crt_constructor) void _d_register_precise_gc()
114+
{
115+
import gc.registry;
116+
registerGCFactory("precise", &initialize_precise);
117+
}
118+
119+
private GC initialize()
120+
{
121+
import core.stdc.string: memcpy;
122+
123+
auto p = cstdlib.malloc(__traits(classInstanceSize, ConservativeGC));
124+
125+
if (!p)
126+
onOutOfMemoryErrorNoGC();
127+
128+
auto init = typeid(ConservativeGC).initializer();
129+
assert(init.length == __traits(classInstanceSize, ConservativeGC));
130+
auto instance = cast(ConservativeGC) memcpy(p, init.ptr, init.length);
131+
instance.__ctor();
132+
133+
return instance;
134+
}
135+
136+
private GC initialize_precise()
137+
{
138+
ConservativeGC.isPrecise = true;
139+
return initialize();
140+
}
141+
106142
class ConservativeGC : GC
107143
{
108144
// For passing to debug code (not thread safe)
@@ -124,42 +160,6 @@ class ConservativeGC : GC
124160
gcLock.lock();
125161
}
126162

127-
128-
static void initialize(ref GC gc)
129-
{
130-
import core.stdc.string: memcpy;
131-
132-
if ((config.gc != "precise") && (config.gc != "conservative"))
133-
return;
134-
135-
if (config.gc == "precise")
136-
isPrecise = true;
137-
138-
auto p = cstdlib.malloc(__traits(classInstanceSize,ConservativeGC));
139-
140-
if (!p)
141-
onOutOfMemoryErrorNoGC();
142-
143-
auto init = typeid(ConservativeGC).initializer();
144-
assert(init.length == __traits(classInstanceSize, ConservativeGC));
145-
auto instance = cast(ConservativeGC) memcpy(p, init.ptr, init.length);
146-
instance.__ctor();
147-
148-
gc = instance;
149-
}
150-
151-
152-
static void finalize(ref GC gc)
153-
{
154-
if ((config.gc != "precise") && (config.gc != "conservative"))
155-
return;
156-
157-
auto instance = cast(ConservativeGC) gc;
158-
instance.Dtor();
159-
cstdlib.free(cast(void*)instance);
160-
}
161-
162-
163163
this()
164164
{
165165
//config is assumed to have already been initialized
@@ -176,7 +176,7 @@ class ConservativeGC : GC
176176
}
177177

178178

179-
void Dtor()
179+
~this()
180180
{
181181
version (linux)
182182
{
@@ -190,6 +190,9 @@ class ConservativeGC : GC
190190
cstdlib.free(gcx);
191191
gcx = null;
192192
}
193+
// TODO: cannot free as memory is overwritten and
194+
// the monitor is still read in rt_finalize (called by destroy)
195+
// cstdlib.free(cast(void*) this);
193196
}
194197

195198

src/gc/impl/manual/gc.d

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -35,46 +35,43 @@ static import core.memory;
3535

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

38-
class ManualGC : GC
38+
// register GC in C constructor (_STI_)
39+
extern(C) pragma(crt_constructor) void _d_register_manual_gc()
3940
{
40-
__gshared Array!Root roots;
41-
__gshared Array!Range ranges;
42-
43-
static void initialize(ref GC gc)
44-
{
45-
import core.stdc.string;
41+
import gc.registry;
42+
registerGCFactory("manual", &initialize);
43+
}
4644

47-
if (config.gc != "manual")
48-
return;
45+
private GC initialize()
46+
{
47+
import core.stdc.string: memcpy;
4948

50-
auto p = cstdlib.malloc(__traits(classInstanceSize, ManualGC));
51-
if (!p)
52-
onOutOfMemoryError();
49+
auto p = cstdlib.malloc(__traits(classInstanceSize, ManualGC));
50+
if (!p)
51+
onOutOfMemoryError();
5352

54-
auto init = typeid(ManualGC).initializer();
55-
assert(init.length == __traits(classInstanceSize, ManualGC));
56-
auto instance = cast(ManualGC) memcpy(p, init.ptr, init.length);
57-
instance.__ctor();
53+
auto init = typeid(ManualGC).initializer();
54+
assert(init.length == __traits(classInstanceSize, ManualGC));
55+
auto instance = cast(ManualGC) memcpy(p, init.ptr, init.length);
56+
instance.__ctor();
5857

59-
gc = instance;
60-
}
61-
62-
static void finalize(ref GC gc)
63-
{
64-
if (config.gc != "manual")
65-
return;
58+
return instance;
59+
}
6660

67-
auto instance = cast(ManualGC) gc;
68-
instance.Dtor();
69-
cstdlib.free(cast(void*) instance);
70-
}
61+
class ManualGC : GC
62+
{
63+
Array!Root roots;
64+
Array!Range ranges;
7165

7266
this()
7367
{
7468
}
7569

76-
void Dtor()
70+
~this()
7771
{
72+
// TODO: cannot free as memory is overwritten and
73+
// the monitor is still read in rt_finalize (called by destroy)
74+
// cstdlib.free(cast(void*) this);
7875
}
7976

8077
void enable()

src/gc/proxy.d

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@
1313
*/
1414
module gc.proxy;
1515

16-
import gc.impl.conservative.gc;
17-
import gc.impl.manual.gc;
1816
import gc.impl.proto.gc;
1917
import gc.config;
2018
import gc.gcinterface;
19+
import gc.registry : createGCInstance;
2120

2221
static import core.memory;
2322

@@ -36,17 +35,31 @@ private
3635

3736
extern (C)
3837
{
38+
// do not import GC modules, they might add a dependency to this whole module
39+
void _d_register_conservative_gc();
40+
void _d_register_manual_gc();
41+
42+
// if you don't want to include the default GCs, replace during link by another implementation
43+
void* register_default_gcs()
44+
{
45+
pragma(inline, false);
46+
// do not call, they register implicitly through pragma(crt_constructor)
47+
// avoid being optimized away
48+
auto reg1 = &_d_register_conservative_gc;
49+
auto reg2 = &_d_register_manual_gc;
50+
return reg1 < reg2 ? reg1 : reg2;
51+
}
52+
3953
void gc_init()
4054
{
4155
instanceLock.lock();
4256
if (!isInstanceInit)
4357
{
44-
auto protoInstance = instance;
58+
register_default_gcs();
4559
config.initialize();
46-
ManualGC.initialize(instance);
47-
ConservativeGC.initialize(instance);
48-
49-
if (instance is protoInstance)
60+
auto protoInstance = instance;
61+
auto newInstance = createGCInstance(config.gc);
62+
if (newInstance is null)
5063
{
5164
import core.stdc.stdio : fprintf, stderr;
5265
import core.stdc.stdlib : exit;
@@ -58,7 +71,7 @@ extern (C)
5871
// Shouldn't get here.
5972
assert(0);
6073
}
61-
74+
instance = newInstance;
6275
// Transfer all ranges and roots to the real GC.
6376
(cast(ProtoGC) protoInstance).term();
6477
isInstanceInit = true;
@@ -108,9 +121,7 @@ extern (C)
108121
instance.runFinalizers((cast(ubyte*)null)[0 .. size_t.max]);
109122
break;
110123
}
111-
112-
ManualGC.finalize(instance);
113-
ConservativeGC.finalize(instance);
124+
destroy(instance);
114125
}
115126
}
116127

0 commit comments

Comments
 (0)