2 Copyright 2005-2010 Intel Corporation. All Rights Reserved.
4 This file is part of Threading Building Blocks.
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.
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.
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
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.
29 #ifndef __TBB_recursive_mutex_H
30 #define __TBB_recursive_mutex_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 );
39 #else /* if not _WIN32||_WIN64 */
41 #endif /* _WIN32||_WIN64 */
44 #include "aligned_space.h"
45 #include "tbb_stddef.h"
46 #include "tbb_profiling.h"
49 //! Mutex that allows recursive mutex acquisition.
50 /** Mutex that allows recursive mutex acquisition.
51 @ingroup synchronization */
52 class recursive_mutex {
54 //! Construct unacquired recursive_mutex.
56 #if TBB_USE_ASSERT || TBB_USE_THREADING_TOOLS
60 InitializeCriticalSection(&impl);
62 pthread_mutexattr_t mtx_attr;
63 int error_code = pthread_mutexattr_init( &mtx_attr );
65 tbb::internal::handle_perror(error_code,"recursive_mutex: pthread_mutexattr_init failed");
67 pthread_mutexattr_settype( &mtx_attr, PTHREAD_MUTEX_RECURSIVE );
68 error_code = pthread_mutex_init( &impl, &mtx_attr );
70 tbb::internal::handle_perror(error_code,"recursive_mutex: pthread_mutex_init failed");
72 pthread_mutexattr_destroy( &mtx_attr );
73 #endif /* _WIN32||_WIN64*/
74 #endif /* TBB_USE_ASSERT */
82 DeleteCriticalSection(&impl);
84 pthread_mutex_destroy(&impl);
86 #endif /* _WIN32||_WIN64 */
87 #endif /* TBB_USE_ASSERT */
91 friend class scoped_lock;
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 {
98 //! Construct lock that has not acquired a recursive_mutex.
99 scoped_lock() : my_mutex(NULL) {};
101 //! Acquire lock on given mutex.
102 scoped_lock( recursive_mutex& mutex ) {
105 #endif /* TBB_USE_ASSERT */
109 //! Release lock (if lock is held).
115 //! Acquire lock on given mutex.
116 void acquire( recursive_mutex& mutex ) {
118 internal_acquire( mutex );
122 #endif /* TBB_USE_ASSERT */
125 //! Try acquire lock on given recursive_mutex.
126 bool try_acquire( recursive_mutex& mutex ) {
128 return internal_try_acquire( mutex );
130 bool result = mutex.try_lock();
134 #endif /* TBB_USE_ASSERT */
144 #endif /* TBB_USE_ASSERT */
148 //! The pointer to the current recursive_mutex to work
149 recursive_mutex* my_mutex;
151 //! All checks from acquire using mutex.state were moved here
152 void __TBB_EXPORTED_METHOD internal_acquire( recursive_mutex& m );
154 //! All checks from try_acquire using mutex.state were moved here
155 bool __TBB_EXPORTED_METHOD internal_try_acquire( recursive_mutex& m );
157 //! All checks from release using mutex.state were moved here
158 void __TBB_EXPORTED_METHOD internal_release();
160 friend class recursive_mutex;
164 static const bool is_rw_mutex = false;
165 static const bool is_recursive_mutex = true;
166 static const bool is_fair_mutex = false;
168 // C++0x compatibility interface
173 aligned_space<scoped_lock,1> tmp;
174 new(tmp.begin()) scoped_lock(*this);
177 EnterCriticalSection(&impl);
179 pthread_mutex_lock(&impl);
180 #endif /* _WIN32||_WIN64 */
181 #endif /* TBB_USE_ASSERT */
184 //! Try acquiring lock (non-blocking)
185 /** Return true if lock acquired; false otherwise. */
188 aligned_space<scoped_lock,1> tmp;
189 return (new(tmp.begin()) scoped_lock)->internal_try_acquire(*this);
192 return TryEnterCriticalSection(&impl)!=0;
194 return pthread_mutex_trylock(&impl)==0;
195 #endif /* _WIN32||_WIN64 */
196 #endif /* TBB_USE_ASSERT */
202 aligned_space<scoped_lock,1> tmp;
203 scoped_lock& s = *tmp.begin();
205 s.internal_release();
208 LeaveCriticalSection(&impl);
210 pthread_mutex_unlock(&impl);
211 #endif /* _WIN32||_WIN64 */
212 #endif /* TBB_USE_ASSERT */
215 //! Return native_handle
217 typedef LPCRITICAL_SECTION native_handle_type;
219 typedef pthread_mutex_t* native_handle_type;
221 native_handle_type native_handle() { return (native_handle_type) &impl; }
225 CRITICAL_SECTION impl;
231 pthread_mutex_t impl;
232 #endif /* _WIN32||_WIN64 */
234 //! All checks from mutex constructor using mutex.state were moved here
235 void __TBB_EXPORTED_METHOD internal_construct();
237 //! All checks from mutex destructor using mutex.state were moved here
238 void __TBB_EXPORTED_METHOD internal_destroy();
241 __TBB_DEFINE_PROFILING_SET_NAME(recursive_mutex)
245 #endif /* __TBB_recursive_mutex_H */