1 // The MIT License (MIT)
2 //
3 // 	Copyright (c) 2015 Sergey Makeev, Vadim Slyusarev
4 //
5 // 	Permission is hereby granted, free of charge, to any person obtaining a copy
6 // 	of this software and associated documentation files (the "Software"), to deal
7 // 	in the Software without restriction, including without limitation the rights
8 // 	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // 	copies of the Software, and to permit persons to whom the Software is
10 // 	furnished to do so, subject to the following conditions:
11 //
12 //  The above copyright notice and this permission notice shall be included in
13 // 	all copies or substantial portions of the Software.
14 //
15 // 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // 	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // 	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // 	THE SOFTWARE.
22 
23 #pragma once
24 
25 #include <ucontext.h>
26 #include <stdlib.h>
27 #include <string.h>
28 
29 namespace MT
30 {
31 
32 	//
33 	//
34 	//
35 	class Fiber
36 	{
37 		void * funcData;
38 		TThreadEntryPoint func;
39 
40 		ucontext_t fiberContext;
41 		bool isInitialized;
42 
43 		static void FiberFuncInternal(void *pFiber)
44 		{
45 			MT_ASSERT(pFiber != nullptr, "Invalid fiber");
46 			Fiber* self = (Fiber*)pFiber;
47 
48 /*
49 			static char temp[128];
50 			sprintf(temp, "Using non initialized fiber %p", pFiber);
51 			MT_ASSERT(self->isInitialized == true, temp);
52 */
53 
54 			MT_ASSERT(self->isInitialized == true, "Using non initialized fiber");
55 
56 
57 			MT_ASSERT(self->func != nullptr, "Invalid fiber func");
58 			self->func(self->funcData);
59 		}
60 
61 	private:
62 
63 		Fiber(const Fiber &) {}
64 		void operator=(const Fiber &) {}
65 
66 	public:
67 
68 		Fiber()
69 			: funcData(nullptr)
70 			, func(nullptr)
71 			, isInitialized(false)
72 		{
73 			memset(&fiberContext, 0, sizeof(ucontext_t));
74 		}
75 
76 		~Fiber()
77 		{
78 			if (isInitialized)
79 			{
80 				if (func != nullptr)
81 				{
82 					free(fiberContext.uc_stack.ss_sp);
83 				}
84 				isInitialized = false;
85 			}
86 		}
87 
88 
89 		void CreateFromThread(Thread & thread)
90 		{
91 			MT_ASSERT(!isInitialized, "Already initialized");
92 			MT_ASSERT(thread.IsCurrentThread(), "ERROR: Can create fiber only from current thread!");
93 
94 //			ucontext_t m;
95 			//fiberContext.uc_link = &m;
96 
97 			int res = getcontext(&fiberContext);
98 			MT_ASSERT(res == 0, "getcontext - failed");
99 
100 			fiberContext.uc_link = nullptr;
101 			fiberContext.uc_stack.ss_sp = thread.GetStackBase();
102 			fiberContext.uc_stack.ss_size = thread.GetStackSize();
103 			fiberContext.uc_stack.ss_flags = 0;
104 
105 			func = nullptr;
106 			funcData = nullptr;
107 
108 			isInitialized = true;
109 		}
110 
111 
112 		void Create(size_t stackSize, TThreadEntryPoint entryPoint, void *userData)
113 		{
114 			MT_ASSERT(!isInitialized, "Already initialized");
115 
116 			func = entryPoint;
117 			funcData = userData;
118 
119 			int res = getcontext(&fiberContext);
120 			MT_ASSERT(res == 0, "getcontext - failed");
121 
122 			fiberContext.uc_link = nullptr;
123 			fiberContext.uc_stack.ss_sp = malloc(stackSize);
124 			fiberContext.uc_stack.ss_size = stackSize;
125 			fiberContext.uc_stack.ss_flags = 0;
126 
127 			makecontext(&fiberContext, (void(*)())&FiberFuncInternal, 1, (void *)this);
128 
129 			isInitialized = true;
130 		}
131 
132 		static void SwitchTo(Fiber & from, Fiber & to)
133 		{
134 			 __sync_synchronize();
135 
136 			MT_ASSERT(from.isInitialized, "Invalid from fiber");
137 			MT_ASSERT(to.isInitialized, "Invalid to fiber");
138 
139 			int res = swapcontext(&from.fiberContext, &to.fiberContext);
140 			MT_ASSERT(res == 0, "setcontext - failed");
141 		}
142 
143 
144 
145 	};
146 
147 
148 }
149 
150 
151