xref: /netbsd-src/external/gpl3/gcc/dist/libphobos/libdruntime/core/internal/gc/proxy.d (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
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  */
8 module core.internal.gc.proxy;
9 
10 import core.internal.gc.impl.proto.gc;
11 import core.gc.config;
12 import core.gc.gcinterface;
13 import core.gc.registry : createGCInstance;
14 
15 static import core.memory;
16 
17 private
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 
pragma(inline,true)29     pragma (inline, true) @trusted @nogc nothrow
30     GC instance() { return _instance; }
31 }
32 
33 extern (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
register_default_gcs()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 
gc_init()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 
gc_init_nothrow()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 
gc_term()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 
gc_enable()127     void gc_enable()
128     {
129         instance.enable();
130     }
131 
gc_disable()132     void gc_disable()
133     {
134         instance.disable();
135     }
136 
gc_collect()137     void gc_collect() nothrow
138     {
139         instance.collect();
140     }
141 
gc_minimize()142     void gc_minimize() nothrow
143     {
144         instance.minimize();
145     }
146 
gc_getAttr(void * p)147     uint gc_getAttr( void* p ) nothrow
148     {
149         return instance.getAttr(p);
150     }
151 
gc_setAttr(void * p,uint a)152     uint gc_setAttr( void* p, uint a ) nothrow
153     {
154         return instance.setAttr(p, a);
155     }
156 
gc_clrAttr(void * p,uint a)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 
gc_reserve(size_t sz)187     size_t gc_reserve( size_t sz ) nothrow
188     {
189         return instance.reserve( sz );
190     }
191 
gc_free(void * p)192     void gc_free( void* p ) nothrow @nogc
193     {
194         return instance.free( p );
195     }
196 
gc_addrOf(void * p)197     void* gc_addrOf( void* p ) nothrow @nogc
198     {
199         return instance.addrOf( p );
200     }
201 
gc_sizeOf(void * p)202     size_t gc_sizeOf( void* p ) nothrow @nogc
203     {
204         return instance.sizeOf( p );
205     }
206 
gc_query(void * p)207     BlkInfo gc_query( void* p ) nothrow
208     {
209         return instance.query( p );
210     }
211 
gc_stats()212     core.memory.GC.Stats gc_stats() @safe nothrow @nogc
213     {
214         return instance.stats();
215     }
216 
gc_profileStats()217     core.memory.GC.ProfileStats gc_profileStats() @safe nothrow @nogc
218     {
219         return instance.profileStats();
220     }
221 
gc_addRoot(void * p)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 
gc_removeRoot(void * p)232     void gc_removeRoot( void* p ) nothrow
233     {
234         return instance.removeRoot( p );
235     }
236 
gc_removeRange(void * p)237     void gc_removeRange( void* p ) nothrow
238     {
239         return instance.removeRange( p );
240     }
241 
gc_runFinalizers(const scope void[]segment)242     void gc_runFinalizers(const scope void[] segment ) nothrow
243     {
244         return instance.runFinalizers( segment );
245     }
246 
gc_inFinalizer()247     bool gc_inFinalizer() nothrow @nogc @safe
248     {
249         return instance.inFinalizer();
250     }
251 
gc_allocatedInCurrentThread()252     ulong gc_allocatedInCurrentThread() nothrow
253     {
254         return instance.allocatedInCurrentThread();
255     }
256 
gc_getProxy()257     GC gc_getProxy() nothrow
258     {
259         return instance;
260     }
261 
262     export
263     {
gc_setProxy(GC proxy)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 
gc_clrProxy()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