]> git.sesse.net Git - casparcg/blob - tbb30_20100406oss/include/tbb/mutex.h
2.0.2: Updated to boost 1.48.
[casparcg] / tbb30_20100406oss / include / tbb / 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_mutex_H
30 #define __TBB_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
50 //! Wrapper around the platform's native reader-writer lock.
51 /** For testing purposes only.
52     @ingroup synchronization */
53 class mutex {
54 public:
55     //! Construct unacquired mutex.
56     mutex() {
57 #if TBB_USE_ASSERT || TBB_USE_THREADING_TOOLS
58     internal_construct();
59 #else
60   #if _WIN32||_WIN64
61         InitializeCriticalSection(&impl);
62   #else
63         int error_code = pthread_mutex_init(&impl,NULL);
64         if( error_code )
65             tbb::internal::handle_perror(error_code,"mutex: pthread_mutex_init failed");
66   #endif /* _WIN32||_WIN64*/
67 #endif /* TBB_USE_ASSERT */
68     };
69
70     ~mutex() {
71 #if TBB_USE_ASSERT
72         internal_destroy();
73 #else
74   #if _WIN32||_WIN64
75         DeleteCriticalSection(&impl);
76   #else
77         pthread_mutex_destroy(&impl); 
78
79   #endif /* _WIN32||_WIN64 */
80 #endif /* TBB_USE_ASSERT */
81     };
82
83     class scoped_lock;
84     friend class scoped_lock;
85
86     //! The scoped locking pattern
87     /** It helps to avoid the common problem of forgetting to release lock.
88         It also nicely provides the "node" for queuing locks. */
89     class scoped_lock : internal::no_copy {
90     public:
91         //! Construct lock that has not acquired a mutex. 
92         scoped_lock() : my_mutex(NULL) {};
93
94         //! Acquire lock on given mutex.
95         scoped_lock( mutex& mutex ) {
96             acquire( mutex );
97         }
98
99         //! Release lock (if lock is held).
100         ~scoped_lock() {
101             if( my_mutex ) 
102                 release();
103         }
104
105         //! Acquire lock on given mutex.
106         void acquire( mutex& mutex ) {
107 #if TBB_USE_ASSERT
108             internal_acquire(mutex);
109 #else
110             mutex.lock();
111             my_mutex = &mutex;
112 #endif /* TBB_USE_ASSERT */
113         }
114
115         //! Try acquire lock on given mutex.
116         bool try_acquire( mutex& mutex ) {
117 #if TBB_USE_ASSERT
118             return internal_try_acquire (mutex);
119 #else
120             bool result = mutex.try_lock();
121             if( result )
122                 my_mutex = &mutex;
123             return result;
124 #endif /* TBB_USE_ASSERT */
125         }
126
127         //! Release lock
128         void release() {
129 #if TBB_USE_ASSERT
130             internal_release ();
131 #else
132             my_mutex->unlock();
133             my_mutex = NULL;
134 #endif /* TBB_USE_ASSERT */
135         }
136
137     private:
138         //! The pointer to the current mutex to work
139         mutex* my_mutex;
140
141         //! All checks from acquire using mutex.state were moved here
142         void __TBB_EXPORTED_METHOD internal_acquire( mutex& m );
143
144         //! All checks from try_acquire using mutex.state were moved here
145         bool __TBB_EXPORTED_METHOD internal_try_acquire( mutex& m );
146
147         //! All checks from release using mutex.state were moved here
148         void __TBB_EXPORTED_METHOD internal_release();
149
150         friend class mutex;
151     };
152
153     // Mutex traits
154     static const bool is_rw_mutex = false;
155     static const bool is_recursive_mutex = false;
156     static const bool is_fair_mutex = false;
157
158     // ISO C++0x compatibility methods
159
160     //! Acquire lock
161     void lock() {
162 #if TBB_USE_ASSERT
163         aligned_space<scoped_lock,1> tmp;
164         new(tmp.begin()) scoped_lock(*this);
165 #else
166   #if _WIN32||_WIN64
167         EnterCriticalSection(&impl);
168   #else
169         pthread_mutex_lock(&impl);
170   #endif /* _WIN32||_WIN64 */
171 #endif /* TBB_USE_ASSERT */
172     }
173
174     //! Try acquiring lock (non-blocking)
175     /** Return true if lock acquired; false otherwise. */
176     bool try_lock() {
177 #if TBB_USE_ASSERT
178         aligned_space<scoped_lock,1> tmp;
179         scoped_lock& s = *tmp.begin();
180         s.my_mutex = NULL;
181         return s.internal_try_acquire(*this);
182 #else
183   #if _WIN32||_WIN64
184         return TryEnterCriticalSection(&impl)!=0;
185   #else
186         return pthread_mutex_trylock(&impl)==0;
187   #endif /* _WIN32||_WIN64 */
188 #endif /* TBB_USE_ASSERT */
189     }
190
191     //! Release lock
192     void unlock() {
193 #if TBB_USE_ASSERT
194         aligned_space<scoped_lock,1> tmp;
195         scoped_lock& s = *tmp.begin();
196         s.my_mutex = this;
197         s.internal_release();
198 #else
199   #if _WIN32||_WIN64
200         LeaveCriticalSection(&impl);
201   #else
202         pthread_mutex_unlock(&impl);
203   #endif /* _WIN32||_WIN64 */
204 #endif /* TBB_USE_ASSERT */
205     }
206
207     //! Return native_handle
208   #if _WIN32||_WIN64
209     typedef LPCRITICAL_SECTION native_handle_type;
210   #else
211     typedef pthread_mutex_t* native_handle_type;
212   #endif
213     native_handle_type native_handle() { return (native_handle_type) &impl; }
214
215     enum state_t {
216         INITIALIZED=0x1234,
217         DESTROYED=0x789A,
218         HELD=0x56CD
219     };
220 private:
221 #if _WIN32||_WIN64
222     CRITICAL_SECTION impl;    
223     enum state_t state;
224 #else
225     pthread_mutex_t impl;
226 #endif /* _WIN32||_WIN64 */
227
228     //! All checks from mutex constructor using mutex.state were moved here
229     void __TBB_EXPORTED_METHOD internal_construct();
230
231     //! All checks from mutex destructor using mutex.state were moved here
232     void __TBB_EXPORTED_METHOD internal_destroy();
233
234 #if _WIN32||_WIN64
235 public:
236     //!  Set the internal state
237     void set_state( state_t to ) { state = to; }
238 #endif
239 };
240
241 __TBB_DEFINE_PROFILING_SET_NAME(mutex)
242
243 } // namespace tbb 
244
245 #endif /* __TBB_mutex_H */