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