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