Borneq

contextclass

Aug 22nd, 2014
374
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 2.52 KB | None | 0 0
  1. #include <ucontext.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <setjmp.h>
  5.  
  6. struct fiber_t
  7. {
  8.     ucontext_t  fib;
  9.     jmp_buf     jmp;
  10. };
  11.  
  12. struct fiber_ctx_t
  13. {
  14.     void(*      fnc)(void*);
  15.     void*       ctx;
  16.     jmp_buf*    cur;
  17.     ucontext_t* prv;
  18. };
  19.  
  20. class Coroutine{
  21. private:
  22.   fiber_t fib;
  23. public:
  24.     virtual void execute() =0;
  25.     void yield(Coroutine *next=NULL);
  26.     void attach();
  27.     Coroutine(long stackSize);
  28.     virtual ~Coroutine();
  29. };
  30.  
  31.  
  32. static void fiber_start_fnc(void* p)
  33. {
  34.     fiber_ctx_t* ctx = (fiber_ctx_t*)p;
  35.     void* uctx = ctx->ctx;
  36.     if (_setjmp(*ctx->cur) == 0)
  37.     {
  38.         ucontext_t tmp;
  39.         swapcontext(&tmp, ctx->prv);
  40.     }
  41.     Coroutine *coroutine = (Coroutine *)uctx;
  42.     coroutine->execute();
  43. }
  44.  
  45. inline void create_fiber(fiber_t* fib, void* uctx)
  46. {
  47.     getcontext(&fib->fib);
  48.     size_t const stack_size = 64*1024;
  49.     fib->fib.uc_stack.ss_sp = (::malloc)(stack_size);
  50.     fib->fib.uc_stack.ss_size = stack_size;
  51.     fib->fib.uc_link = 0;
  52.     ucontext_t tmp;
  53.     fiber_ctx_t ctx = {NULL, uctx, &fib->jmp, &tmp};
  54.     makecontext(&fib->fib, (void(*)())fiber_start_fnc, 1, &ctx);
  55.     swapcontext(&tmp, &fib->fib);
  56. }
  57.  
  58. inline void switch_to_fiber(fiber_t& fiber, fiber_t& prevfiber)
  59. {
  60.     if (_setjmp(prevfiber.jmp) == 0)
  61.         _longjmp(fiber.jmp, 1);
  62. }
  63.  
  64. __thread fiber_t fibmain;
  65. __thread bool initialized_fibmain = false;
  66.  
  67. void Coroutine::yield(Coroutine *next)
  68. {
  69.     if (next==NULL)
  70.        switch_to_fiber(fibmain, fib);
  71.     else
  72.        switch_to_fiber(next->fib, fib);
  73. }
  74.  
  75. void Coroutine::attach()
  76. {
  77.     switch_to_fiber(fib, fibmain);
  78. }
  79.  
  80. Coroutine::Coroutine(long stackSize)
  81. {
  82.     if (!initialized_fibmain)
  83.     {
  84.         create_fiber(&fibmain, NULL);
  85.         initialized_fibmain = true;
  86.     }
  87.     create_fiber(&fib, this);
  88. }
  89.  
  90. Coroutine::~Coroutine()
  91. {
  92.     free(fib.fib.uc_stack.ss_sp);
  93. }
  94.  
  95.  
  96. Coroutine *A,*B;
  97.  
  98. class CoroutineA : public Coroutine{
  99. public:
  100.     CoroutineA(): Coroutine(8*1024){};
  101.     void execute()
  102.     {
  103.         printf("CoroutineA\n");
  104.         for (int i=0; i<100; i++)
  105.         {
  106.             printf("i=%d\n",i);
  107.             yield(B);
  108.         }
  109.         printf("after yield CoroutineA\n");
  110.     }
  111. };
  112.  
  113. class CoroutineB : public Coroutine{
  114. public:
  115.     CoroutineB(): Coroutine(8*1024){};
  116.     void execute()
  117.     {
  118.         printf("CoroutineB\n");
  119.         for (int i=0; i<100; i++)
  120.         {
  121.             printf("i=%d\n",i);
  122.             yield(A);
  123.         }
  124.         printf("after yield CoroutineB\n");
  125.     }
  126. };
  127.  
  128.  
  129. int main()
  130. {
  131.     A = new CoroutineA();
  132.     B = new CoroutineB();
  133.     A->attach();
  134.     delete A;
  135.     delete B;
  136.     return 0;
  137. }
Advertisement
Add Comment
Please, Sign In to add comment