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 (~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, 0); 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); 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 pthread_setspecific(key, value); 158 #endif 159 } 160 getLocalStorage(LocalStorageKey key)161 inline void *Thread::getLocalStorage(LocalStorageKey key) 162 { 163 #if defined(_WIN32) 164 return TlsGetValue(key); 165 #else 166 return pthread_getspecific(key); 167 #endif 168 } 169 signal()170 inline void Event::signal() 171 { 172 #if defined(_WIN32) 173 SetEvent(handle); 174 #else 175 pthread_mutex_lock(&mutex); 176 signaled = true; 177 pthread_cond_signal(&handle); 178 pthread_mutex_unlock(&mutex); 179 #endif 180 } 181 wait()182 inline void Event::wait() 183 { 184 #if defined(_WIN32) 185 WaitForSingleObject(handle, INFINITE); 186 #else 187 pthread_mutex_lock(&mutex); 188 while(!signaled) pthread_cond_wait(&handle, &mutex); 189 signaled = false; 190 pthread_mutex_unlock(&mutex); 191 #endif 192 } 193 194 #if PERF_PROFILE atomicExchange(volatile int64_t * target,int64_t value)195 inline int64_t atomicExchange(volatile int64_t *target, int64_t value) 196 { 197 #if defined(_WIN32) 198 return InterlockedExchange64(target, value); 199 #else 200 int ret; 201 __asm__ __volatile__("lock; xchg8 %0,(%1)" : "=r" (ret) :"r" (target), "0" (value) : "memory" ); 202 return ret; 203 #endif 204 } 205 #endif 206 atomicExchange(volatile int * target,int value)207 inline int atomicExchange(volatile int *target, int value) 208 { 209 #if defined(_WIN32) 210 return InterlockedExchange((volatile long*)target, (long)value); 211 #else 212 int ret; 213 __asm__ __volatile__("lock; xchgl %0,(%1)" : "=r" (ret) :"r" (target), "0" (value) : "memory" ); 214 return ret; 215 #endif 216 } 217 atomicIncrement(volatile int * value)218 inline int atomicIncrement(volatile int *value) 219 { 220 #if defined(_WIN32) 221 return InterlockedIncrement((volatile long*)value); 222 #else 223 return __sync_add_and_fetch(value, 1); 224 #endif 225 } 226 atomicDecrement(volatile int * value)227 inline int atomicDecrement(volatile int *value) 228 { 229 #if defined(_WIN32) 230 return InterlockedDecrement((volatile long*)value); 231 #else 232 return __sync_sub_and_fetch(value, 1); 233 #endif 234 } 235 atomicAdd(volatile int * target,int value)236 inline int atomicAdd(volatile int* target, int value) 237 { 238 #if defined(_MSC_VER) 239 return InterlockedExchangeAdd((volatile long*)target, value) + value; 240 #else 241 return __sync_add_and_fetch(target, value); 242 #endif 243 } 244 nop()245 inline void nop() 246 { 247 #if defined(_WIN32) 248 __nop(); 249 #else 250 __asm__ __volatile__ ("nop"); 251 #endif 252 } 253 } 254 255 #endif // sw_Thread_hpp 256