]> git.cworth.org Git - apitrace/blob - common/os_thread.hpp
Use skiplist-based FastCallSet within trace::CallSet
[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 #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 std::thread
288      */
289     class thread {
290     public:
291 #ifdef _WIN32
292         typedef HANDLE native_handle_type;
293 #else
294         typedef pthread_t native_handle_type;
295 #endif
296
297         inline
298         thread() :
299             _native_handle(0)
300         {
301         }
302
303         inline
304         thread(const thread &other) :
305             _native_handle(other._native_handle)
306         {
307         }
308
309         template< class Function, class Arg >
310         explicit thread( Function& f, Arg arg ) {
311 #ifdef _WIN32
312             DWORD id = 0;
313             _native_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, (LPVOID)arg, 0, &id);
314 #else
315             pthread_create(&_native_handle, NULL, (void *(*) (void *))f, (void *)arg);
316 #endif
317         }
318
319         inline bool
320         joinable(void) const {
321             return _native_handle != 0;
322         }
323
324         inline void
325         join() {
326 #ifdef _WIN32
327             WaitForSingleObject(_native_handle, INFINITE);
328 #else
329             pthread_join(_native_handle, NULL);
330 #endif
331         }
332
333     private:
334         native_handle_type _native_handle;
335
336 #if 0
337 #ifdef _WIN32
338         template< class Function, class Arg >
339         static DWORD WINAPI
340         ThreadProc(LPVOID lpParameter) {
341
342         );
343 #endif
344 #endif
345     };
346
347 } /* namespace os */
348
349 #endif /* _OS_THREAD_HPP_ */