blob: a42e62471c390fd569125d3f566fcf3e0147f9bb [file] [log] [blame]
Nicolas Capensc07dc4b2018-08-06 14:20:45 -04001// 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 rr_Thread_hpp
16#define rr_Thread_hpp
17
18#if defined(_WIN32)
Ben Clayton713b8d32019-12-17 20:37:56 +000019# ifndef WIN32_LEAN_AND_MEAN
20# define WIN32_LEAN_AND_MEAN
21# endif
22# include <windows.h>
23# include <intrin.h>
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040024#else
Ben Clayton713b8d32019-12-17 20:37:56 +000025# include <pthread.h>
26# include <sched.h>
27# include <unistd.h>
28# define TLS_OUT_OF_INDEXES (pthread_key_t)(~0)
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040029#endif
30
31#include <stdlib.h>
32
33#if defined(__clang__)
Ben Clayton713b8d32019-12-17 20:37:56 +000034# if __has_include(<atomic>) // clang has an explicit check for the availability of atomic
35# define USE_STD_ATOMIC 1
36# endif
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040037// atomic is available in C++11 or newer, and in Visual Studio 2012 or newer
Ben Clayton713b8d32019-12-17 20:37:56 +000038#elif(defined(_MSC_VER) && (_MSC_VER >= 1700)) || (__cplusplus >= 201103L)
39# define USE_STD_ATOMIC 1
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040040#endif
41
42#if USE_STD_ATOMIC
Ben Clayton713b8d32019-12-17 20:37:56 +000043# include <atomic>
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040044#endif
45
Nicolas Capens157ba262019-12-10 17:49:14 -050046namespace rr {
47
48class Event;
49
50class Thread
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040051{
Nicolas Capens157ba262019-12-10 17:49:14 -050052public:
53 Thread(void (*threadFunction)(void *parameters), void *parameters);
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040054
Nicolas Capens157ba262019-12-10 17:49:14 -050055 ~Thread();
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040056
Nicolas Capens157ba262019-12-10 17:49:14 -050057 void join();
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040058
Nicolas Capens157ba262019-12-10 17:49:14 -050059 static void yield();
60 static void sleep(int milliseconds);
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040061
Ben Clayton713b8d32019-12-17 20:37:56 +000062#if defined(_WIN32)
63 typedef DWORD LocalStorageKey;
64#else
65 typedef pthread_key_t LocalStorageKey;
66#endif
Nicolas Capensc07dc4b2018-08-06 14:20:45 -040067
Nicolas Capens157ba262019-12-10 17:49:14 -050068 static LocalStorageKey allocateLocalStorageKey(void (*destructor)(void *storage) = free);
69 static void freeLocalStorageKey(LocalStorageKey key);
70 static void *allocateLocalStorage(LocalStorageKey key, size_t size);
71 static void *getLocalStorage(LocalStorageKey key);
72 static void freeLocalStorage(LocalStorageKey key);
73
74private:
75 struct Entry
76 {
77 void (*const threadFunction)(void *parameters);
78 void *threadParameters;
79 Event *init;
80 };
81
Ben Clayton713b8d32019-12-17 20:37:56 +000082#if defined(_WIN32)
83 static unsigned long __stdcall startFunction(void *parameters);
84 HANDLE handle;
85#else
86 static void *startFunction(void *parameters);
87 pthread_t handle;
88#endif
Nicolas Capens157ba262019-12-10 17:49:14 -050089
90 bool hasJoined = false;
91};
92
93class Event
94{
95 friend class Thread;
96
97public:
98 Event();
99
100 ~Event();
101
102 void signal();
103 void wait();
104
105private:
Ben Clayton713b8d32019-12-17 20:37:56 +0000106#if defined(_WIN32)
107 HANDLE handle;
108#else
109 pthread_cond_t handle;
110 pthread_mutex_t mutex;
111 volatile bool signaled;
112#endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500113};
114
115#if PERF_PROFILE
116int64_t atomicExchange(int64_t volatile *target, int64_t value);
117int atomicExchange(int volatile *target, int value);
118#endif
119
120int atomicIncrement(int volatile *value);
121int atomicDecrement(int volatile *value);
122int atomicAdd(int volatile *target, int value);
123void nop();
124
125} // namespace rr
126
127/* Inline implementation */
128
129namespace rr {
130
131inline void Thread::yield()
132{
Ben Clayton713b8d32019-12-17 20:37:56 +0000133#if defined(_WIN32)
134 Sleep(0);
135#elif defined(__APPLE__)
136 pthread_yield_np();
137#else
138 sched_yield();
139#endif
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400140}
141
Nicolas Capens157ba262019-12-10 17:49:14 -0500142inline void Thread::sleep(int milliseconds)
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400143{
Ben Clayton713b8d32019-12-17 20:37:56 +0000144#if defined(_WIN32)
145 Sleep(milliseconds);
146#else
147 usleep(1000 * milliseconds);
148#endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500149}
150
151inline Thread::LocalStorageKey Thread::allocateLocalStorageKey(void (*destructor)(void *storage))
152{
Ben Clayton713b8d32019-12-17 20:37:56 +0000153#if defined(_WIN32)
154 return TlsAlloc();
155#else
156 LocalStorageKey key;
157 pthread_key_create(&key, destructor);
158 return key;
159#endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500160}
161
162inline void Thread::freeLocalStorageKey(LocalStorageKey key)
163{
Ben Clayton713b8d32019-12-17 20:37:56 +0000164#if defined(_WIN32)
165 TlsFree(key);
166#else
167 pthread_key_delete(key); // Using an invalid key is an error but not undefined behavior.
168#endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500169}
170
171inline void *Thread::allocateLocalStorage(LocalStorageKey key, size_t size)
172{
173 if(key == TLS_OUT_OF_INDEXES)
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400174 {
Nicolas Capens157ba262019-12-10 17:49:14 -0500175 return nullptr;
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400176 }
177
Nicolas Capens157ba262019-12-10 17:49:14 -0500178 freeLocalStorage(key);
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400179
Nicolas Capens157ba262019-12-10 17:49:14 -0500180 void *storage = malloc(size);
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400181
Ben Clayton713b8d32019-12-17 20:37:56 +0000182#if defined(_WIN32)
183 TlsSetValue(key, storage);
184#else
185 pthread_setspecific(key, storage);
186#endif
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400187
Nicolas Capens157ba262019-12-10 17:49:14 -0500188 return storage;
189}
190
191inline void *Thread::getLocalStorage(LocalStorageKey key)
192{
Ben Clayton713b8d32019-12-17 20:37:56 +0000193#if defined(_WIN32)
194 return TlsGetValue(key);
195#else
196 if(key == TLS_OUT_OF_INDEXES) // Avoid undefined behavior.
197 {
198 return nullptr;
199 }
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400200
Ben Clayton713b8d32019-12-17 20:37:56 +0000201 return pthread_getspecific(key);
202#endif
Nicolas Capensc07dc4b2018-08-06 14:20:45 -0400203}
204
Nicolas Capens157ba262019-12-10 17:49:14 -0500205inline void Thread::freeLocalStorage(LocalStorageKey key)
206{
207 free(getLocalStorage(key));
208
Ben Clayton713b8d32019-12-17 20:37:56 +0000209#if defined(_WIN32)
210 TlsSetValue(key, nullptr);
211#else
212 pthread_setspecific(key, nullptr);
213#endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500214}
215
216inline void Event::signal()
217{
Ben Clayton713b8d32019-12-17 20:37:56 +0000218#if defined(_WIN32)
219 SetEvent(handle);
220#else
221 pthread_mutex_lock(&mutex);
222 signaled = true;
223 pthread_cond_signal(&handle);
224 pthread_mutex_unlock(&mutex);
225#endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500226}
227
228inline void Event::wait()
229{
Ben Clayton713b8d32019-12-17 20:37:56 +0000230#if defined(_WIN32)
231 WaitForSingleObject(handle, INFINITE);
232#else
233 pthread_mutex_lock(&mutex);
234 while(!signaled) pthread_cond_wait(&handle, &mutex);
235 signaled = false;
236 pthread_mutex_unlock(&mutex);
237#endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500238}
239
240#if PERF_PROFILE
241inline int64_t atomicExchange(volatile int64_t *target, int64_t value)
242{
Ben Clayton713b8d32019-12-17 20:37:56 +0000243# if defined(_WIN32)
244 return InterlockedExchange64(target, value);
245# else
246 int ret;
247 __asm__ __volatile__("lock; xchg8 %x0,(%x1)"
248 : "=r"(ret)
249 : "r"(target), "0"(value)
250 : "memory");
251 return ret;
252# endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500253}
254
255inline int atomicExchange(volatile int *target, int value)
256{
Ben Clayton713b8d32019-12-17 20:37:56 +0000257# if defined(_WIN32)
258 return InterlockedExchange((volatile long *)target, (long)value);
259# else
260 int ret;
261 __asm__ __volatile__("lock; xchgl %x0,(%x1)"
262 : "=r"(ret)
263 : "r"(target), "0"(value)
264 : "memory");
265 return ret;
266# endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500267}
268#endif
269
270inline int atomicIncrement(volatile int *value)
271{
Ben Clayton713b8d32019-12-17 20:37:56 +0000272#if defined(_WIN32)
273 return InterlockedIncrement((volatile long *)value);
274#else
275 return __sync_add_and_fetch(value, 1);
276#endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500277}
278
279inline int atomicDecrement(volatile int *value)
280{
Ben Clayton713b8d32019-12-17 20:37:56 +0000281#if defined(_WIN32)
282 return InterlockedDecrement((volatile long *)value);
283#else
284 return __sync_sub_and_fetch(value, 1);
285#endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500286}
287
Ben Clayton713b8d32019-12-17 20:37:56 +0000288inline int atomicAdd(volatile int *target, int value)
Nicolas Capens157ba262019-12-10 17:49:14 -0500289{
Ben Clayton713b8d32019-12-17 20:37:56 +0000290#if defined(_WIN32)
291 return InterlockedExchangeAdd((volatile long *)target, value) + value;
292#else
293 return __sync_add_and_fetch(target, value);
294#endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500295}
296
297inline void nop()
298{
Ben Clayton713b8d32019-12-17 20:37:56 +0000299#if defined(_WIN32)
300 __nop();
301#else
302 __asm__ __volatile__("nop");
303#endif
Nicolas Capens157ba262019-12-10 17:49:14 -0500304}
305
306#if USE_STD_ATOMIC
Ben Clayton713b8d32019-12-17 20:37:56 +0000307class AtomicInt
308{
309public:
310 AtomicInt()
311 : ai()
312 {}
313 AtomicInt(int i)
314 : ai(i)
315 {}
Nicolas Capens157ba262019-12-10 17:49:14 -0500316
Ben Clayton713b8d32019-12-17 20:37:56 +0000317 inline operator int() const { return ai.load(std::memory_order_acquire); }
318 inline void operator=(const AtomicInt &i) { ai.store(i.ai.load(std::memory_order_acquire), std::memory_order_release); }
319 inline void operator=(int i) { ai.store(i, std::memory_order_release); }
320 inline void operator--() { ai.fetch_sub(1, std::memory_order_acq_rel); }
321 inline void operator++() { ai.fetch_add(1, std::memory_order_acq_rel); }
322 inline int operator--(int) { return ai.fetch_sub(1, std::memory_order_acq_rel) - 1; }
323 inline int operator++(int) { return ai.fetch_add(1, std::memory_order_acq_rel) + 1; }
324 inline void operator-=(int i) { ai.fetch_sub(i, std::memory_order_acq_rel); }
325 inline void operator+=(int i) { ai.fetch_add(i, std::memory_order_acq_rel); }
326
327private:
328 std::atomic<int> ai;
329};
Nicolas Capens157ba262019-12-10 17:49:14 -0500330#else
Ben Clayton713b8d32019-12-17 20:37:56 +0000331class AtomicInt
332{
333public:
334 AtomicInt() {}
335 AtomicInt(int i)
336 : vi(i)
337 {}
Nicolas Capens157ba262019-12-10 17:49:14 -0500338
Ben Clayton713b8d32019-12-17 20:37:56 +0000339 inline operator int() const { return vi; } // Note: this isn't a guaranteed atomic operation
340 inline void operator=(const AtomicInt &i) { atomicExchange(&vi, i.vi); }
341 inline void operator=(int i) { atomicExchange(&vi, i); }
342 inline void operator--() { atomicDecrement(&vi); }
343 inline void operator++() { atomicIncrement(&vi); }
344 inline int operator--(int) { return atomicDecrement(&vi); }
345 inline int operator++(int) { return atomicIncrement(&vi); }
346 inline void operator-=(int i) { atomicAdd(&vi, -i); }
347 inline void operator+=(int i) { atomicAdd(&vi, i); }
348
349private:
350 volatile int vi;
351};
Nicolas Capens157ba262019-12-10 17:49:14 -0500352#endif
353
354} // namespace rr
355
Ben Clayton713b8d32019-12-17 20:37:56 +0000356#endif // rr_Thread_hpp