]> git.sesse.net Git - casparcg/blob - tbb30_20100406oss/include/tbb/compat/condition_variable
2.0.2: Updated to boost 1.48.
[casparcg] / tbb30_20100406oss / include / tbb / compat / condition_variable
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_condition_variable_H
30 #define __TBB_condition_variable_H
31
32 #if _WIN32||_WIN64
33 #include <windows.h>
34
35 namespace tbb { 
36 namespace interface5 {
37 namespace internal { 
38 struct condition_variable_using_event
39 {
40     //! Event for blocking waiting threads.
41     HANDLE event;
42     //! Protects invariants involving n_waiters, release_count, and epoch.
43     CRITICAL_SECTION mutex;
44     //! Number of threads waiting on this condition variable
45     int n_waiters;
46     //! Number of threads remaining that should no longer wait on this condition variable.
47     int release_count;
48     //! To keep threads from waking up prematurely with earlier signals.
49     unsigned epoch;
50 };
51 }}} // namespace tbb::interface5::internal
52
53 #ifndef CONDITION_VARIABLE_INIT
54 typedef void* CONDITION_VARIABLE;
55 typedef CONDITION_VARIABLE* PCONDITION_VARIABLE;
56 #endif
57
58 #else /* if not _WIN32||_WIN64 */
59 #include <pthread.h>
60 #endif /* _WIN32||_WIN64 */
61
62 #include "../tbb_stddef.h"
63 #include "../mutex.h"
64 #include "../tbb_thread.h"
65 #include "../tbb_exception.h"
66 #include "../tbb_profiling.h"
67
68 namespace tbb {
69
70 namespace interface5 {
71
72 // C++0x standard working draft 30.4.3
73 // Lock tag types
74 struct defer_lock_t { }; //! do not acquire ownership of the mutex
75 struct try_to_lock_t { }; //! try to acquire ownership of the mutex without blocking
76 struct adopt_lock_t { }; //! assume the calling thread has already
77 const defer_lock_t defer_lock = {};
78 const try_to_lock_t try_to_lock = {};
79 const adopt_lock_t adopt_lock = {};
80
81 // C++0x standard working draft 30.4.3.1
82 //! lock_guard 
83 template<typename M>
84 class lock_guard : tbb::internal::no_copy {
85 public:
86     //! mutex type
87     typedef M mutex_type;
88
89     //! Constructor
90     /** precondition: If mutex_type is not a recursive mutex, the calling thread
91         does not own the mutex m. */
92     explicit lock_guard(mutex_type& m) : pm(m) {m.lock();}
93     
94     //! Adopt_lock constructor
95     /** precondition: the calling thread owns the mutex m. */
96     lock_guard(mutex_type& m, adopt_lock_t) : pm(m) {}
97
98     //! Destructor
99     ~lock_guard() { pm.unlock(); }
100 private:
101     mutex_type& pm;
102 };
103
104 // C++0x standard working draft 30.4.3.2
105 //! unique_lock 
106 template<typename M>
107 class unique_lock : tbb::internal::no_copy {
108     friend class condition_variable;
109 public:
110     typedef M mutex_type;
111
112     // 30.4.3.2.1 construct/copy/destroy
113     // NB: Without constructors that take an r-value reference to a unique_lock, the following constructor is of little use.
114     //! Constructor
115     /** postcondition: pm==0 && owns==false */
116     unique_lock() : pm(NULL), owns(false) {}
117
118     //! Constructor
119     /** precondition: if mutex_type is not a recursive mutex, the  calling thread
120         does not own the mutex m.  If the precondition is not met, a deadlock occurs.
121         postcondition: pm==&m and owns==true */
122     explicit unique_lock(mutex_type& m) : pm(&m) {m.lock(); owns=true;}
123
124     //! Defer_lock constructor
125     /** postcondition: pm==&m and owns==false */
126     unique_lock(mutex_type& m, defer_lock_t) : pm(&m), owns(false) {}
127
128     //! Try_to_lock constructor
129     /** precondition: if mutex_type is not a recursive mutex, the  calling thread
130        does not own the mutex m.  If the precondition is not met, a deadlock occurs.
131        postcondition: pm==&m and owns==res where res is the value returned by
132        the call to m.try_lock(). */
133     unique_lock(mutex_type& m, try_to_lock_t) : pm(&m) {owns = m.try_lock();}
134
135     //! Adopt_lock constructor
136     /** precondition: the calling thread owns the mutex. If it does not, mutex->unlock() would fail.
137         postcondition: pm==&m and owns==true */
138     unique_lock(mutex_type& m, adopt_lock_t) : pm(&m), owns(true) {}
139
140     //! Timed unique_lock acquisition.
141     /** To avoid requiring support for namespace chrono, this method deviates from the working draft in that 
142         it uses tbb::tick_count::interval_t to specify the time duration. */
143     unique_lock(mutex_type& m, const tick_count::interval_t &i) : pm(&m) {owns = try_lock_for( i );}
144
145     //! Destructor
146     ~unique_lock() { if( owns ) pm->unlock(); }
147
148     // 30.4.3.2.2 locking
149     //! Lock the mutex and own it.
150     void lock() {
151         if( pm ) {
152             if( !owns ) {
153                 pm->lock();
154                 owns = true;
155             } else 
156                 throw_exception_v4( tbb::internal::eid_possible_deadlock );
157         } else 
158             throw_exception_v4( tbb::internal::eid_operation_not_permitted );
159         __TBB_ASSERT( owns, NULL );
160     }
161
162     //! Try to lock the mutex. 
163     /** If successful, note that this lock owns it. Otherwise, set it false. */
164     bool try_lock() {
165         if( pm ) {
166             if( !owns )
167                 owns = pm->try_lock();
168             else
169                 throw_exception_v4( tbb::internal::eid_possible_deadlock );
170         } else 
171             throw_exception_v4( tbb::internal::eid_operation_not_permitted );
172         return owns;
173     }
174  
175     //! Try to lock the mutex. 
176     bool try_lock_for( const tick_count::interval_t &i );
177
178     //! Unlock the mutex
179     /** And note that this lock no longer owns it. */
180     void unlock() { 
181         if( owns ) {
182             pm->unlock();
183             owns = false;
184         } else
185             throw_exception_v4( tbb::internal::eid_operation_not_permitted );
186         __TBB_ASSERT( !owns, NULL );
187     }
188
189     // 30.4.3.2.3 modifiers
190     //! Swap the two unique locks
191     void swap(unique_lock& u) {
192         mutex_type* t_pm = u.pm;    u.pm   = pm;    pm   = t_pm;
193         bool t_owns      = u.owns;  u.owns = owns;  owns = t_owns;
194     }
195
196     //! Release control over the mutex.
197     mutex_type* release() {
198         mutex_type* o_pm = pm; 
199         pm = NULL; 
200         owns = false; 
201         return o_pm; 
202     }
203
204     // 30.4.3.2.4 observers
205     //! Does this lock own the mutex?
206     bool owns_lock() const { return owns; }
207
208     //! Does this lock own the mutex?
209     /*explicit*/ operator bool() const { return owns; }
210
211     //! Return the mutex that this lock currently has.
212     mutex_type* mutex() const { return pm; }
213
214 private:
215     mutex_type* pm;
216     bool owns;
217 };
218
219 template<typename M>
220 bool unique_lock<M>::try_lock_for( const tick_count::interval_t &i)
221
222     const int unique_lock_tick = 100; /* microseconds; 0.1 milliseconds */
223     // the smallest wait-time is 0.1 milliseconds.
224     bool res = pm->try_lock();
225     int duration_in_micro; 
226     if( !res && (duration_in_micro=int(i.seconds()*1e6))>unique_lock_tick ) {
227         tick_count::interval_t i_100( double(unique_lock_tick)/1e6 /* seconds */); // 100 microseconds = 0.1*10E-3
228         do {
229             this_tbb_thread::sleep(i_100); // sleep for 100 micro seconds
230             duration_in_micro -= unique_lock_tick;
231             res = pm->try_lock();
232         } while( !res && duration_in_micro>unique_lock_tick );
233     }
234     return (owns=res);
235 }
236
237 //! Swap the two unique locks that have the mutexes of same type 
238 template<typename M>
239 void swap(unique_lock<M>& x, unique_lock<M>& y) { x.swap( y ); }
240
241 namespace internal {
242
243 #if _WIN32||_WIN64
244 union condvar_impl_t {
245     condition_variable_using_event cv_event;
246     CONDITION_VARIABLE             cv_native;
247 };
248
249 void __TBB_EXPORTED_FUNC internal_initialize_condition_variable( condvar_impl_t& cv );
250 void __TBB_EXPORTED_FUNC internal_destroy_condition_variable(    condvar_impl_t& cv );
251 void __TBB_EXPORTED_FUNC internal_condition_variable_notify_one( condvar_impl_t& cv );
252 void __TBB_EXPORTED_FUNC internal_condition_variable_notify_all( condvar_impl_t& cv );
253 bool __TBB_EXPORTED_FUNC internal_condition_variable_wait( condvar_impl_t& cv, mutex* mtx, const tick_count::interval_t* i = NULL );
254 #else /* if !(_WIN32||_WIN64), i.e., POSIX threads */
255 typedef pthread_cond_t condvar_impl_t;
256 #endif
257
258 } // namespace internal
259
260 //! cv_status
261 /** C++0x standard working draft 30.5 */
262 enum cv_status { no_timeout, timeout }; 
263
264 //! condition variable
265 /** C++0x standard working draft 30.5.1 
266     @ingroup synchronization */
267 class condition_variable : tbb::internal::no_copy {
268 public:
269     //! Constructor
270     condition_variable() { 
271 #if _WIN32||_WIN64
272         internal_initialize_condition_variable( my_cv ); 
273 #else
274         pthread_cond_init( &my_cv, NULL );
275 #endif
276     }
277
278     //! Destructor
279     ~condition_variable() { 
280         //precondition: There shall be no thread blocked on *this.
281 #if _WIN32||_WIN64
282         internal_destroy_condition_variable( my_cv );
283 #else
284         pthread_cond_destroy( &my_cv );
285 #endif
286     }
287
288     //! Notify one thread and wake it up
289     void notify_one() { 
290 #if _WIN32||_WIN64
291         internal_condition_variable_notify_one( my_cv ); 
292 #else
293         pthread_cond_signal( &my_cv );
294 #endif
295     }
296
297     //! Notify all threads 
298     void notify_all() { 
299 #if _WIN32||_WIN64
300         internal_condition_variable_notify_all( my_cv ); 
301 #else
302         pthread_cond_broadcast( &my_cv );
303 #endif
304     }
305
306     //! Release the mutex associated with the lock and wait on this condition variable
307     void wait(unique_lock<mutex>& lock);
308
309     //! Wait on this condition variable while pred is false
310     template <class Predicate>
311     void wait(unique_lock<mutex>& lock, Predicate pred) {
312         while( !pred() )
313             wait( lock );
314     }
315
316     //! Timed version of wait()
317     cv_status wait_for(unique_lock<mutex>& lock, const tick_count::interval_t &i );
318
319     //! Timed version of the predicated wait
320     /** The loop terminates when pred() returns true or when the time duration specified by rel_time (i) has elapsed. */
321     template<typename Predicate>
322     bool wait_for(unique_lock<mutex>& lock, const tick_count::interval_t &i, Predicate pred)
323     {
324         while( !pred() ) {
325             cv_status st = wait_for( lock, i );
326             if( st==timeout )
327                 return pred();
328         }
329         return true;
330     }
331
332     // C++0x standard working draft. 30.2.3
333     typedef internal::condvar_impl_t* native_handle_type;
334
335     native_handle_type native_handle() { return (native_handle_type) &my_cv; }
336
337 private:
338     internal::condvar_impl_t my_cv;
339 };
340
341
342 #if _WIN32||_WIN64
343 inline void condition_variable::wait( unique_lock<mutex>& lock )
344 {
345     __TBB_ASSERT( lock.owns, NULL );
346     lock.owns = false;
347     if( !internal_condition_variable_wait( my_cv, lock.mutex() ) ) {
348         int ec = GetLastError();
349         // on Windows 7, SleepConditionVariableCS() may return ERROR_TIMEOUT while the doc says it returns WAIT_TIMEOUT
350         __TBB_ASSERT_EX( ec!=WAIT_TIMEOUT&&ec!=ERROR_TIMEOUT, NULL );
351         lock.owns = true;
352         throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
353     }
354     lock.owns = true;
355 }
356
357 inline cv_status condition_variable::wait_for( unique_lock<mutex>& lock, const tick_count::interval_t& i )
358 {
359     cv_status rc = no_timeout;
360     __TBB_ASSERT( lock.owns, NULL );
361     lock.owns = false;
362     // condvar_wait could be SleepConditionVariableCS (or SleepConditionVariableSRW) or our own pre-vista cond_var_wait()
363     if( !internal_condition_variable_wait( my_cv, lock.mutex(), &i ) ) {
364         int ec = GetLastError();
365         if( ec==WAIT_TIMEOUT || ec==ERROR_TIMEOUT )
366             rc = timeout;
367         else {
368             lock.owns = true;
369             throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
370         }
371     }
372     lock.owns = true;
373     return rc;
374 }
375 #else
376 #if __linux__
377 #include <ctime>
378 #else /* generic Unix */
379 #include <sys/time.h>
380 #include <errno.h>
381 #endif
382
383 inline void condition_variable::wait( unique_lock<mutex>& lock )
384 {
385     __TBB_ASSERT( lock.owns, NULL );
386     lock.owns = false;
387     if( pthread_cond_wait( &my_cv, lock.mutex()->native_handle() ) ) {
388         lock.owns = true;
389         throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
390     }
391     // upon successful return, the mutex has been locked and is owned by the calling thread.
392     lock.owns = true;
393 }
394
395 inline cv_status condition_variable::wait_for( unique_lock<mutex>& lock, const tick_count::interval_t& i )
396 {
397 #if __linux__
398     struct timespec req;
399     double sec = i.seconds();
400     clock_gettime( CLOCK_REALTIME, &req );
401     req.tv_sec  += static_cast<long>(sec);
402     req.tv_nsec += static_cast<long>( (sec - static_cast<long>(sec))*1e9 );
403 #else /* generic Unix */
404     struct timeval tv;
405     struct timespec req;
406     double sec = i.seconds();
407     int status = gettimeofday(&tv, NULL);
408     __TBB_ASSERT_EX( status==0, "gettimeofday failed" );
409     req.tv_sec  = tv.tv_sec + static_cast<long>(sec);
410     req.tv_nsec = tv.tv_usec*1000 + static_cast<long>( (sec - static_cast<long>(sec))*1e9 );
411 #endif /*(choice of OS) */
412
413     int ec;
414     cv_status rc = no_timeout;
415     __TBB_ASSERT( lock.owns, NULL );
416     lock.owns = false;
417     if( ( ec=pthread_cond_timedwait( &my_cv, lock.mutex()->native_handle(), &req ) ) ) {
418         if( ec==ETIMEDOUT )
419             rc = timeout;
420         else {
421             __TBB_ASSERT( lock.try_lock()==false, NULL );
422             lock.owns = true;
423             throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
424         }
425     }
426     lock.owns = true;
427     return rc;
428 }
429 #endif /* !(_WIN32||_WIN64) */
430
431 } // namespace interface5
432
433 __TBB_DEFINE_PROFILING_SET_NAME(interface5::condition_variable)
434
435 } // namespace tbb 
436
437 #if TBB_IMPLEMENT_CPP0X
438
439 namespace std {
440
441 using tbb::interface5::defer_lock_t;
442 using tbb::interface5::try_to_lock_t;
443 using tbb::interface5::adopt_lock_t;
444 using tbb::interface5::defer_lock;
445 using tbb::interface5::try_to_lock;
446 using tbb::interface5::adopt_lock;
447 using tbb::interface5::lock_guard;
448 using tbb::interface5::unique_lock;
449 using tbb::interface5::swap;   /* this is for void std::swap(unique_lock<M>&,unique_lock<M>&) */
450 using tbb::interface5::condition_variable;
451 using tbb::interface5::cv_status;
452 using tbb::interface5::timeout;
453 using tbb::interface5::no_timeout;
454
455 } // namespace std 
456
457 #endif /* TBB_IMPLEMENT_CPP0X */
458
459 #endif /* __TBB_condition_variable_H */