PageRenderTime 67ms CodeModel.GetById 2ms app.highlight 61ms RepoModel.GetById 2ms app.codeStats 0ms

/src/gcstub/gc.d

http://github.com/AlexeyProkhin/druntime
D | 379 lines | 299 code | 52 blank | 28 comment | 34 complexity | 8c887d83f8251a5d45464fb8272cf11e MD5 | raw file
  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: Copyright Sean Kelly 2005 - 2009.
 17 * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
 18 * Authors:   Sean Kelly
 19 */
 20
 21/*          Copyright Sean Kelly 2005 - 2009.
 22 * Distributed under the Boost Software License, Version 1.0.
 23 *    (See accompanying file LICENSE or copy at
 24 *          http://www.boost.org/LICENSE_1_0.txt)
 25 */
 26module gc.gc;
 27
 28private
 29{
 30   import core.stdc.stdlib;
 31   import core.stdc.stdio;
 32
 33   enum BlkAttr : uint
 34    {
 35        FINALIZE    = 0b0000_0001,
 36        NO_SCAN     = 0b0000_0010,
 37        NO_MOVE     = 0b0000_0100,
 38        APPENDABLE  = 0b0000_1000,
 39        ALL_BITS    = 0b1111_1111
 40    }
 41
 42    struct BlkInfo
 43    {
 44        void*  base;
 45        size_t size;
 46        uint   attr;
 47    }
 48
 49    extern (C) void thread_init();
 50    extern (C) void onOutOfMemoryError();
 51
 52    struct Proxy
 53    {
 54        extern (C) void function() gc_enable;
 55        extern (C) void function() gc_disable;
 56        extern (C) void function() gc_collect;
 57        extern (C) void function() gc_minimize;
 58
 59        extern (C) uint function(void*) gc_getAttr;
 60        extern (C) uint function(void*, uint) gc_setAttr;
 61        extern (C) uint function(void*, uint) gc_clrAttr;
 62
 63        extern (C) void*   function(size_t, uint) gc_malloc;
 64        extern (C) BlkInfo function(size_t, uint) gc_qalloc;
 65        extern (C) void*   function(size_t, uint) gc_calloc;
 66        extern (C) void*   function(void*, size_t, uint ba) gc_realloc;
 67        extern (C) size_t  function(void*, size_t, size_t) gc_extend;
 68        extern (C) size_t  function(size_t) gc_reserve;
 69        extern (C) void    function(void*) gc_free;
 70
 71        extern (C) void*   function(void*) gc_addrOf;
 72        extern (C) size_t  function(void*) gc_sizeOf;
 73
 74        extern (C) BlkInfo function(void*) gc_query;
 75
 76        extern (C) void function(void*) gc_addRoot;
 77        extern (C) void function(void*, size_t) gc_addRange;
 78
 79        extern (C) void function(void*) gc_removeRoot;
 80        extern (C) void function(void*) gc_removeRange;
 81    }
 82
 83    __gshared Proxy  pthis;
 84    __gshared Proxy* proxy;
 85
 86    void initProxy()
 87    {
 88        pthis.gc_enable = &gc_enable;
 89        pthis.gc_disable = &gc_disable;
 90        pthis.gc_collect = &gc_collect;
 91        pthis.gc_minimize = &gc_minimize;
 92
 93        pthis.gc_getAttr = &gc_getAttr;
 94        pthis.gc_setAttr = &gc_setAttr;
 95        pthis.gc_clrAttr = &gc_clrAttr;
 96
 97        pthis.gc_malloc = &gc_malloc;
 98        pthis.gc_qalloc = &gc_qalloc;
 99        pthis.gc_calloc = &gc_calloc;
100        pthis.gc_realloc = &gc_realloc;
101        pthis.gc_extend = &gc_extend;
102        pthis.gc_reserve = &gc_reserve;
103        pthis.gc_free = &gc_free;
104
105        pthis.gc_addrOf = &gc_addrOf;
106        pthis.gc_sizeOf = &gc_sizeOf;
107
108        pthis.gc_query = &gc_query;
109
110        pthis.gc_addRoot = &gc_addRoot;
111        pthis.gc_addRange = &gc_addRange;
112
113        pthis.gc_removeRoot = &gc_removeRoot;
114        pthis.gc_removeRange = &gc_removeRange;
115    }
116
117    __gshared void** roots  = null;
118    __gshared size_t nroots = 0;
119
120    struct Range
121    {
122        void*  pos;
123        size_t len;
124    }
125
126    __gshared Range* ranges  = null;
127    __gshared size_t nranges = 0;
128}
129
130extern (C) void gc_init()
131{
132    // NOTE: The GC must initialize the thread library before its first
133    //       collection, and always before returning from gc_init().
134    thread_init();
135    initProxy();
136}
137
138extern (C) void gc_term()
139{
140    free( roots );
141    free( ranges );
142}
143
144extern (C) void gc_enable()
145{
146    if( proxy is null )
147        return;
148    return proxy.gc_enable();
149}
150
151extern (C) void gc_disable()
152{
153    if( proxy is null )
154        return;
155    return proxy.gc_disable();
156}
157
158extern (C) void gc_collect()
159{
160    if( proxy is null )
161        return;
162    return proxy.gc_collect();
163}
164
165extern (C) void gc_minimize()
166{
167    if( proxy is null )
168        return;
169    return proxy.gc_minimize();
170}
171
172extern (C) uint gc_getAttr( void* p )
173{
174    if( proxy is null )
175        return 0;
176    return proxy.gc_getAttr( p );
177}
178
179extern (C) uint gc_setAttr( void* p, uint a )
180{
181    if( proxy is null )
182        return 0;
183    return proxy.gc_setAttr( p, a );
184}
185
186extern (C) uint gc_clrAttr( void* p, uint a )
187{
188    if( proxy is null )
189        return 0;
190    return proxy.gc_clrAttr( p, a );
191}
192
193extern (C) void* gc_malloc( size_t sz, uint ba = 0 )
194{
195    if( proxy is null )
196    {
197        void* p = malloc( sz );
198
199        if( sz && p is null )
200            onOutOfMemoryError();
201        return p;
202    }
203    return proxy.gc_malloc( sz, ba );
204}
205
206extern (C) BlkInfo gc_qalloc( size_t sz, uint ba = 0 )
207{
208    if( proxy is null )
209    {
210        BlkInfo retval;
211        retval.base = gc_malloc(sz, ba);
212        retval.size = sz;
213        retval.attr = ba;
214        return retval;
215    }
216    return proxy.gc_qalloc( sz, ba );
217}
218
219extern (C) void* gc_calloc( size_t sz, uint ba = 0 )
220{
221    if( proxy is null )
222    {
223        void* p = calloc( 1, sz );
224
225        if( sz && p is null )
226            onOutOfMemoryError();
227        return p;
228    }
229    return proxy.gc_calloc( sz, ba );
230}
231
232extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 )
233{
234    if( proxy is null )
235    {
236        p = realloc( p, sz );
237
238        if( sz && p is null )
239            onOutOfMemoryError();
240        return p;
241    }
242    return proxy.gc_realloc( p, sz, ba );
243}
244
245extern (C) size_t gc_extend( void* p, size_t mx, size_t sz )
246{
247    if( proxy is null )
248        return 0;
249    return proxy.gc_extend( p, mx, sz );
250}
251
252extern (C) size_t gc_reserve( size_t sz )
253{
254    if( proxy is null )
255        return 0;
256    return proxy.gc_reserve( sz );
257}
258
259extern (C) void gc_free( void* p )
260{
261    if( proxy is null )
262        return free( p );
263    return proxy.gc_free( p );
264}
265
266extern (C) void* gc_addrOf( void* p )
267{
268    if( proxy is null )
269        return null;
270    return proxy.gc_addrOf( p );
271}
272
273extern (C) size_t gc_sizeOf( void* p )
274{
275    if( proxy is null )
276        return 0;
277    return proxy.gc_sizeOf( p );
278}
279
280extern (C) BlkInfo gc_query( void* p )
281{
282    if( proxy is null )
283        return BlkInfo.init;
284    return proxy.gc_query( p );
285}
286
287extern (C) void gc_addRoot( void* p )
288{
289    if( proxy is null )
290    {
291        void** r = cast(void**) realloc( roots,
292                                         (nroots+1) * roots[0].sizeof );
293        if( r is null )
294            onOutOfMemoryError();
295        r[nroots++] = p;
296        roots = r;
297        return;
298    }
299    return proxy.gc_addRoot( p );
300}
301
302extern (C) void gc_addRange( void* p, size_t sz )
303{
304    //printf("gcstub::gc_addRange() proxy = %p\n", proxy);
305    if( proxy is null )
306    {
307        Range* r = cast(Range*) realloc( ranges,
308                                         (nranges+1) * ranges[0].sizeof );
309        if( r is null )
310            onOutOfMemoryError();
311        r[nranges].pos = p;
312        r[nranges].len = sz;
313        ranges = r;
314        ++nranges;
315        return;
316    }
317    return proxy.gc_addRange( p, sz );
318}
319
320extern (C) void gc_removeRoot( void *p )
321{
322    if( proxy is null )
323    {
324        for( size_t i = 0; i < nroots; ++i )
325        {
326            if( roots[i] is p )
327            {
328                roots[i] = roots[--nroots];
329                return;
330            }
331        }
332        assert( false );
333    }
334    return proxy.gc_removeRoot( p );
335}
336
337extern (C) void gc_removeRange( void *p )
338{
339    if( proxy is null )
340    {
341        for( size_t i = 0; i < nranges; ++i )
342        {
343            if( ranges[i].pos is p )
344            {
345                ranges[i] = ranges[--nranges];
346                return;
347            }
348        }
349        assert( false );
350    }
351    return proxy.gc_removeRange( p );
352}
353
354extern (C) Proxy* gc_getProxy()
355{
356    return &pthis;
357}
358
359export extern (C) void gc_setProxy( Proxy* p )
360{
361    if( proxy !is null )
362    {
363        // TODO: Decide if this is an error condition.
364    }
365    proxy = p;
366    foreach( r; roots[0 .. nroots] )
367        proxy.gc_addRoot( r );
368    foreach( r; ranges[0 .. nranges] )
369        proxy.gc_addRange( r.pos, r.len );
370}
371
372export extern (C) void gc_clrProxy()
373{
374    foreach( r; ranges[0 .. nranges] )
375        proxy.gc_removeRange( r.pos );
376    foreach( r; roots[0 .. nroots] )
377        proxy.gc_removeRoot( r );
378    proxy = null;
379}