1 #pragma once 2 3 #include <ucontext.h> 4 #include <stdlib.h> 5 6 namespace MT 7 { 8 9 // 10 // 11 // 12 class Fiber 13 { 14 void * funcData; 15 TThreadEntryPoint func; 16 17 ucontext_t fiberContext; 18 bool isInitialized; 19 20 static void FiberFuncInternal(void *pFiber) 21 { 22 Fiber* self = (Fiber*)pFiber; 23 self->func(self->funcData); 24 } 25 26 private: 27 28 Fiber(const Fiber &) {} 29 void operator=(const Fiber &) {} 30 31 public: 32 33 Fiber() 34 : isInitialized(false) 35 { 36 } 37 38 ~Fiber() 39 { 40 if (isInitialized) 41 { 42 if (func != nullptr) 43 { 44 free(fiberContext.uc_stack.ss_sp); 45 } 46 isInitialized = false; 47 } 48 } 49 50 51 void CreateFromThread(Thread & thread) 52 { 53 ASSERT(!isInitialized, "Already initialized"); 54 ASSERT(thread.IsCurrentThread(), "Can't create fiber from this thread"); 55 56 ucontext_t m; 57 fiberContext.uc_link = &m; 58 59 int res = getcontext(&fiberContext); 60 ASSERT(res == 0, "getcontext - failed"); 61 62 fiberContext.uc_link = nullptr; 63 fiberContext.uc_stack.ss_sp = thread.GetStackBase(); 64 fiberContext.uc_stack.ss_size = thread.GetStackSize(); 65 fiberContext.uc_stack.ss_flags = 0; 66 67 func = nullptr; 68 funcData = nullptr; 69 70 isInitialized = true; 71 } 72 73 74 void Create(size_t stackSize, TThreadEntryPoint entryPoint, void *userData) 75 { 76 ASSERT(!isInitialized, "Already initialized"); 77 78 func = entryPoint; 79 funcData = userData; 80 81 int res = getcontext(&fiberContext); 82 ASSERT(res == 0, "getcontext - failed"); 83 84 fiberContext.uc_link = nullptr; 85 fiberContext.uc_stack.ss_sp = malloc(stackSize); 86 fiberContext.uc_stack.ss_size = stackSize; 87 fiberContext.uc_stack.ss_flags = 0; 88 makecontext(&fiberContext, (void(*)())&FiberFuncInternal, 1, this); 89 90 isInitialized = true; 91 } 92 93 static void SwitchTo(Fiber & from, Fiber & to) 94 { 95 __sync_synchronize(); 96 97 ASSERT(from.isInitialized, "Invalid from fiber"); 98 ASSERT(to.isInitialized, "Invalid to fiber"); 99 int res = swapcontext(&from.fiberContext, &to.fiberContext); 100 ASSERT(res == 0, "setcontext - failed"); 101 } 102 103 104 105 }; 106 107 108 } 109 110 111