bbgc.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. //v1001
  2. #include <utility>
  3. #include "bbgc.h"
  4. // For testing only...
  5. // #define BBGC_DISABLED 1
  6. //For future ref...
  7. #if BB_THREADED
  8. //fast but unpredictable
  9. //#define BBGC_LOCK while( bbGC::spinlock.test_and_set( std::memory_order_acquire ) ) std::this_thread::yield();
  10. //#define BBGC_UNLOCK bbGC::spinlock.clear( std::memory_order_release );
  11. //pretty slow...
  12. //#define BBGC_LOCK bbGC::mutex.lock();
  13. //#define BBGC_UNLOCK bbGC::mutex.unlock();
  14. //better...a 'Benaphore' apparently...
  15. #define BBGC_LOCK \
  16. if( ++bbGC::locks>1 ){ \
  17. std::unique_lock<std::mutex> lock( bbGC::mutex ); \
  18. bbGC::cond_var.wait( lock,[]{ return bbGC::sem_count>0;} ); \
  19. --bbGC::sem_count; \
  20. }
  21. #define BBGC_UNLOCK \
  22. if( --bbGC::locks>0 ){ \
  23. std::unique_lock<std::mutex> lock( bbGC::mutex ); \
  24. ++bbGC::sem_count; \
  25. bbGC::cond_var.notify_one(); \
  26. }
  27. int sem_count;
  28. std::mutex mutex;
  29. std::atomic_int locks;
  30. std::condition_variable cond_var;
  31. std::atomic_flag spinlock=ATOMIC_FLAG_INIT;
  32. #endif
  33. struct bbGCRetained{
  34. bbGCRetained *succ;
  35. bbGCNode *node;
  36. };
  37. namespace bbGC{
  38. int markedBit;
  39. int unmarkedBit;
  40. bbGCNode *markQueue;
  41. bbGCNode *markedList;
  42. bbGCNode *unmarkedList;
  43. bbGCRoot *roots;
  44. bbGCFiber *fibers;
  45. bbGCFiber *currentFiber;
  46. bbGCTmp *freeTmps;
  47. bbGCNode markLists[2];
  48. bbGCNode freeList;
  49. size_t markedBytes;
  50. size_t unmarkedBytes;
  51. size_t allocedBytes;
  52. bbGCRetained *retained;
  53. bbGCRetained *retained_free;
  54. void init(){
  55. static bool done;
  56. if( done ) return;
  57. done=true;
  58. markedBit=1;
  59. markedList=&markLists[0];
  60. markedList->succ=markedList->pred=markedList;
  61. unmarkedBit=2;
  62. unmarkedList=&markLists[1];
  63. unmarkedList->succ=unmarkedList->pred=unmarkedList;
  64. freeList.succ=freeList.pred=&freeList;
  65. fibers=new bbGCFiber;
  66. currentFiber=fibers;
  67. }
  68. void destroy( bbGCNode *p ){
  69. // printf( "destroying: %s %p\n",p->typeName(),p );
  70. #if BBGC_DEBUG
  71. p->flags=3;
  72. #else
  73. p->~bbGCNode();
  74. bbFree( p );
  75. #endif
  76. }
  77. void reclaim( size_t size=0x7fffffff ){
  78. while( freeList.succ!=&freeList ){
  79. bbGCNode *p=freeList.succ;
  80. size_t psize=bbMallocSize( p );
  81. remove( p );
  82. destroy( p );
  83. if( psize>=size ) break;
  84. size-=psize;
  85. }
  86. }
  87. void mark( bbGCNode *p ){
  88. if( !p || p->flags==markedBit ) return;
  89. remove( p );
  90. insert( p,markedList );
  91. p->flags=markedBit;
  92. markedBytes+=bbMallocSize( p );
  93. p->gcMark();
  94. }
  95. void markRoots(){
  96. for( bbGCRoot *root=roots;root;root=root->succ ){
  97. root->gcMark();
  98. }
  99. }
  100. void markRetained(){
  101. for( bbGCRetained *r=retained;r;r=r->succ ){
  102. if( r->node ) r->node->gcMark();
  103. r=r->succ;
  104. }
  105. }
  106. void markFibers(){
  107. bbGCFiber *fiber=fibers;
  108. for(;;){
  109. bbGCMark( fiber->entry );
  110. for( bbGCFrame *frame=fiber->frames;frame;frame=frame->succ ){
  111. frame->gcMark();
  112. }
  113. for( bbGCNode *node=fiber->ctoring;node;node=node->succ ){
  114. node->gcMark();
  115. }
  116. for( bbGCTmp *tmp=fiber->tmps;tmp;tmp=tmp->succ ){
  117. tmp->node->gcMark();
  118. }
  119. fiber=fiber->succ;
  120. if( fiber==fibers ) break;
  121. }
  122. }
  123. void markQueued( size_t tomark=0x7fffffff ){
  124. while( markQueue && markedBytes<tomark ){
  125. bbGCNode *p=markQueue;
  126. markQueue=p->succ;
  127. insert( p,markedList );
  128. markedBytes+=bbMallocSize( p );
  129. // printf( "marking %s\n",p->typeName() );fflush( stdout );
  130. p->gcMark();
  131. }
  132. }
  133. void sweep(){
  134. // puts( "bbGC::sweep()" );fflush( stdout );
  135. markRetained();
  136. markFibers();
  137. markQueued();
  138. if( unmarkedList->succ!=unmarkedList ){
  139. //append unmarked to end of free queue
  140. unmarkedList->succ->pred=freeList.pred;
  141. unmarkedList->pred->succ=&freeList;
  142. freeList.pred->succ=unmarkedList->succ;
  143. freeList.pred=unmarkedList->pred;
  144. //clear unmarked
  145. unmarkedList->succ=unmarkedList->pred=unmarkedList;
  146. }
  147. std::swap( markedList,unmarkedList );
  148. std::swap( markedBit,unmarkedBit );
  149. unmarkedBytes=markedBytes;
  150. markedBytes=0;
  151. allocedBytes=0;
  152. markRoots();
  153. }
  154. bbGCNode *alloc( size_t size ){
  155. #ifndef BBGC_DISABLED
  156. if( allocedBytes>=BBGC_TRIGGER ){
  157. sweep();
  158. #if BBGC_AGGRESSIVE
  159. reclaim();
  160. #endif
  161. }else{
  162. #if BBGC_INCREMENTAL
  163. // size_t tomark=double( allocedBytes ) / double( BBGC_TRIGGER ) * double( unmarkedBytes + allocedBytes );
  164. size_t tomark=double( allocedBytes ) / double( BBGC_TRIGGER ) * double( unmarkedBytes + BBGC_TRIGGER );
  165. markQueued( tomark );
  166. #endif
  167. }
  168. #endif
  169. bbGCNode *p=(bbGCNode*)bbMalloc( size );
  170. *((void**)p)=(void*)0xcafebabe;
  171. p->flags=0;
  172. size=bbMallocSize( p );
  173. allocedBytes+=size;
  174. #if !BBGC_AGGRESSIVE
  175. reclaim( size );
  176. #endif
  177. return p;
  178. }
  179. void collect(){
  180. sweep();
  181. reclaim();
  182. // printf( "GCCollect: in use=%i\n",(int)unmarkedBytes );fflush( stdout );
  183. }
  184. void retain( bbGCNode *node ){
  185. bbGCRetained *r=retained_free;
  186. if( !r ){
  187. //should alloc buf-worth...
  188. r=new bbGCRetained;
  189. }
  190. r->node=node;
  191. r->succ=retained;
  192. retained=r;
  193. }
  194. void release( bbGCNode *node ){
  195. bbGCRetained **p=&retained;
  196. while( bbGCRetained *r=*p ){
  197. if( r->node==node ){
  198. *p=r->succ;
  199. r->succ=retained_free;
  200. retained_free=r;
  201. return;
  202. }
  203. p=&r->succ;
  204. r=r->succ;
  205. }
  206. printf( "Wanting! bbGC::release() node not found!\n" );
  207. }
  208. }