• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 The SwiftShader Authors. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //    http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef sw_Thread_hpp
16 #define sw_Thread_hpp
17 
18 #if defined(_WIN32)
19 	#ifndef WIN32_LEAN_AND_MEAN
20 		#define WIN32_LEAN_AND_MEAN
21 	#endif
22 	#include <windows.h>
23 	#include <intrin.h>
24 #else
25 	#include <pthread.h>
26 	#include <sched.h>
27 	#include <unistd.h>
28 	#define TLS_OUT_OF_INDEXES (pthread_key_t)(~0)
29 #endif
30 
31 namespace sw
32 {
33 	class Event;
34 
35 	class Thread
36 	{
37 	public:
38 		Thread(void (*threadFunction)(void *parameters), void *parameters);
39 
40 		~Thread();
41 
42 		void join();
43 
44 		static void yield();
45 		static void sleep(int milliseconds);
46 
47 		#if defined(_WIN32)
48 			typedef DWORD LocalStorageKey;
49 		#else
50 			typedef pthread_key_t LocalStorageKey;
51 		#endif
52 
53 		static LocalStorageKey allocateLocalStorageKey();
54 		static void freeLocalStorageKey(LocalStorageKey key);
55 		static void setLocalStorage(LocalStorageKey key, void *value);
56 		static void *getLocalStorage(LocalStorageKey key);
57 
58 	private:
59 		struct Entry
60 		{
61 			void (*const threadFunction)(void *parameters);
62 			void *threadParameters;
63 			Event *init;
64 		};
65 
66 		#if defined(_WIN32)
67 			static unsigned long __stdcall startFunction(void *parameters);
68 			HANDLE handle;
69 		#else
70 			static void *startFunction(void *parameters);
71 			pthread_t handle;
72 		#endif
73 
74 		bool hasJoined = false;
75 	};
76 
77 	class Event
78 	{
79 		friend class Thread;
80 
81 	public:
82 		Event();
83 
84 		~Event();
85 
86 		void signal();
87 		void wait();
88 
89 	private:
90 		#if defined(_WIN32)
91 			HANDLE handle;
92 		#else
93 			pthread_cond_t handle;
94 			pthread_mutex_t mutex;
95 			volatile bool signaled;
96 		#endif
97 	};
98 
99 	#if PERF_PROFILE
100 	int64_t atomicExchange(int64_t volatile *target, int64_t value);
101 	#endif
102 
103 	int atomicExchange(int volatile *target, int value);
104 	int atomicIncrement(int volatile *value);
105 	int atomicDecrement(int volatile *value);
106 	int atomicAdd(int volatile *target, int value);
107 	void nop();
108 }
109 
110 namespace sw
111 {
yield()112 	inline void Thread::yield()
113 	{
114 		#if defined(_WIN32)
115 			Sleep(0);
116 		#elif defined(__APPLE__)
117 			pthread_yield_np();
118 		#else
119 			sched_yield();
120 		#endif
121 	}
122 
sleep(int milliseconds)123 	inline void Thread::sleep(int milliseconds)
124 	{
125 		#if defined(_WIN32)
126 			Sleep(milliseconds);
127 		#else
128 			usleep(1000 * milliseconds);
129 		#endif
130 	}
131 
allocateLocalStorageKey()132 	inline Thread::LocalStorageKey Thread::allocateLocalStorageKey()
133 	{
134 		#if defined(_WIN32)
135 			return TlsAlloc();
136 		#else
137 			LocalStorageKey key;
138 			pthread_key_create(&key, NULL);
139 			return key;
140 		#endif
141 	}
142 
freeLocalStorageKey(LocalStorageKey key)143 	inline void Thread::freeLocalStorageKey(LocalStorageKey key)
144 	{
145 		#if defined(_WIN32)
146 			TlsFree(key);
147 		#else
148 			pthread_key_delete(key);   // Using an invalid key is an error but not undefined behavior.
149 		#endif
150 	}
151 
setLocalStorage(LocalStorageKey key,void * value)152 	inline void Thread::setLocalStorage(LocalStorageKey key, void *value)
153 	{
154 		#if defined(_WIN32)
155 			TlsSetValue(key, value);
156 		#else
157 			if(key != TLS_OUT_OF_INDEXES)   // Avoid undefined behavior.
158 			{
159 				pthread_setspecific(key, value);
160 			}
161 		#endif
162 	}
163 
getLocalStorage(LocalStorageKey key)164 	inline void *Thread::getLocalStorage(LocalStorageKey key)
165 	{
166 		#if defined(_WIN32)
167 			return TlsGetValue(key);
168 		#else
169 			if(key == TLS_OUT_OF_INDEXES)   // Avoid undefined behavior.
170 			{
171 				return nullptr;
172 			}
173 
174 			return pthread_getspecific(key);
175 		#endif
176 	}
177 
signal()178 	inline void Event::signal()
179 	{
180 		#if defined(_WIN32)
181 			SetEvent(handle);
182 		#else
183 			pthread_mutex_lock(&mutex);
184 			signaled = true;
185 			pthread_cond_signal(&handle);
186 			pthread_mutex_unlock(&mutex);
187 		#endif
188 	}
189 
wait()190 	inline void Event::wait()
191 	{
192 		#if defined(_WIN32)
193 			WaitForSingleObject(handle, INFINITE);
194 		#else
195 			pthread_mutex_lock(&mutex);
196 			while(!signaled) pthread_cond_wait(&handle, &mutex);
197 			signaled = false;
198 			pthread_mutex_unlock(&mutex);
199 		#endif
200 	}
201 
202 	#if PERF_PROFILE
atomicExchange(volatile int64_t * target,int64_t value)203 	inline int64_t atomicExchange(volatile int64_t *target, int64_t value)
204 	{
205 		#if defined(_WIN32)
206 			return InterlockedExchange64(target, value);
207 		#else
208 			int ret;
209 			__asm__ __volatile__("lock; xchg8 %0,(%1)" : "=r" (ret) :"r" (target), "0" (value) : "memory" );
210 			return ret;
211 		#endif
212 	}
213 	#endif
214 
atomicExchange(volatile int * target,int value)215 	inline int atomicExchange(volatile int *target, int value)
216 	{
217 		#if defined(_WIN32)
218 			return InterlockedExchange((volatile long*)target, (long)value);
219 		#else
220 			int ret;
221 			__asm__ __volatile__("lock; xchgl %0,(%1)" : "=r" (ret) :"r" (target), "0" (value) : "memory" );
222 			return ret;
223 		#endif
224 	}
225 
atomicIncrement(volatile int * value)226 	inline int atomicIncrement(volatile int *value)
227 	{
228 		#if defined(_WIN32)
229 			return InterlockedIncrement((volatile long*)value);
230 		#else
231 			return __sync_add_and_fetch(value, 1);
232 		#endif
233 	}
234 
atomicDecrement(volatile int * value)235 	inline int atomicDecrement(volatile int *value)
236 	{
237 		#if defined(_WIN32)
238 			return InterlockedDecrement((volatile long*)value);
239 		#else
240 			return __sync_sub_and_fetch(value, 1);
241 		#endif
242 	}
243 
atomicAdd(volatile int * target,int value)244 	inline int atomicAdd(volatile int* target, int value)
245 	{
246 		#if defined(_MSC_VER)
247 			return InterlockedExchangeAdd((volatile long*)target, value) + value;
248 		#else
249 			return __sync_add_and_fetch(target, value);
250 		#endif
251 	}
252 
nop()253 	inline void nop()
254 	{
255 		#if defined(_WIN32)
256 			__nop();
257 		#else
258 			__asm__ __volatile__ ("nop");
259 		#endif
260 	}
261 }
262 
263 #endif   // sw_Thread_hpp
264