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