fiber.cpp 3.8 KB

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