]> git.cworth.org Git - apitrace/blob - common/os_thread.hpp
os: Fallback to OS TLS when compiler does not support it (issue #120).
[apitrace] / common / os_thread.hpp
1 /**************************************************************************
2  *
3  * Copyright 2011-2012 Jose Fonseca
4  * All Rights Reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  *
24  **************************************************************************/
25
26 /*
27  * OS native thread abstraction.
28  *
29  * Mimics C++11 threads.
30  */
31
32 #ifndef _OS_THREAD_HPP_
33 #define _OS_THREAD_HPP_
34
35
36 #ifdef _WIN32
37 #include <windows.h>
38 #else
39 #include <pthread.h>
40 #endif
41
42
43 /*
44  * These features are not supported on Windows XP
45  */
46 #define USE_WIN32_DECLSPEC_THREAD 0
47 #define USE_WIN32_CONDITION_VARIABLES 0
48
49
50 /**
51  * Compiler TLS.
52  *
53  * See also:
54  * - http://gcc.gnu.org/onlinedocs/gcc-4.6.3/gcc/Thread_002dLocal.html
55  * - http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx
56  */
57 #if !defined(_WIN32) || USE_WIN32_DECLSPEC_THREAD
58 #  if defined(_MSC_VER)
59 #    define OS_THREAD_SPECIFIC_PTR(_type) __declspec(thread) _type *
60 #  elif defined(__GNUC__)
61 #    define OS_THREAD_SPECIFIC_PTR(_type) __thread _type *
62 #  endif
63 #endif
64 #if !defined(OS_THREAD_SPECIFIC_PTR)
65 #  define OS_THREAD_SPECIFIC_PTR(_type) os::thread_specific_ptr< _type >
66 #endif
67
68
69 namespace os {
70
71
72     /**
73      * Base class for mutex and recursive_mutex.
74      */
75     class _base_mutex
76     {
77     public:
78 #ifdef _WIN32
79         typedef CRITICAL_SECTION native_handle_type;
80 #else
81         typedef pthread_mutex_t native_handle_type;
82 #endif
83
84         _base_mutex(void) {
85 #ifdef _WIN32
86             InitializeCriticalSection(&_native_handle);
87 #else
88             pthread_mutexattr_t attr;
89             pthread_mutexattr_init(&attr);
90             pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
91             pthread_mutex_init(&_native_handle, &attr);
92             pthread_mutexattr_destroy(&attr);
93 #endif
94         }
95
96         ~_base_mutex() {
97 #ifdef _WIN32
98             DeleteCriticalSection(&_native_handle);
99 #else
100             pthread_mutex_destroy(&_native_handle);
101 #endif
102         }
103
104         inline void
105         lock(void) {
106 #ifdef _WIN32
107             EnterCriticalSection(&_native_handle);
108 #else
109             pthread_mutex_lock(&_native_handle);
110 #endif
111         }
112
113         inline void
114         unlock(void) {
115 #ifdef _WIN32
116             LeaveCriticalSection(&_native_handle);
117 #else
118             pthread_mutex_unlock(&_native_handle);
119 #endif
120         }
121
122         native_handle_type & native_handle() {
123             return _native_handle;
124         }
125
126     protected:
127         native_handle_type _native_handle;
128     };
129
130
131     /**
132      * Same interface as std::mutex.
133      */
134     class mutex : public _base_mutex
135     {
136     public:
137         inline
138         mutex(void) {
139 #ifdef _WIN32
140             InitializeCriticalSection(&_native_handle);
141 #else
142             pthread_mutex_init(&_native_handle, NULL);
143 #endif
144         }
145     };
146
147
148     /**
149      * Same interface as std::recursive_mutex.
150      */
151     class recursive_mutex : public _base_mutex
152     {
153     public:
154         inline
155         recursive_mutex(void) {
156 #ifdef _WIN32
157             InitializeCriticalSection(&_native_handle);
158 #else
159             pthread_mutexattr_t attr;
160             pthread_mutexattr_init(&attr);
161             pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
162             pthread_mutex_init(&_native_handle, &attr);
163             pthread_mutexattr_destroy(&attr);
164 #endif
165         }
166     };
167
168
169     /**
170      * Same interface as std::unique_lock;
171      */
172     template< class Mutex >
173     class unique_lock
174     {
175     public:
176         typedef Mutex mutex_type;
177
178         inline explicit
179         unique_lock(mutex_type & mutex) :
180             _mutex(&mutex)
181         {
182             _mutex->lock();
183         }
184
185         inline
186         ~unique_lock() {
187             _mutex->unlock();
188         }
189
190         inline void
191         lock() {
192             _mutex->lock();
193         }
194
195         inline void
196         unlock() {
197             _mutex->unlock();
198         }
199
200         mutex_type *
201         mutex() const {
202             return _mutex;
203         }
204
205     protected:
206         mutex_type *_mutex;
207     };
208
209
210     /**
211      * Same interface as std::condition_variable
212      */
213     class condition_variable
214     {
215     private:
216 #ifdef _WIN32
217 #  if USE_WIN32_CONDITION_VARIABLES
218         // XXX: Only supported on Vista an higher. Not yet supported by WINE.
219         typedef CONDITION_VARIABLE native_handle_type;
220         native_handle_type _native_handle;
221 #else
222         // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
223         LONG cWaiters;
224         HANDLE hEvent;
225 #endif
226 #else
227         typedef pthread_cond_t native_handle_type;
228         native_handle_type _native_handle;
229 #endif
230
231     public:
232         condition_variable() {
233 #ifdef _WIN32
234 #  if USE_WIN32_CONDITION_VARIABLES
235             InitializeConditionVariable(&_native_handle);
236 #  else
237             cWaiters = 0;
238             hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
239 #  endif
240 #else
241             pthread_cond_init(&_native_handle, NULL);
242 #endif
243         }
244
245         ~condition_variable() {
246 #ifdef _WIN32
247 #  if USE_WIN32_CONDITION_VARIABLES
248             /* No-op */
249 #  else
250             CloseHandle(hEvent);
251 #  endif
252 #else
253             pthread_cond_destroy(&_native_handle);
254 #endif
255         }
256
257         inline void
258         signal(void) {
259 #ifdef _WIN32
260 #  if USE_WIN32_CONDITION_VARIABLES
261             WakeConditionVariable(&_native_handle);
262 #  else
263             if (cWaiters) {
264                 SetEvent(hEvent);
265             }
266 #  endif
267 #else
268             pthread_cond_signal(&_native_handle);
269 #endif
270         }
271
272         inline void
273         wait(unique_lock<mutex> & lock) {
274             mutex::native_handle_type & mutex_native_handle = lock.mutex()->native_handle();
275 #ifdef _WIN32
276 #  if USE_WIN32_CONDITION_VARIABLES
277             SleepConditionVariableCS(&_native_handle, &mutex_native_handle, INFINITE);
278 #  else
279             InterlockedIncrement(&cWaiters);
280             LeaveCriticalSection(&mutex_native_handle);
281             WaitForSingleObject(hEvent, INFINITE);
282             EnterCriticalSection(&mutex_native_handle);
283             InterlockedDecrement(&cWaiters);
284 #  endif
285 #else
286             pthread_cond_wait(&_native_handle, &mutex_native_handle);
287 #endif
288         }
289     };
290
291
292     template <typename T>
293     class thread_specific_ptr
294     {
295     private:
296 #ifdef _WIN32
297         DWORD dwTlsIndex;
298 #else
299         pthread_key_t key;
300 #endif
301
302     public:
303         thread_specific_ptr(void) {
304 #ifdef _WIN32
305             dwTlsIndex = TlsAlloc();
306 #else
307             pthread_key_create(&key, NULL);
308 #endif
309         }
310
311         ~thread_specific_ptr() {
312 #ifdef _WIN32
313             TlsFree(dwTlsIndex);
314 #else
315             pthread_key_delete(key);
316 #endif
317         }
318
319         inline T *
320         get(void) const {
321             void *ptr;
322 #ifdef _WIN32
323             ptr = TlsGetValue(dwTlsIndex);
324 #else
325             ptr = pthread_getspecific(key);
326 #endif
327             return static_cast<T*>(ptr);
328         }
329
330         inline
331         operator T * (void) const
332         {
333             return get();
334         }
335
336         inline T *
337         operator -> (void) const
338         {
339             return get();
340         }
341
342         inline T *
343         operator = (T * new_value)
344         {
345             set(new_value);
346             return new_value;
347         }
348
349         inline void
350         set(T* new_value) {
351 #ifdef _WIN32
352             TlsSetValue(dwTlsIndex, new_value);
353 #else
354             pthread_setspecific(key, new_value);
355 #endif
356         }
357     };
358
359
360     /**
361      * Same interface as std::thread
362      */
363     class thread {
364     public:
365 #ifdef _WIN32
366         typedef HANDLE native_handle_type;
367 #else
368         typedef pthread_t native_handle_type;
369 #endif
370
371         inline
372         thread() :
373             _native_handle(0)
374         {
375         }
376
377         inline
378         thread(const thread &other) :
379             _native_handle(other._native_handle)
380         {
381         }
382
383         template< class Function, class Arg >
384         explicit thread( Function& f, Arg arg ) {
385 #ifdef _WIN32
386             DWORD id = 0;
387             _native_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, (LPVOID)arg, 0, &id);
388 #else
389             pthread_create(&_native_handle, NULL, (void *(*) (void *))f, (void *)arg);
390 #endif
391         }
392
393         inline bool
394         joinable(void) const {
395             return _native_handle != 0;
396         }
397
398         inline void
399         join() {
400 #ifdef _WIN32
401             WaitForSingleObject(_native_handle, INFINITE);
402 #else
403             pthread_join(_native_handle, NULL);
404 #endif
405         }
406
407     private:
408         native_handle_type _native_handle;
409
410 #if 0
411 #ifdef _WIN32
412         template< class Function, class Arg >
413         static DWORD WINAPI
414         ThreadProc(LPVOID lpParameter) {
415
416         );
417 #endif
418 #endif
419     };
420
421 } /* namespace os */
422
423 #endif /* _OS_THREAD_HPP_ */