]> git.cworth.org Git - apitrace/blob - common/os_thread.hpp
f5f4e48a0f60a3d24131e4828ce9740197d7d1b0
[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  * 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             SleepConditionVariableCS(&_native_handle, &mutex_native_handle, INFINITE);
243 #else
244             pthread_cond_wait(&_native_handle, &mutex_native_handle);
245 #endif
246         }
247
248     protected:
249         native_handle_type _native_handle;
250     };
251
252
253     /**
254      * Same interface as std::thread
255      */
256     class thread {
257     public:
258 #ifdef _WIN32
259         typedef HANDLE native_handle_type;
260 #else
261         typedef pthread_t native_handle_type;
262 #endif
263
264         inline
265         thread() :
266             _native_handle(0)
267         {
268         }
269
270         inline
271         thread(thread &other) :
272             _native_handle(other._native_handle)
273         {
274         }
275
276         template< class Function, class Arg >
277         explicit thread( Function& f, Arg arg ) {
278 #ifdef _WIN32
279             DWORD id = 0;
280             _native_handle = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)f, (LPVOID)arg, 0, &id);
281 #else
282             pthread_create(&_native_handle, NULL, ( void *(*) (void *))f, arg);
283 #endif
284         }
285
286         inline bool
287         joinable(void) const {
288             return _native_handle != 0;
289         }
290
291         inline void
292         join() {
293 #ifdef _WIN32
294             WaitForSingleObject(_native_handle, INFINITE);
295 #else
296             pthread_join(_native_handle, NULL);
297 #endif
298         }
299
300     private:
301         native_handle_type _native_handle;
302
303 #if 0
304 #ifdef _WIN32
305         template< class Function, class Arg >
306         static DWORD WINAPI
307         ThreadProc(LPVOID lpParameter) {
308
309         );
310 #endif
311 #endif
312     };
313
314 } /* namespace os */
315
316 #endif /* _OS_THREAD_HPP_ */