1/**
2 * Contains the external GC interface.
3 *
4 * Copyright: D Language Foundation 2005 - 2021.
5 * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6 * Authors:   Walter Bright, Sean Kelly
7 */
8module core.internal.gc.proxy;
9
10import core.internal.gc.impl.proto.gc;
11import core.gc.config;
12import core.gc.gcinterface;
13import core.gc.registry : createGCInstance;
14
15static import core.memory;
16
17private
18{
19    static import core.memory;
20    alias BlkInfo = core.memory.GC.BlkInfo;
21
22    import core.internal.spinlock;
23    static SpinLock instanceLock;
24
25    __gshared bool isInstanceInit = false;
26    __gshared GC _instance = new ProtoGC();
27    __gshared GC proxiedGC; // used to iterate roots of Windows DLLs
28
29    pragma (inline, true) @trusted @nogc nothrow
30    GC instance() { return _instance; }
31}
32
33extern (C)
34{
35    import core.attribute : weak;
36
37    // do not import GC modules, they might add a dependency to this whole module
38    void _d_register_conservative_gc();
39    void _d_register_manual_gc();
40
41    // if you don't want to include the default GCs, replace during link by another implementation
42    void* register_default_gcs() @weak
43    {
44        pragma(inline, false);
45        // do not call, they register implicitly through pragma(crt_constructor)
46        // avoid being optimized away
47        auto reg1 = &_d_register_conservative_gc;
48        auto reg2 = &_d_register_manual_gc;
49        return reg1 < reg2 ? reg1 : reg2;
50    }
51
52    void gc_init()
53    {
54        instanceLock.lock();
55        if (!isInstanceInit)
56        {
57            register_default_gcs();
58            config.initialize();
59            auto protoInstance = instance;
60            auto newInstance = createGCInstance(config.gc);
61            if (newInstance is null)
62            {
63                import core.stdc.stdio : fprintf, stderr;
64                import core.stdc.stdlib : exit;
65
66                fprintf(stderr, "No GC was initialized, please recheck the name of the selected GC ('%.*s').\n", cast(int)config.gc.length, config.gc.ptr);
67                instanceLock.unlock();
68                exit(1);
69
70                // Shouldn't get here.
71                assert(0);
72            }
73            _instance = newInstance;
74            // Transfer all ranges and roots to the real GC.
75            (cast(ProtoGC) protoInstance).transferRangesAndRoots();
76            isInstanceInit = true;
77        }
78        instanceLock.unlock();
79    }
80
81    void gc_init_nothrow() nothrow
82    {
83        scope(failure)
84        {
85            import core.internal.abort;
86            abort("Cannot initialize the garbage collector.\n");
87            assert(0);
88        }
89        gc_init();
90    }
91
92    void gc_term()
93    {
94        if (isInstanceInit)
95        {
96            switch (config.cleanup)
97            {
98                default:
99                    import core.stdc.stdio : fprintf, stderr;
100                    fprintf(stderr, "Unknown GC cleanup method, please recheck ('%.*s').\n",
101                            cast(int)config.cleanup.length, config.cleanup.ptr);
102                    break;
103                case "none":
104                    break;
105                case "collect":
106                    // NOTE: There may be daemons threads still running when this routine is
107                    //       called.  If so, cleaning memory out from under then is a good
108                    //       way to make them crash horribly.  This probably doesn't matter
109                    //       much since the app is supposed to be shutting down anyway, but
110                    //       I'm disabling cleanup for now until I can think about it some
111                    //       more.
112                    //
113                    // NOTE: Due to popular demand, this has been re-enabled.  It still has
114                    //       the problems mentioned above though, so I guess we'll see.
115
116                    instance.collectNoStack();  // not really a 'collect all' -- still scans
117                                                // static data area, roots, and ranges.
118                    break;
119                case "finalize":
120                    instance.runFinalizers((cast(ubyte*)null)[0 .. size_t.max]);
121                    break;
122            }
123            destroy(instance);
124        }
125    }
126
127    void gc_enable()
128    {
129        instance.enable();
130    }
131
132    void gc_disable()
133    {
134        instance.disable();
135    }
136
137    void gc_collect() nothrow
138    {
139        instance.collect();
140    }
141
142    void gc_minimize() nothrow
143    {
144        instance.minimize();
145    }
146
147    uint gc_getAttr( void* p ) nothrow
148    {
149        return instance.getAttr(p);
150    }
151
152    uint gc_setAttr( void* p, uint a ) nothrow
153    {
154        return instance.setAttr(p, a);
155    }
156
157    uint gc_clrAttr( void* p, uint a ) nothrow
158    {
159        return instance.clrAttr(p, a);
160    }
161
162    void* gc_malloc( size_t sz, uint ba = 0, const scope TypeInfo ti = null ) nothrow
163    {
164        return instance.malloc(sz, ba, ti);
165    }
166
167    BlkInfo gc_qalloc( size_t sz, uint ba = 0, const scope TypeInfo ti = null ) nothrow
168    {
169        return instance.qalloc( sz, ba, ti );
170    }
171
172    void* gc_calloc( size_t sz, uint ba = 0, const scope TypeInfo ti = null ) nothrow
173    {
174        return instance.calloc( sz, ba, ti );
175    }
176
177    void* gc_realloc( void* p, size_t sz, uint ba = 0, const scope TypeInfo ti = null ) nothrow
178    {
179        return instance.realloc( p, sz, ba, ti );
180    }
181
182    size_t gc_extend( void* p, size_t mx, size_t sz, const scope TypeInfo ti = null ) nothrow
183    {
184        return instance.extend( p, mx, sz,ti );
185    }
186
187    size_t gc_reserve( size_t sz ) nothrow
188    {
189        return instance.reserve( sz );
190    }
191
192    void gc_free( void* p ) nothrow @nogc
193    {
194        return instance.free( p );
195    }
196
197    void* gc_addrOf( void* p ) nothrow @nogc
198    {
199        return instance.addrOf( p );
200    }
201
202    size_t gc_sizeOf( void* p ) nothrow @nogc
203    {
204        return instance.sizeOf( p );
205    }
206
207    BlkInfo gc_query( void* p ) nothrow
208    {
209        return instance.query( p );
210    }
211
212    core.memory.GC.Stats gc_stats() @safe nothrow @nogc
213    {
214        return instance.stats();
215    }
216
217    core.memory.GC.ProfileStats gc_profileStats() @safe nothrow @nogc
218    {
219        return instance.profileStats();
220    }
221
222    void gc_addRoot( void* p ) nothrow @nogc
223    {
224        return instance.addRoot( p );
225    }
226
227    void gc_addRange( void* p, size_t sz, const TypeInfo ti = null ) nothrow @nogc
228    {
229        return instance.addRange( p, sz, ti );
230    }
231
232    void gc_removeRoot( void* p ) nothrow
233    {
234        return instance.removeRoot( p );
235    }
236
237    void gc_removeRange( void* p ) nothrow
238    {
239        return instance.removeRange( p );
240    }
241
242    void gc_runFinalizers(const scope void[] segment ) nothrow
243    {
244        return instance.runFinalizers( segment );
245    }
246
247    bool gc_inFinalizer() nothrow @nogc @safe
248    {
249        return instance.inFinalizer();
250    }
251
252    ulong gc_allocatedInCurrentThread() nothrow
253    {
254        return instance.allocatedInCurrentThread();
255    }
256
257    GC gc_getProxy() nothrow
258    {
259        return instance;
260    }
261
262    export
263    {
264        void gc_setProxy( GC proxy )
265        {
266            foreach (root; instance.rootIter)
267            {
268                proxy.addRoot(root);
269            }
270
271            foreach (range; instance.rangeIter)
272            {
273                proxy.addRange(range.pbot, range.ptop - range.pbot, range.ti);
274            }
275
276            proxiedGC = instance; // remember initial GC to later remove roots
277            _instance = proxy;
278        }
279
280        void gc_clrProxy()
281        {
282            foreach (root; proxiedGC.rootIter)
283            {
284                instance.removeRoot(root);
285            }
286
287            foreach (range; proxiedGC.rangeIter)
288            {
289                instance.removeRange(range);
290            }
291
292            _instance = proxiedGC;
293            proxiedGC = null;
294        }
295    }
296}
297