bbgc.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  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. namespace bbGC{
  34. int markedBit;
  35. int unmarkedBit;
  36. bbGCNode *markQueue;
  37. bbGCNode *markedList;
  38. bbGCNode *unmarkedList;
  39. bbGCRoot *roots;
  40. bbGCFiber *fibers;
  41. bbGCFiber *currentFiber;
  42. bbGCTmp *freeTmps;
  43. bbGCNode markLists[2];
  44. bbGCNode freeList;
  45. size_t markedBytes;
  46. size_t unmarkedBytes;
  47. size_t allocedBytes;
  48. void init(){
  49. static bool done;
  50. if( done ) return;
  51. done=true;
  52. markedBit=1;
  53. markedList=&markLists[0];
  54. markedList->succ=markedList->pred=markedList;
  55. unmarkedBit=2;
  56. unmarkedList=&markLists[1];
  57. unmarkedList->succ=unmarkedList->pred=unmarkedList;
  58. freeList.succ=freeList.pred=&freeList;
  59. fibers=new bbGCFiber;
  60. currentFiber=fibers;
  61. }
  62. void destroy( bbGCNode *p ){
  63. // printf( "destroying: %s %p\n",p->typeName(),p );
  64. #if BBGC_DEBUG
  65. p->flags=3;
  66. #else
  67. p->~bbGCNode();
  68. bbFree( p );
  69. #endif
  70. }
  71. void reclaim( size_t size=0x7fffffff ){
  72. while( freeList.succ!=&freeList ){
  73. bbGCNode *p=freeList.succ;
  74. size_t psize=bbMallocSize( p );
  75. remove( p );
  76. destroy( p );
  77. if( psize>=size ) break;
  78. size-=psize;
  79. }
  80. }
  81. void mark( bbGCNode *p ){
  82. if( !p || p->flags==markedBit ) return;
  83. remove( p );
  84. insert( p,markedList );
  85. p->flags=markedBit;
  86. markedBytes+=bbMallocSize( p );
  87. p->gcMark();
  88. }
  89. void markRoots(){
  90. for( bbGCRoot *root=roots;root;root=root->succ ){
  91. root->gcMark();
  92. }
  93. }
  94. void markFibers(){
  95. bbGCFiber *fiber=fibers;
  96. for(;;){
  97. bbGCMark( fiber->entry );
  98. for( bbGCFrame *frame=fiber->frames;frame;frame=frame->succ ){
  99. frame->gcMark();
  100. }
  101. for( bbGCNode *node=fiber->ctoring;node;node=node->succ ){
  102. node->gcMark();
  103. }
  104. for( bbGCTmp *tmp=fiber->tmps;tmp;tmp=tmp->succ ){
  105. tmp->node->gcMark();
  106. }
  107. fiber=fiber->succ;
  108. if( fiber==fibers ) break;
  109. }
  110. }
  111. void markQueued( size_t tomark=0x7fffffff ){
  112. while( markQueue && markedBytes<tomark ){
  113. bbGCNode *p=markQueue;
  114. markQueue=p->succ;
  115. insert( p,markedList );
  116. markedBytes+=bbMallocSize( p );
  117. // printf( "marking %s\n",p->typeName() );fflush( stdout );
  118. p->gcMark();
  119. }
  120. }
  121. void sweep(){
  122. // puts( "bbGC::sweep()" );fflush( stdout );
  123. markFibers();
  124. markQueued();
  125. if( unmarkedList->succ!=unmarkedList ){
  126. //append unmarked to end of free queue
  127. unmarkedList->succ->pred=freeList.pred;
  128. unmarkedList->pred->succ=&freeList;
  129. freeList.pred->succ=unmarkedList->succ;
  130. freeList.pred=unmarkedList->pred;
  131. //clear unmarked
  132. unmarkedList->succ=unmarkedList->pred=unmarkedList;
  133. }
  134. std::swap( markedList,unmarkedList );
  135. std::swap( markedBit,unmarkedBit );
  136. unmarkedBytes=markedBytes;
  137. markedBytes=0;
  138. allocedBytes=0;
  139. markRoots();
  140. }
  141. bbGCNode *alloc( size_t size ){
  142. #ifndef BBGC_DISABLED
  143. if( allocedBytes>=BBGC_TRIGGER ){
  144. sweep();
  145. #if BBGC_AGGRESSIVE
  146. reclaim();
  147. #endif
  148. }else{
  149. #if BBGC_INCREMENTAL
  150. // size_t tomark=double( allocedBytes ) / double( BBGC_TRIGGER ) * double( unmarkedBytes + allocedBytes );
  151. size_t tomark=double( allocedBytes ) / double( BBGC_TRIGGER ) * double( unmarkedBytes + BBGC_TRIGGER );
  152. markQueued( tomark );
  153. #endif
  154. }
  155. #endif
  156. bbGCNode *p=(bbGCNode*)bbMalloc( size );
  157. *((void**)p)=(void*)0xcafebabe;
  158. p->flags=0;
  159. size=bbMallocSize( p );
  160. allocedBytes+=size;
  161. #if !BBGC_AGGRESSIVE
  162. reclaim( size );
  163. #endif
  164. return p;
  165. }
  166. void collect(){
  167. sweep();
  168. reclaim();
  169. // printf( "GCCollect: in use=%i\n",(int)unmarkedBytes );fflush( stdout );
  170. }
  171. }