]> git.cworth.org Git - apitrace/blob - common/os_thread.hpp
Revert "Remove os::thread_specific_ptr"
[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 / boost 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 #define USE_WIN32_CONDITION_VARIABLES 0
44
45
46 /**
47  * Compiler TLS.
48  *
49  * See also:
50  * - http://gcc.gnu.org/onlinedocs/gcc-4.6.3/gcc/Thread_002dLocal.html
51  * - http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx
52  */
53 #if defined(_MSC_VER)
54 #  define thread_specific __declspec(thread)
55 #elif defined(__GNUC__)
56 #  define thread_specific __thread
57 #else
58 #  define thread_specific
59 #  error "Unsupported compiler"
60 #endif
61
62
63 namespace os {
64
65
66     /**
67      * Base class for mutex and recursive_mutex.
68      */
69     class _base_mutex
70     {
71     public:
72 #ifdef _WIN32
73         typedef CRITICAL_SECTION native_handle_type;
74 #else
75         typedef pthread_mutex_t native_handle_type;
76 #endif
77
78         _base_mutex(void) {
79 #ifdef _WIN32
80             InitializeCriticalSection(&_native_handle);
81 #else
82             pthread_mutexattr_t attr;
83             pthread_mutexattr_init(&attr);
84             pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
85             pthread_mutex_init(&_native_handle, &attr);
86             pthread_mutexattr_destroy(&attr);
87 #endif
88         }
89
90         ~_base_mutex() {
91 #ifdef _WIN32
92             DeleteCriticalSection(&_native_handle);
93 #else
94             pthread_mutex_destroy(&_native_handle);
95 #endif
96         }
97
98         inline void
99         lock(void) {
100 #ifdef _WIN32
101             EnterCriticalSection(&_native_handle);
102 #else
103             pthread_mutex_lock(&_native_handle);
104 #endif
105         }
106
107         inline void
108         unlock(void) {
109 #ifdef _WIN32
110             LeaveCriticalSection(&_native_handle);
111 #else
112             pthread_mutex_unlock(&_native_handle);
113 #endif
114         }
115
116         native_handle_type & native_handle() {
117             return _native_handle;
118         }
119
120     protected:
121         native_handle_type _native_handle;
122     };
123
124
125     /**
126      * Same interface as std::mutex.
127      */
128     class mutex : public _base_mutex
129     {
130     public:
131         inline
132         mutex(void) {
133 #ifdef _WIN32
134             InitializeCriticalSection(&_native_handle);
135 #else
136             pthread_mutex_init(&_native_handle, NULL);
137 #endif
138         }
139     };
140
141
142     /**
143      * Same interface as std::recursive_mutex.
144      */
145     class recursive_mutex : public _base_mutex
146     {
147     public:
148         inline
149         recursive_mutex(void) {
150 #ifdef _WIN32
151             InitializeCriticalSection(&_native_handle);
152 #else
153             pthread_mutexattr_t attr;
154             pthread_mutexattr_init(&attr);
155             pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
156             pthread_mutex_init(&_native_handle, &attr);
157             pthread_mutexattr_destroy(&attr);
158 #endif
159         }
160     };
161
162
163     /**
164      * Same interface as std::unique_lock;
165      */
166     template< class Mutex >
167     class unique_lock
168     {
169     public:
170         typedef Mutex mutex_type;
171
172         inline explicit
173         unique_lock(mutex_type & mutex) :
174             _mutex(&mutex)
175         {
176             _mutex->lock();
177         }
178
179         inline
180         ~unique_lock() {
181             _mutex->unlock();
182         }
183
184         inline void
185         lock() {
186             _mutex->lock();
187         }
188
189         inline void
190         unlock() {
191             _mutex->unlock();
192         }
193
194         mutex_type *
195         mutex() const {
196             return _mutex;
197         }
198
199     protected:
200         mutex_type *_mutex;
201     };
202
203
204     /**
205      * Same interface as std::condition_variable
206      */
207     class condition_variable
208     {
209     private:
210 #ifdef _WIN32
211 #  if USE_WIN32_CONDITION_VARIABLES
212         // XXX: Only supported on Vista an higher. Not yet supported by WINE.
213         typedef CONDITION_VARIABLE native_handle_type;
214         native_handle_type _native_handle;
215 #else
216         // http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
217         LONG cWaiters;
218         HANDLE hEvent;
219 #endif
220 #else
221         typedef pthread_cond_t native_handle_type;
222         native_handle_type _native_handle;
223 #endif
224
225     public:
226         condition_variable() {
227 #ifdef _WIN32
228 #  if USE_WIN32_CONDITION_VARIABLES
229             InitializeConditionVariable(&_native_handle);
230 #  else
231             cWaiters = 0;
232             hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
233 #  endif
234 #else
235             pthread_cond_init(&_native_handle, NULL);
236 #endif
237         }
238
239         ~condition_variable() {
240 #ifdef _WIN32
241 #  if USE_WIN32_CONDITION_VARIABLES
242             /* No-op */
243 #  else
244             CloseHandle(hEvent);
245 #  endif
246 #else
247             pthread_cond_destroy(&_native_handle);
248 #endif
249         }
250
251         inline void
252         signal(void) {
253 #ifdef _WIN32
254 #  if USE_WIN32_CONDITION_VARIABLES
255             WakeConditionVariable(&_native_handle);
256 #  else
257             if (cWaiters) {
258                 SetEvent(hEvent);
259             }
260 #  endif
261 #else
262             pthread_cond_signal(&_native_handle);
263 #endif
264         }
265
266         inline void
267         wait(unique_lock<mutex> & lock) {
268             mutex::native_handle_type & mutex_native_handle = lock.mutex()->native_handle();
269 #ifdef _WIN32
270 #  if USE_WIN32_CONDITION_VARIABLES
271             SleepConditionVariableCS(&_native_handle, &mutex_native_handle, INFINITE);
272 #  else
273             InterlockedIncrement(&cWaiters);
274             LeaveCriticalSection(&mutex_native_handle);
275             WaitForSingleObject(hEvent, INFINITE);
276             EnterCriticalSection(&mutex_native_handle);
277             InterlockedDecrement(&cWaiters);
278 #  endif
279 #else
280             pthread_cond_wait(&_native_handle, &mutex_native_handle);
281 #endif
282         }
283     };
284
285
286     /**
287      * Same interface as boost::thread_specific_ptr.
288      */
289     template <typename T>
290     class thread_specific_ptr
291     {
292     private:
293 #ifdef _WIN32
294         DWORD dwTlsIndex;
295 #else
296         pthread_key_t key;
297
298         static void destructor(void *ptr) {
299             delete static_cast<T *>(ptr);
300         }
301 #endif
302
303     public:
304         thread_specific_ptr(void) {
305 #ifdef _WIN32
306             dwTlsIndex = TlsAlloc();
307 #else
308             pthread_key_create(&key, &destructor);
309 #endif
310         }
311
312         ~thread_specific_ptr() {
313 #ifdef _WIN32
314             TlsFree(dwTlsIndex);
315 #else
316             pthread_key_delete(key);
317 #endif
318         }
319
320         T* 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         T* operator -> (void) const
331         {
332             return get();
333         }
334
335         T& operator * (void) const
336         {
337             return *get();
338         }
339
340         void reset(T* new_value=0) {
341             T * old_value = get();
342             set(new_value);
343             if (old_value) {
344                 delete old_value;
345             }
346         }
347
348         T* release (void) {
349             T * old_value = get();
350             set(0);
351             return old_value;
352         }
353
354 private:
355         void set(T* new_value) {
356 #ifdef _WIN32
357             TlsSetValue(dwTlsIndex, new_value);
358 #else
359             pthread_setspecific(key, new_value);
360 #endif
361         }
362     };
363
364
365     /**
366      * Same interface as std::thread
367      */
368     class thread {
369     public:
370 #ifdef _WIN32
371         typedef HANDLE native_handle_type;
372 #else
373         typedef pthread_t native_handle_type;
374 #endif
375
376         inline
377         thread() :
378             _native_handle(0)
379         {
380         }
381
382         inline
383         thread(const thread &other) :
384             _native_handle(other._native_handle)
385         {
386         }
387
388         template< class Function, class Arg >
389         explicit thread( Function& f, Arg arg ) {
390 #ifdef _WIN32
391             DWORD id = 0;
392             _native_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, (LPVOID)arg, 0, &id);
393 #else
394             pthread_create(&_native_handle, NULL, (void *(*) (void *))f, (void *)arg);
395 #endif
396         }
397
398         inline bool
399         joinable(void) const {
400             return _native_handle != 0;
401         }
402
403         inline void
404         join() {
405 #ifdef _WIN32
406             WaitForSingleObject(_native_handle, INFINITE);
407 #else
408             pthread_join(_native_handle, NULL);
409 #endif
410         }
411
412     private:
413         native_handle_type _native_handle;
414
415 #if 0
416 #ifdef _WIN32
417         template< class Function, class Arg >
418         static DWORD WINAPI
419         ThreadProc(LPVOID lpParameter) {
420
421         );
422 #endif
423 #endif
424     };
425
426 } /* namespace os */
427
428 #endif /* _OS_THREAD_HPP_ */