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