]> git.cworth.org Git - apitrace/blob - common/os_thread.hpp
Implement grouping of calls.
[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  * This feature is not supported on Windows XP
45  */
46 #define USE_WIN32_CONDITION_VARIABLES 0
47
48
49 /**
50  * Compiler TLS.
51  *
52  * See also:
53  * - http://gcc.gnu.org/onlinedocs/gcc-4.6.3/gcc/Thread_002dLocal.html
54  * - http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx
55  */
56 #if defined(HAVE_COMPILER_TLS)
57 #  define OS_THREAD_SPECIFIC_PTR(_type) HAVE_COMPILER_TLS _type *
58 #else
59 #  define OS_THREAD_SPECIFIC_PTR(_type) os::thread_specific_ptr< _type >
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     template <typename T>
287     class thread_specific_ptr
288     {
289     private:
290 #ifdef _WIN32
291         DWORD dwTlsIndex;
292 #else
293         pthread_key_t key;
294 #endif
295
296     public:
297         thread_specific_ptr(void) {
298 #ifdef _WIN32
299             dwTlsIndex = TlsAlloc();
300 #else
301             pthread_key_create(&key, NULL);
302 #endif
303         }
304
305         ~thread_specific_ptr() {
306 #ifdef _WIN32
307             TlsFree(dwTlsIndex);
308 #else
309             pthread_key_delete(key);
310 #endif
311         }
312
313         inline T *
314         get(void) const {
315             void *ptr;
316 #ifdef _WIN32
317             ptr = TlsGetValue(dwTlsIndex);
318 #else
319             ptr = pthread_getspecific(key);
320 #endif
321             return static_cast<T*>(ptr);
322         }
323
324         inline
325         operator T * (void) const
326         {
327             return get();
328         }
329
330         inline T *
331         operator -> (void) const
332         {
333             return get();
334         }
335
336         inline T *
337         operator = (T * new_value)
338         {
339             set(new_value);
340             return new_value;
341         }
342
343         inline void
344         set(T* new_value) {
345 #ifdef _WIN32
346             TlsSetValue(dwTlsIndex, new_value);
347 #else
348             pthread_setspecific(key, new_value);
349 #endif
350         }
351     };
352
353
354     /**
355      * Same interface as std::thread
356      */
357     class thread {
358     public:
359 #ifdef _WIN32
360         typedef HANDLE native_handle_type;
361 #else
362         typedef pthread_t native_handle_type;
363 #endif
364
365         inline
366         thread() :
367             _native_handle(0)
368         {
369         }
370
371         inline
372         thread(const thread &other) :
373             _native_handle(other._native_handle)
374         {
375         }
376
377         inline
378         ~thread() {
379         }
380
381         template< class Function, class Arg >
382         explicit thread( Function& f, Arg arg ) {
383 #ifdef _WIN32
384             DWORD id = 0;
385             _native_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, (LPVOID)arg, 0, &id);
386 #else
387             pthread_create(&_native_handle, NULL, (void *(*) (void *))f, (void *)arg);
388 #endif
389         }
390
391         inline thread &
392         operator =(const thread &other) {
393             _native_handle = other._native_handle;
394             return *this;
395         }
396
397         inline bool
398         joinable(void) const {
399             return _native_handle != 0;
400         }
401
402         inline void
403         join() {
404 #ifdef _WIN32
405             WaitForSingleObject(_native_handle, INFINITE);
406 #else
407             pthread_join(_native_handle, NULL);
408 #endif
409         }
410
411     private:
412         native_handle_type _native_handle;
413
414 #if 0
415 #ifdef _WIN32
416         template< class Function, class Arg >
417         static DWORD WINAPI
418         ThreadProc(LPVOID lpParameter) {
419
420         );
421 #endif
422 #endif
423     };
424
425 } /* namespace os */
426
427 #endif /* _OS_THREAD_HPP_ */