2
0

fiber.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. #include "fiber.h"
  2. #include "fcontext.h"
  3. #include "../../time/native/time.h"
  4. #include "../../async/native/async.h"
  5. namespace bbFiber{
  6. const int MAX_FIBERS=1024;
  7. const size_t STACK_SIZE=65536; //woho
  8. const size_t STACK_BUF_SIZE=65536;
  9. struct Fiber{
  10. Fiber *succ;
  11. int id;
  12. unsigned char *stack;
  13. bbDBContext *dbContext;
  14. bbGCFiber *gcFiber;
  15. fcontext_t fcontext;
  16. fcontext_t fcontext2;
  17. };
  18. Fiber *fibers;
  19. Fiber *freeFibers;
  20. Fiber *mainFiber;
  21. Fiber *currFiber;
  22. unsigned char *stackBuf,*stackEnd;
  23. unsigned char *allocStack(){
  24. if( stackBuf==stackEnd ){
  25. stackBuf=alloc_fcontext_stack( STACK_BUF_SIZE,false );
  26. stackEnd=stackBuf+STACK_BUF_SIZE;
  27. }
  28. unsigned char *p=stackBuf;
  29. stackBuf+=STACK_SIZE;
  30. return p;
  31. }
  32. void init(){
  33. if( fibers ) return;
  34. fibers=new Fiber[MAX_FIBERS];
  35. bbGCFiber *gcFibers=new bbGCFiber[MAX_FIBERS];
  36. bbDBContext *dbContexts=new bbDBContext[MAX_FIBERS];
  37. for( int i=0;i<MAX_FIBERS;++i ){
  38. fibers[i].id=i;
  39. fibers[i].succ=&fibers[i+1];
  40. fibers[i].stack=nullptr;
  41. fibers[i].gcFiber=&gcFibers[i];
  42. fibers[i].dbContext=&dbContexts[i];
  43. fibers[i].fcontext=nullptr;
  44. fibers[i].fcontext2=nullptr;
  45. }
  46. fibers[MAX_FIBERS-1].succ=nullptr;
  47. freeFibers=&fibers[1];
  48. mainFiber=&fibers[0];
  49. mainFiber->gcFiber=bbGC::currentFiber;
  50. mainFiber->dbContext=bbDB::currentContext;
  51. currFiber=mainFiber;
  52. }
  53. Fiber *getFiber( int id ){
  54. if( !fibers ) return nullptr;
  55. Fiber *fiber=&fibers[id & (MAX_FIBERS-1)];
  56. if( fiber->id==id ) return fiber;
  57. return nullptr;
  58. }
  59. Fiber *allocFiber(){
  60. if( !fibers ) init();
  61. Fiber *fiber=freeFibers;
  62. if( !fiber ) return nullptr;
  63. if( !fiber->stack ) fiber->stack=allocStack();
  64. freeFibers=fiber->succ;
  65. fiber->id+=MAX_FIBERS;
  66. return fiber;
  67. }
  68. fcontext_t freeFiber( Fiber *fiber ){
  69. fcontext_t fcontext=fiber->fcontext2;
  70. fiber->id+=MAX_FIBERS;
  71. fiber->succ=freeFibers;
  72. freeFibers=fiber;
  73. return fcontext;
  74. }
  75. void setCurrFiber( Fiber *fiber ){
  76. bbGC::currentFiber=fiber->gcFiber;
  77. bbDB::currentContext=fiber->dbContext;
  78. currFiber=fiber;
  79. }
  80. void fiberEntry( transfer_t t ){
  81. Fiber *fiber=(Fiber*)t.data;
  82. fiber->fcontext2=t.fcontext;
  83. fiber->dbContext->init();
  84. fiber->gcFiber->link();
  85. setCurrFiber( fiber );
  86. fiber->gcFiber->entry();
  87. fiber->gcFiber->unlink();
  88. jump_fcontext( freeFiber( fiber ),nullptr );
  89. }
  90. // ***** API *****
  91. // Currently unsafe!
  92. //
  93. // gcFiber->entry will not be gc_marked until fiber is running...
  94. //
  95. int createFiber( Entry entry ){
  96. Fiber *fiber=allocFiber();
  97. if( !fiber ) return 0;
  98. fiber->gcFiber->entry=entry;
  99. fiber->fcontext=make_fcontext( fiber->stack+STACK_SIZE,STACK_SIZE,fiberEntry );
  100. return fiber->id;
  101. }
  102. // Safe!
  103. //
  104. int startFiber( Entry entry ){
  105. Fiber *fiber=allocFiber();
  106. if( !fiber ) return 0;
  107. int id=fiber->id;
  108. fiber->gcFiber->entry=entry;
  109. fiber->fcontext=make_fcontext( fiber->stack+STACK_SIZE,STACK_SIZE,fiberEntry );
  110. Fiber *curr=currFiber;
  111. fiber->fcontext=jump_fcontext( fiber->fcontext,fiber ).fcontext;
  112. setCurrFiber( curr );
  113. return id;
  114. }
  115. void resumeFiber( int id ){
  116. Fiber *fiber=getFiber( id );
  117. if( !fiber ){
  118. //
  119. // could signal a semaphore...?
  120. //
  121. bbDB::error( "Invalid fiber id" );
  122. return;
  123. }
  124. Fiber *curr=currFiber;
  125. fiber->fcontext=jump_fcontext( fiber->fcontext,fiber ).fcontext;
  126. setCurrFiber( curr );
  127. }
  128. void suspendCurrentFiber(){
  129. if( currFiber==mainFiber ){
  130. //
  131. // could wait on a semaphore...?
  132. //
  133. bbDB::error( "Can't suspend main fiber" );
  134. return;
  135. }
  136. Fiber *fiber=currFiber;
  137. fiber->fcontext2=jump_fcontext( fiber->fcontext2,nullptr ).fcontext;
  138. setCurrFiber( fiber );
  139. }
  140. void currentFiberSleep( double seconds ){
  141. struct ResumeEvent : public bbAsync::Event{
  142. int fiber;
  143. ResumeEvent():fiber( getCurrentFiber() ){}
  144. void dispatch(){
  145. resumeFiber( fiber );
  146. }
  147. };
  148. ResumeEvent event;
  149. event.post( seconds );
  150. suspendCurrentFiber();
  151. }
  152. void terminateFiber( int id ){
  153. }
  154. int getCurrentFiber(){
  155. if( fibers ) return currFiber->id;
  156. return 0;
  157. }
  158. }