]> git.llucax.com Git - software/druntime.git/blob - src/gc/stub/gc.d
First attempt at support for dynamic library loading and unloading. Currently, only...
[software/druntime.git] / src / gc / stub / gc.d
1 /**
2  * This module contains a minimal garbage collector implementation according to
3  * published requirements.  This library is mostly intended to serve as an
4  * example, but it is usable in applications which do not rely on a garbage
5  * collector to clean up memory (ie. when dynamic array resizing is not used,
6  * and all memory allocated with 'new' is freed deterministically with
7  * 'delete').
8  *
9  * Please note that block attribute data must be tracked, or at a minimum, the
10  * FINALIZE bit must be tracked for any allocated memory block because calling
11  * rt_finalize on a non-object block can result in an access violation.  In the
12  * allocator below, this tracking is done via a leading uint bitmask.  A real
13  * allocator may do better to store this data separately, similar to the basic
14  * GC.
15  *
16  * Copyright: Public Domain
17  * License:   Public Domain
18  * Authors:   Sean Kelly
19  */
20
21 module gc.gc;
22
23 private import core.stdc.stdlib;
24
25 private
26 {
27    enum BlkAttr : uint
28     {
29         FINALIZE = 0b0000_0001,
30         NO_SCAN  = 0b0000_0010,
31         NO_MOVE  = 0b0000_0100,
32         ALL_BITS = 0b1111_1111
33     }
34
35     struct BlkInfo
36     {
37         void*  base;
38         size_t size;
39         uint   attr;
40     }
41
42     extern (C) void thread_init();
43     extern (C) void onOutOfMemoryError();
44 }
45
46 extern (C) void gc_init()
47 {
48     // NOTE: The GC must initialize the thread library before its first
49     //       collection, and always before returning from gc_init().
50     thread_init();
51 }
52
53 extern (C) void gc_term()
54 {
55
56 }
57
58 extern (C) void gc_enable()
59 {
60     if( proxy is null )
61         return;
62     return proxy.gc_enable();
63 }
64
65 extern (C) void gc_disable()
66 {
67     if( proxy is null )
68         return;
69     return proxy.gc_disable();
70 }
71
72 extern (C) void gc_collect()
73 {
74     if( proxy is null )
75         return;
76     return proxy.gc_collect();
77 }
78
79 extern (C) void gc_minimize()
80 {
81     if( proxy is null )
82         return;
83     return proxy.gc_minimize();
84 }
85
86 extern (C) uint gc_getAttr( void* p )
87 {
88     if( proxy is null )
89         return 0;
90     return proxy.gc_getAttr( p );
91 }
92
93 extern (C) uint gc_setAttr( void* p, uint a )
94 {
95     if( proxy is null )
96         return 0;
97     return proxy.gc_setAttr( p, a );
98 }
99
100 extern (C) uint gc_clrAttr( void* p, uint a )
101 {
102     if( proxy is null )
103         return 0;
104     return proxy.gc_clrAttr( p, a );
105 }
106
107 extern (C) void* gc_malloc( size_t sz, uint ba = 0 )
108 {
109     if( proxy is null )
110     {
111         void* p = malloc( sz );
112
113         if( sz && p is null )
114             onOutOfMemoryError();
115         return p;
116     }
117     return proxy.gc_malloc( sz, ba );
118 }
119
120 extern (C) void* gc_calloc( size_t sz, uint ba = 0 )
121 {
122     if( proxy is null )
123     {
124         void* p = calloc( 1, sz );
125
126         if( sz && p is null )
127             onOutOfMemoryError();
128         return p;
129     }
130     return proxy.gc_calloc( sz, ba );
131 }
132
133 extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 )
134 {
135     if( proxy is null )
136     {
137         p = realloc( p, sz );
138
139         if( sz && p is null )
140             onOutOfMemoryError();
141         return p;
142     }
143     return proxy.gc_realloc( p, sz, ba );
144 }
145
146 extern (C) size_t gc_extend( void* p, size_t mx, size_t sz )
147 {
148     if( proxy is null )
149         return 0;
150     return proxy.gc_extend( p, mx, sz );
151 }
152
153 extern (C) size_t gc_reserve( size_t sz )
154 {
155     if( proxy is null )
156         return 0;
157     return proxy.gc_reserve( sz );
158 }
159
160 extern (C) void gc_free( void* p )
161 {
162     if( proxy is null )
163         return free( p );
164     return proxy.gc_free( p );
165 }
166
167 extern (C) void* gc_addrOf( void* p )
168 {
169     if( proxy is null )
170         return null;
171     return proxy.gc_addrOf( p );
172 }
173
174 extern (C) size_t gc_sizeOf( void* p )
175 {
176     if( proxy is null )
177         return 0;
178     return proxy.gc_sizeOf( p );
179 }
180
181 extern (C) BlkInfo gc_query( void* p )
182 {
183     if( proxy is null )
184         return BlkInfo.init;
185     return proxy.gc_query( p );
186 }
187
188 // TODO: Implement range storage.
189 // TODO: Implement root storage.
190
191 extern (C) void gc_addRoot( void* p )
192 {
193     if( proxy is null )
194         return;
195     return proxy.gc_addRoot( p );
196 }
197
198 extern (C) void gc_addRange( void* p, size_t sz )
199 {
200     if( proxy is null )
201         return;
202     return proxy.gc_addRange( p, sz );
203 }
204
205 extern (C) void gc_removeRoot( void *p )
206 {
207     if( proxy is null )
208         return;
209     return proxy.gc_removeRoot( p );
210 }
211
212 extern (C) void gc_removeRange( void *p )
213 {
214     if( proxy is null )
215         return;
216     return proxy.gc_removeRange( p );
217 }
218
219 struct Proxy
220 {
221     extern (C) void function() gc_enable;
222     extern (C) void function() gc_disable;
223     extern (C) void function() gc_collect;
224     extern (C) void function() gc_minimize;
225
226     extern (C) uint function(void*) gc_getAttr;
227     extern (C) uint function(void*, uint) gc_setAttr;
228     extern (C) uint function(void*, uint) gc_clrAttr;
229
230     extern (C) void*  function(size_t, uint) gc_malloc;
231     extern (C) void*  function(size_t, uint) gc_calloc;
232     extern (C) void*  function(void*, size_t, uint ba) gc_realloc;
233     extern (C) size_t function(void*, size_t, size_t) gc_extend;
234     extern (C) size_t function(size_t) gc_reserve;
235     extern (C) void   function(void*) gc_free;
236
237     extern (C) void*   function(void*) gc_addrOf;
238     extern (C) size_t  function(void*) gc_sizeOf;
239
240     extern (C) BlkInfo function(void*) gc_query;
241
242     extern (C) void function(void*) gc_addRoot;
243     extern (C) void function(void*, size_t) gc_addRange;
244
245     extern (C) void function(void*) gc_removeRoot;
246     extern (C) void function(void*) gc_removeRange;
247 }
248
249 Proxy  pthis;
250 Proxy* proxy;
251
252 static this()
253 {
254     pthis.gc_enable = &gc_enable;
255     pthis.gc_disable = &gc_disable;
256     pthis.gc_collect = &gc_collect;
257     pthis.gc_minimize = &gc_minimize;
258
259     pthis.gc_getAttr = &gc_getAttr;
260     pthis.gc_setAttr = &gc_setAttr;
261     pthis.gc_clrAttr = &gc_clrAttr;
262
263     pthis.gc_malloc = &gc_malloc;
264     pthis.gc_calloc = &gc_calloc;
265     pthis.gc_realloc = &gc_realloc;
266     pthis.gc_extend = &gc_extend;
267     pthis.gc_reserve = &gc_reserve;
268     pthis.gc_free = &gc_free;
269
270     pthis.gc_addrOf = &gc_addrOf;
271     pthis.gc_sizeOf = &gc_sizeOf;
272
273     pthis.gc_query = &gc_query;
274
275     pthis.gc_addRoot = &gc_addRoot;
276     pthis.gc_addRange = &gc_addRange;
277
278     pthis.gc_removeRoot = &gc_removeRoot;
279     pthis.gc_removeRange = &gc_removeRange;
280 }
281
282 extern (C) Proxy* gc_getProxy()
283 {
284     return &pthis;
285 }
286
287 export extern (C) void gc_setProxy( Proxy* p )
288 {
289     if( proxy !is null )
290     {
291         // error?
292     }
293     proxy = p;
294     ///foreach range
295     //proxy.addRange();
296     //foreach root
297     //proxy.addRoot()
298 }
299
300 export extern (C) void gc_clrProxy()
301 {
302     // foreach root
303     // proxy.removeRoot();
304     // foreach range
305     // proxy.removeReange();
306     proxy = null;
307 }