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 <pthread.h>
26 #include <unistd.h>
27 #include <time.h>
28 #include <limits.h>
29 #include <stdlib.h>
30 
31 #ifdef __APPLE_CC__
32 #include <thread>
33 #endif
34 
35 #define _DARWIN_C_SOURCE
36 #include <sys/mman.h>
37 
38 #ifndef MAP_ANONYMOUS
39     #define MAP_ANONYMOUS MAP_ANON
40 #endif
41 
42 #ifndef MAP_STACK
43     #define MAP_STACK (0)
44 #endif
45 
46 #include <Platform/Common/MTThread.h>
47 #include <MTAllocator.h>
48 
49 namespace MT
50 {
51 	class _Fiber;
52 
53 	class Thread : public ThreadBase
54 	{
55 		pthread_t thread;
56 		pthread_attr_t threadAttr;
57 
58 		Memory::StackDesc stackDesc;
59 
60     size_t stackSize;
61 
62 		bool isStarted;
63 
64 		static void* ThreadFuncInternal(void *pThread)
65 		{
66 			Thread * self = (Thread *)pThread;
67 
68 			self->func(self->funcData);
69 
70 			return nullptr;
71 		}
72 
73 	public:
74 
75 		Thread()
76 			: stackSize(0)
77 			, isStarted(false)
78 		{
79 		}
80 
81 		void* GetStackBottom()
82 		{
83 			return stackDesc.stackBottom;
84 		}
85 
86 		size_t GetStackSize()
87 		{
88 			return stackSize;
89 		}
90 
91 
92 		void Start(size_t _stackSize, TThreadEntryPoint entryPoint, void *userData)
93 		{
94 			MT_ASSERT(!isStarted, "Thread already stared");
95 
96 			MT_ASSERT(func == nullptr, "Thread already started");
97 
98 			func = entryPoint;
99 			funcData = userData;
100 
101 			stackDesc = Memory::AllocStack(_stackSize);
102 			stackSize = stackDesc.GetStackSize();
103 
104 			MT_ASSERT(stackSize >= PTHREAD_STACK_MIN, "Thread stack to small");
105 
106 			int err = pthread_attr_init(&threadAttr);
107 			MT_ASSERT(err == 0, "pthread_attr_init - error");
108 
109 			err = pthread_attr_setstack(&threadAttr, stackDesc.stackBottom, stackSize);
110 			MT_ASSERT(err == 0, "pthread_attr_setstack - error");
111 
112 			err = pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_JOINABLE);
113 			MT_ASSERT(err == 0, "pthread_attr_setdetachstate - error");
114 
115 			isStarted = true;
116 
117 			err = pthread_create(&thread, &threadAttr, ThreadFuncInternal, this);
118 			MT_ASSERT(err == 0, "pthread_create - error");
119 		}
120 
121 		void Stop()
122 		{
123 			MT_ASSERT(isStarted, "Thread is not started");
124 
125 			if (func == nullptr)
126 			{
127 				return;
128 			}
129 
130 			void *threadStatus = nullptr;
131 			int err = pthread_join(thread, &threadStatus);
132 			MT_ASSERT(err == 0, "pthread_join - error");
133 
134 			err = pthread_attr_destroy(&threadAttr);
135 			MT_ASSERT(err == 0, "pthread_attr_destroy - error");
136 
137 			func = nullptr;
138 			funcData = nullptr;
139 
140 			if (stackDesc.stackMemory != nullptr)
141 			{
142 				Memory::FreeStack(stackDesc);
143 			}
144 
145 			stackSize = 0;
146 			isStarted = false;
147 		}
148 
149 		bool IsCurrentThread() const
150 		{
151 			if(!isStarted)
152 			{
153 				return false;
154 			}
155 
156 			pthread_t callThread = pthread_self();
157 			if (pthread_equal(callThread, thread))
158 			{
159 					return true;
160 			}
161 			return false;
162 		}
163 
164 		static int GetNumberOfHardwareThreads()
165 		{
166 #ifdef __APPLE_CC__
167             return std::thread::hardware_concurrency();
168 #else
169 			long numberOfProcessors = sysconf( _SC_NPROCESSORS_ONLN );
170 			return (int)numberOfProcessors;
171 #endif
172 		}
173 
174 		static void Sleep(uint32 milliseconds)
175 		{
176       struct timespec req;
177       time_t sec = (int)(milliseconds/1000);
178       milliseconds = milliseconds - (sec*1000);
179       req.tv_sec = sec;
180       req.tv_nsec = milliseconds * 1000000L;
181       while (nanosleep(&req,&req) == -1 )
182 			{
183 				continue;
184 			}
185 		}
186 
187 	};
188 
189 
190 }
191 
192 
193