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 #define MT_FIBER_DEBUG (1)
26 
27 namespace MT
28 {
29 
30 	//
31 	//
32 	//
33 	class Fiber
34 	{
35 		void * funcData;
36 		TThreadEntryPoint func;
37 
38 		void* fiber;
39 
40 #if MT_FIBER_DEBUG
41 		AtomicInt counter;
42 		AtomicInt ownerThread;
43 #endif
44 
45 		static void __stdcall FiberFuncInternal(void *pFiber)
46 		{
47 			Fiber* self = (Fiber*)pFiber;
48 			self->func(self->funcData);
49 		}
50 
51 	private:
52 
53 		Fiber(const Fiber &) {}
54 		void operator=(const Fiber &) {}
55 
56 	public:
57 
58 		Fiber()
59 			: fiber(nullptr)
60 		{
61 		}
62 
63 		~Fiber()
64 		{
65 			if (fiber)
66 			{
67 				//we don't need to delete context on fibers created from thread.
68 				if (func != nullptr)
69 				{
70 					DeleteFiber(fiber);
71 				}
72 
73 				fiber = nullptr;
74 			}
75 		}
76 
77 
78 		void CreateFromThread(Thread & thread)
79 		{
80 			MT_ASSERT(fiber == nullptr, "Fiber already created");
81 			MT_ASSERT(thread.IsCurrentThread(), "Can't create fiber from this thread");
82 
83 			func = nullptr;
84 			funcData = nullptr;
85 
86 			fiber = ::ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH);
87 			MT_ASSERT(fiber != nullptr, "Can't create fiber");
88 
89 #if MT_FIBER_DEBUG
90 			ownerThread.Set(0xFFFFFFFF);
91 			counter.Set(1);
92 #endif
93 		}
94 
95 
96 		void Create(size_t stackSize, TThreadEntryPoint entryPoint, void *userData)
97 		{
98 			MT_ASSERT(fiber == nullptr, "Fiber already created");
99 
100 			func = entryPoint;
101 			funcData = userData;
102 			fiber = ::CreateFiber( stackSize, FiberFuncInternal, this );
103 			MT_ASSERT(fiber != nullptr, "Can't create fiber");
104 
105 #if MT_FIBER_DEBUG
106 			ownerThread.Set(0xFFFFFFFF);
107 			counter.Set(0);
108 #endif
109 		}
110 
111 #if MT_FIBER_DEBUG
112 		int GetUsageCounter() const
113 		{
114 			return counter.Get();
115 		}
116 
117 		int GetOwnerThread() const
118 		{
119 			return ownerThread.Get();
120 		}
121 
122 #endif
123 
124 
125 		static void SwitchTo(Fiber & from, Fiber & to)
126 		{
127 			MemoryBarrier();
128 
129 			MT_ASSERT(from.fiber != nullptr, "Invalid from fiber");
130 			MT_ASSERT(to.fiber != nullptr, "Invalid to fiber");
131 
132 #if MT_FIBER_DEBUG
133 
134 			to.ownerThread.Set(::GetCurrentThreadId());
135 
136 			MT_ASSERT(from.counter.Get() == 1, "Invalid fiber state");
137 			MT_ASSERT(to.counter.Get() == 0, "Invalid fiber state");
138 
139 			int counterNow = from.counter.Dec();
140 			MT_ASSERT(counterNow == 0, "Invalid fiber state");
141 
142 			counterNow = to.counter.Inc();
143 			MT_ASSERT(counterNow == 1, "Invalid fiber state");
144 #endif
145 
146 			::SwitchToFiber( (LPVOID)to.fiber );
147 		}
148 
149 
150 	};
151 
152 
153 }
154 
155 
156