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