]> git.sesse.net Git - casparcg/blob - tbb30_20100406oss/include/tbb/recursive_mutex.h
2.0.2: Updated to boost 1.48.
[casparcg] / tbb30_20100406oss / include / tbb / recursive_mutex.h
1 /*
2     Copyright 2005-2010 Intel Corporation.  All Rights Reserved.
3
4     This file is part of Threading Building Blocks.
5
6     Threading Building Blocks is free software; you can redistribute it
7     and/or modify it under the terms of the GNU General Public License
8     version 2 as published by the Free Software Foundation.
9
10     Threading Building Blocks is distributed in the hope that it will be
11     useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with Threading Building Blocks; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19     As a special exception, you may use this file as part of a free software
20     library without restriction.  Specifically, if other files instantiate
21     templates or use macros or inline functions from this file, or you compile
22     this file and link it with other files to produce an executable, this
23     file does not by itself cause the resulting executable to be covered by
24     the GNU General Public License.  This exception does not however
25     invalidate any other reasons why the executable file might be covered by
26     the GNU General Public License.
27 */
28
29 #ifndef __TBB_recursive_mutex_H
30 #define __TBB_recursive_mutex_H
31
32 #if _WIN32||_WIN64
33     #include <windows.h>
34     #if !defined(_WIN32_WINNT)
35     // The following Windows API function is declared explicitly;
36     // otherwise any user would have to specify /D_WIN32_WINNT=0x0400
37     extern "C" BOOL WINAPI TryEnterCriticalSection( LPCRITICAL_SECTION );
38     #endif
39 #else /* if not _WIN32||_WIN64 */
40     #include <pthread.h>
41 #endif /* _WIN32||_WIN64 */
42
43 #include <new>
44 #include "aligned_space.h"
45 #include "tbb_stddef.h"
46 #include "tbb_profiling.h"
47
48 namespace tbb {
49 //! Mutex that allows recursive mutex acquisition.
50 /** Mutex that allows recursive mutex acquisition.
51     @ingroup synchronization */
52 class recursive_mutex {
53 public:
54     //! Construct unacquired recursive_mutex.
55     recursive_mutex() {
56 #if TBB_USE_ASSERT || TBB_USE_THREADING_TOOLS
57         internal_construct();
58 #else
59   #if _WIN32||_WIN64
60         InitializeCriticalSection(&impl);
61   #else
62         pthread_mutexattr_t mtx_attr;
63         int error_code = pthread_mutexattr_init( &mtx_attr );
64         if( error_code )
65             tbb::internal::handle_perror(error_code,"recursive_mutex: pthread_mutexattr_init failed");
66
67         pthread_mutexattr_settype( &mtx_attr, PTHREAD_MUTEX_RECURSIVE );
68         error_code = pthread_mutex_init( &impl, &mtx_attr );
69         if( error_code )
70             tbb::internal::handle_perror(error_code,"recursive_mutex: pthread_mutex_init failed");
71
72         pthread_mutexattr_destroy( &mtx_attr );
73   #endif /* _WIN32||_WIN64*/
74 #endif /* TBB_USE_ASSERT */
75     };
76
77     ~recursive_mutex() {
78 #if TBB_USE_ASSERT
79         internal_destroy();
80 #else
81   #if _WIN32||_WIN64
82         DeleteCriticalSection(&impl);
83   #else
84         pthread_mutex_destroy(&impl); 
85
86   #endif /* _WIN32||_WIN64 */
87 #endif /* TBB_USE_ASSERT */
88     };
89
90     class scoped_lock;
91     friend class scoped_lock;
92
93     //! The scoped locking pattern
94     /** It helps to avoid the common problem of forgetting to release lock.
95         It also nicely provides the "node" for queuing locks. */
96     class scoped_lock: internal::no_copy {
97     public:
98         //! Construct lock that has not acquired a recursive_mutex. 
99         scoped_lock() : my_mutex(NULL) {};
100
101         //! Acquire lock on given mutex.
102         scoped_lock( recursive_mutex& mutex ) {
103 #if TBB_USE_ASSERT
104             my_mutex = &mutex; 
105 #endif /* TBB_USE_ASSERT */
106             acquire( mutex );
107         }
108
109         //! Release lock (if lock is held).
110         ~scoped_lock() {
111             if( my_mutex ) 
112                 release();
113         }
114
115         //! Acquire lock on given mutex.
116         void acquire( recursive_mutex& mutex ) {
117 #if TBB_USE_ASSERT
118             internal_acquire( mutex );
119 #else
120             my_mutex = &mutex;
121             mutex.lock();
122 #endif /* TBB_USE_ASSERT */
123         }
124
125         //! Try acquire lock on given recursive_mutex.
126         bool try_acquire( recursive_mutex& mutex ) {
127 #if TBB_USE_ASSERT
128             return internal_try_acquire( mutex );
129 #else
130             bool result = mutex.try_lock();
131             if( result )
132                 my_mutex = &mutex;
133             return result;
134 #endif /* TBB_USE_ASSERT */
135         }
136
137         //! Release lock
138         void release() {
139 #if TBB_USE_ASSERT
140             internal_release();
141 #else
142             my_mutex->unlock();
143             my_mutex = NULL;
144 #endif /* TBB_USE_ASSERT */
145         }
146
147     private:
148         //! The pointer to the current recursive_mutex to work
149         recursive_mutex* my_mutex;
150
151         //! All checks from acquire using mutex.state were moved here
152         void __TBB_EXPORTED_METHOD internal_acquire( recursive_mutex& m );
153
154         //! All checks from try_acquire using mutex.state were moved here
155         bool __TBB_EXPORTED_METHOD internal_try_acquire( recursive_mutex& m );
156
157         //! All checks from release using mutex.state were moved here
158         void __TBB_EXPORTED_METHOD internal_release();
159
160         friend class recursive_mutex;
161     };
162
163     // Mutex traits
164     static const bool is_rw_mutex = false;
165     static const bool is_recursive_mutex = true;
166     static const bool is_fair_mutex = false;
167
168     // C++0x compatibility interface
169     
170     //! Acquire lock
171     void lock() {
172 #if TBB_USE_ASSERT
173         aligned_space<scoped_lock,1> tmp;
174         new(tmp.begin()) scoped_lock(*this);
175 #else
176   #if _WIN32||_WIN64
177         EnterCriticalSection(&impl);
178   #else
179         pthread_mutex_lock(&impl);
180   #endif /* _WIN32||_WIN64 */
181 #endif /* TBB_USE_ASSERT */
182     }
183
184     //! Try acquiring lock (non-blocking)
185     /** Return true if lock acquired; false otherwise. */
186     bool try_lock() {
187 #if TBB_USE_ASSERT
188         aligned_space<scoped_lock,1> tmp;
189         return (new(tmp.begin()) scoped_lock)->internal_try_acquire(*this);
190 #else        
191   #if _WIN32||_WIN64
192         return TryEnterCriticalSection(&impl)!=0;
193   #else
194         return pthread_mutex_trylock(&impl)==0;
195   #endif /* _WIN32||_WIN64 */
196 #endif /* TBB_USE_ASSERT */
197     }
198
199     //! Release lock
200     void unlock() {
201 #if TBB_USE_ASSERT
202         aligned_space<scoped_lock,1> tmp;
203         scoped_lock& s = *tmp.begin();
204         s.my_mutex = this;
205         s.internal_release();
206 #else
207   #if _WIN32||_WIN64
208         LeaveCriticalSection(&impl);
209   #else
210         pthread_mutex_unlock(&impl);
211   #endif /* _WIN32||_WIN64 */
212 #endif /* TBB_USE_ASSERT */
213     }
214
215     //! Return native_handle
216   #if _WIN32||_WIN64
217     typedef LPCRITICAL_SECTION native_handle_type;
218   #else
219     typedef pthread_mutex_t* native_handle_type;
220   #endif
221     native_handle_type native_handle() { return (native_handle_type) &impl; }
222
223 private:
224 #if _WIN32||_WIN64
225     CRITICAL_SECTION impl;
226     enum state_t {
227         INITIALIZED=0x1234,
228         DESTROYED=0x789A,
229     } state;
230 #else
231     pthread_mutex_t impl;
232 #endif /* _WIN32||_WIN64 */
233
234     //! All checks from mutex constructor using mutex.state were moved here
235     void __TBB_EXPORTED_METHOD internal_construct();
236
237     //! All checks from mutex destructor using mutex.state were moved here
238     void __TBB_EXPORTED_METHOD internal_destroy();
239 };
240
241 __TBB_DEFINE_PROFILING_SET_NAME(recursive_mutex)
242
243 } // namespace tbb 
244
245 #endif /* __TBB_recursive_mutex_H */