/src/gcstub/gc.d
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}