Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/tbb/compat/condition_variable is written in an unsupported language. File is not indexed.

0001 /*
0002     Copyright (c) 2005-2020 Intel Corporation
0003 
0004     Licensed under the Apache License, Version 2.0 (the "License");
0005     you may not use this file except in compliance with the License.
0006     You may obtain a copy of the License at
0007 
0008         http://www.apache.org/licenses/LICENSE-2.0
0009 
0010     Unless required by applicable law or agreed to in writing, software
0011     distributed under the License is distributed on an "AS IS" BASIS,
0012     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0013     See the License for the specific language governing permissions and
0014     limitations under the License.
0015 */
0016 
0017 #include "../internal/_deprecated_header_message_guard.h"
0018 
0019 #if !defined(__TBB_show_deprecation_message_condition_variable_H) && defined(__TBB_show_deprecated_header_message)
0020 #define  __TBB_show_deprecation_message_condition_variable_H
0021 #pragma message("TBB Warning: tbb/compat/condition_variable is deprecated. For details, please see Deprecated Features appendix in the TBB reference manual.")
0022 #endif
0023 
0024 #if defined(__TBB_show_deprecated_header_message)
0025 #undef __TBB_show_deprecated_header_message
0026 #endif
0027 
0028 #ifndef __TBB_condition_variable_H
0029 #define __TBB_condition_variable_H
0030 
0031 #define __TBB_condition_variable_H_include_area
0032 #include "../internal/_warning_suppress_enable_notice.h"
0033 
0034 #if _WIN32||_WIN64
0035 #include "../machine/windows_api.h"
0036 
0037 namespace tbb {
0038 namespace interface5 {
0039 namespace internal {
0040 struct condition_variable_using_event
0041 {
0042     //! Event for blocking waiting threads.
0043     HANDLE event;
0044     //! Protects invariants involving n_waiters, release_count, and epoch.
0045     CRITICAL_SECTION mutex;
0046     //! Number of threads waiting on this condition variable
0047     int n_waiters;
0048     //! Number of threads remaining that should no longer wait on this condition variable.
0049     int release_count;
0050     //! To keep threads from waking up prematurely with earlier signals.
0051     unsigned epoch;
0052 };
0053 }}} // namespace tbb::interface5::internal
0054 
0055 #ifndef CONDITION_VARIABLE_INIT
0056 typedef void* CONDITION_VARIABLE;
0057 typedef CONDITION_VARIABLE* PCONDITION_VARIABLE;
0058 #endif
0059 
0060 #else /* if not _WIN32||_WIN64 */
0061 #include <errno.h> // some systems need it for ETIMEDOUT
0062 #include <pthread.h>
0063 #if __linux__
0064 #include <ctime>
0065 #else /* generic Unix */
0066 #include <sys/time.h>
0067 #endif
0068 #endif /* _WIN32||_WIN64 */
0069 
0070 #include "../tbb_stddef.h"
0071 #include "../mutex.h"
0072 #include "../tbb_thread.h"
0073 #include "../tbb_exception.h"
0074 #include "../tbb_profiling.h"
0075 
0076 namespace tbb {
0077 
0078 namespace interface5 {
0079 
0080 // C++0x standard working draft 30.4.3
0081 // Lock tag types
0082 struct __TBB_DEPRECATED_IN_VERBOSE_MODE defer_lock_t { }; //! do not acquire ownership of the mutex
0083 struct __TBB_DEPRECATED_IN_VERBOSE_MODE try_to_lock_t { }; //! try to acquire ownership of the mutex without blocking
0084 struct __TBB_DEPRECATED_IN_VERBOSE_MODE adopt_lock_t { }; //! assume the calling thread has already
0085 __TBB_DEPRECATED_IN_VERBOSE_MODE const defer_lock_t defer_lock = {};
0086 __TBB_DEPRECATED_IN_VERBOSE_MODE const try_to_lock_t try_to_lock = {};
0087 __TBB_DEPRECATED_IN_VERBOSE_MODE const adopt_lock_t adopt_lock = {};
0088 
0089 // C++0x standard working draft 30.4.3.1
0090 //! lock_guard
0091 template<typename M>
0092 class __TBB_DEPRECATED_IN_VERBOSE_MODE lock_guard : tbb::internal::no_copy {
0093 public:
0094     //! mutex type
0095     typedef M mutex_type;
0096 
0097     //! Constructor
0098     /** precondition: If mutex_type is not a recursive mutex, the calling thread
0099         does not own the mutex m. */
0100     explicit lock_guard(mutex_type& m) : pm(m) {m.lock();}
0101 
0102     //! Adopt_lock constructor
0103     /** precondition: the calling thread owns the mutex m. */
0104     lock_guard(mutex_type& m, adopt_lock_t) : pm(m) {}
0105 
0106     //! Destructor
0107     ~lock_guard() { pm.unlock(); }
0108 private:
0109     mutex_type& pm;
0110 };
0111 
0112 // C++0x standard working draft 30.4.3.2
0113 //! unique_lock
0114 template<typename M>
0115 class __TBB_DEPRECATED_IN_VERBOSE_MODE unique_lock : tbb::internal::no_copy {
0116     friend class condition_variable;
0117 public:
0118     typedef M mutex_type;
0119 
0120     // 30.4.3.2.1 construct/copy/destroy
0121     // NB: Without constructors that take an r-value reference to a unique_lock, the following constructor is of little use.
0122     //! Constructor
0123     /** postcondition: pm==0 && owns==false */
0124     unique_lock() : pm(NULL), owns(false) {}
0125 
0126     //! Constructor
0127     /** precondition: if mutex_type is not a recursive mutex, the  calling thread
0128         does not own the mutex m.  If the precondition is not met, a deadlock occurs.
0129         postcondition: pm==&m and owns==true */
0130     explicit unique_lock(mutex_type& m) : pm(&m) {m.lock(); owns=true;}
0131 
0132     //! Defer_lock constructor
0133     /** postcondition: pm==&m and owns==false */
0134     unique_lock(mutex_type& m, defer_lock_t) : pm(&m), owns(false) {}
0135 
0136     //! Try_to_lock constructor
0137     /** precondition: if mutex_type is not a recursive mutex, the  calling thread
0138        does not own the mutex m.  If the precondition is not met, a deadlock occurs.
0139        postcondition: pm==&m and owns==res where res is the value returned by
0140        the call to m.try_lock(). */
0141     unique_lock(mutex_type& m, try_to_lock_t) : pm(&m) {owns = m.try_lock();}
0142 
0143     //! Adopt_lock constructor
0144     /** precondition: the calling thread owns the mutex. If it does not, mutex->unlock() would fail.
0145         postcondition: pm==&m and owns==true */
0146     unique_lock(mutex_type& m, adopt_lock_t) : pm(&m), owns(true) {}
0147 
0148     //! Timed unique_lock acquisition.
0149     /** To avoid requiring support for namespace chrono, this method deviates from the working draft in that
0150         it uses tbb::tick_count::interval_t to specify the time duration. */
0151     unique_lock(mutex_type& m, const tick_count::interval_t &i) : pm(&m) {owns = try_lock_for( i );}
0152 
0153 #if __TBB_CPP11_RVALUE_REF_PRESENT
0154     //! Move constructor
0155     /** postconditions: pm == src_p.pm and owns == src_p.owns (where src_p is the state of src just prior to this
0156         construction), src.pm == 0 and src.owns == false. */
0157     unique_lock(unique_lock && src): pm(NULL), owns(false) {this->swap(src);}
0158 
0159     //! Move assignment
0160     /** effects: If owns calls pm->unlock().
0161         Postconditions: pm == src_p.pm and owns == src_p.owns (where src_p is the state of src just prior to this
0162         assignment), src.pm == 0 and src.owns == false. */
0163     unique_lock& operator=(unique_lock && src) {
0164         if (owns)
0165             this->unlock();
0166         pm = NULL;
0167         this->swap(src);
0168         return *this;
0169     }
0170 #endif // __TBB_CPP11_RVALUE_REF_PRESENT
0171 
0172     //! Destructor
0173     ~unique_lock() { if( owns ) pm->unlock(); }
0174 
0175     // 30.4.3.2.2 locking
0176     //! Lock the mutex and own it.
0177     void lock() {
0178         if( pm ) {
0179             if( !owns ) {
0180                 pm->lock();
0181                 owns = true;
0182             } else
0183                 throw_exception_v4( tbb::internal::eid_possible_deadlock );
0184         } else
0185             throw_exception_v4( tbb::internal::eid_operation_not_permitted );
0186         __TBB_ASSERT( owns, NULL );
0187     }
0188 
0189     //! Try to lock the mutex.
0190     /** If successful, note that this lock owns it. Otherwise, set it false. */
0191     bool try_lock() {
0192         if( pm ) {
0193             if( !owns )
0194                 owns = pm->try_lock();
0195             else
0196                 throw_exception_v4( tbb::internal::eid_possible_deadlock );
0197         } else
0198             throw_exception_v4( tbb::internal::eid_operation_not_permitted );
0199         return owns;
0200     }
0201 
0202     //! Try to lock the mutex.
0203     bool try_lock_for( const tick_count::interval_t &i );
0204 
0205     //! Unlock the mutex
0206     /** And note that this lock no longer owns it. */
0207     void unlock() {
0208         if( owns ) {
0209             pm->unlock();
0210             owns = false;
0211         } else
0212             throw_exception_v4( tbb::internal::eid_operation_not_permitted );
0213         __TBB_ASSERT( !owns, NULL );
0214     }
0215 
0216     // 30.4.3.2.3 modifiers
0217     //! Swap the two unique locks
0218     void swap(unique_lock& u) {
0219         mutex_type* t_pm = u.pm;    u.pm   = pm;    pm   = t_pm;
0220         bool t_owns      = u.owns;  u.owns = owns;  owns = t_owns;
0221     }
0222 
0223     //! Release control over the mutex.
0224     mutex_type* release() {
0225         mutex_type* o_pm = pm;
0226         pm = NULL;
0227         owns = false;
0228         return o_pm;
0229     }
0230 
0231     // 30.4.3.2.4 observers
0232     //! Does this lock own the mutex?
0233     bool owns_lock() const { return owns; }
0234 
0235     // TODO: Un-comment 'explicit' when the last non-C++0x compiler support is dropped
0236     //! Does this lock own the mutex?
0237     /*explicit*/ operator bool() const { return owns; }
0238 
0239     //! Return the mutex that this lock currently has.
0240     mutex_type* mutex() const { return pm; }
0241 
0242 private:
0243     mutex_type* pm;
0244     bool owns;
0245 };
0246 
0247 template<typename M>
0248 __TBB_DEPRECATED_IN_VERBOSE_MODE bool unique_lock<M>::try_lock_for( const tick_count::interval_t &i)
0249 {
0250     const int unique_lock_tick = 100; /* microseconds; 0.1 milliseconds */
0251     // the smallest wait-time is 0.1 milliseconds.
0252     bool res = pm->try_lock();
0253     int duration_in_micro;
0254     if( !res && (duration_in_micro=int(i.seconds()*1e6))>unique_lock_tick ) {
0255         tick_count::interval_t i_100( double(unique_lock_tick)/1e6 /* seconds */); // 100 microseconds = 0.1*10E-3
0256         do {
0257             this_tbb_thread::sleep(i_100); // sleep for 100 micro seconds
0258             duration_in_micro -= unique_lock_tick;
0259             res = pm->try_lock();
0260         } while( !res && duration_in_micro>unique_lock_tick );
0261     }
0262     return (owns=res);
0263 }
0264 
0265 //! Swap the two unique locks that have the mutexes of same type
0266 template<typename M>
0267 void swap(unique_lock<M>& x, unique_lock<M>& y) { x.swap( y ); }
0268 
0269 namespace internal {
0270 
0271 #if _WIN32||_WIN64
0272 union condvar_impl_t {
0273     condition_variable_using_event cv_event;
0274     CONDITION_VARIABLE             cv_native;
0275 };
0276 void __TBB_EXPORTED_FUNC internal_initialize_condition_variable( condvar_impl_t& cv );
0277 void __TBB_EXPORTED_FUNC internal_destroy_condition_variable(    condvar_impl_t& cv );
0278 void __TBB_EXPORTED_FUNC internal_condition_variable_notify_one( condvar_impl_t& cv );
0279 void __TBB_EXPORTED_FUNC internal_condition_variable_notify_all( condvar_impl_t& cv );
0280 bool __TBB_EXPORTED_FUNC internal_condition_variable_wait( condvar_impl_t& cv, mutex* mtx, const tick_count::interval_t* i = NULL );
0281 
0282 #else /* if !(_WIN32||_WIN64), i.e., POSIX threads */
0283 typedef pthread_cond_t condvar_impl_t;
0284 #endif
0285 
0286 } // namespace internal
0287 
0288 //! cv_status
0289 /** C++0x standard working draft 30.5 */
0290 enum cv_status { no_timeout, timeout };
0291 
0292 //! condition variable
0293 /** C++0x standard working draft 30.5.1
0294     @ingroup synchronization */
0295 class __TBB_DEPRECATED_IN_VERBOSE_MODE condition_variable : tbb::internal::no_copy {
0296 public:
0297     //! Constructor
0298     condition_variable() {
0299 #if _WIN32||_WIN64
0300         internal_initialize_condition_variable( my_cv );
0301 #else
0302         pthread_cond_init( &my_cv, NULL );
0303 #endif
0304     }
0305 
0306     //! Destructor
0307     ~condition_variable() {
0308         //precondition: There shall be no thread blocked on *this.
0309 #if _WIN32||_WIN64
0310         internal_destroy_condition_variable( my_cv );
0311 #else
0312         pthread_cond_destroy( &my_cv );
0313 #endif
0314     }
0315 
0316     //! Notify one thread and wake it up
0317     void notify_one() {
0318 #if _WIN32||_WIN64
0319         internal_condition_variable_notify_one( my_cv );
0320 #else
0321         pthread_cond_signal( &my_cv );
0322 #endif
0323     }
0324 
0325     //! Notify all threads
0326     void notify_all() {
0327 #if _WIN32||_WIN64
0328         internal_condition_variable_notify_all( my_cv );
0329 #else
0330         pthread_cond_broadcast( &my_cv );
0331 #endif
0332     }
0333 
0334     //! Release the mutex associated with the lock and wait on this condition variable
0335     void wait(unique_lock<mutex>& lock);
0336 
0337     //! Wait on this condition variable while pred is false
0338     template <class Predicate>
0339     void wait(unique_lock<mutex>& lock, Predicate pred) {
0340         while( !pred() )
0341             wait( lock );
0342     }
0343 
0344     //! Timed version of wait()
0345     cv_status wait_for(unique_lock<mutex>& lock, const tick_count::interval_t &i );
0346 
0347     //! Timed version of the predicated wait
0348     /** The loop terminates when pred() returns true or when the time duration specified by rel_time (i) has elapsed. */
0349     template<typename Predicate>
0350     bool wait_for(unique_lock<mutex>& lock, const tick_count::interval_t &i, Predicate pred)
0351     {
0352         while( !pred() ) {
0353             cv_status st = wait_for( lock, i );
0354             if( st==timeout )
0355                 return pred();
0356         }
0357         return true;
0358     }
0359 
0360     // C++0x standard working draft. 30.2.3
0361     typedef internal::condvar_impl_t* native_handle_type;
0362 
0363     native_handle_type native_handle() { return (native_handle_type) &my_cv; }
0364 
0365 private:
0366     internal::condvar_impl_t my_cv;
0367 };
0368 
0369 
0370 #if _WIN32||_WIN64
0371 inline void condition_variable::wait( unique_lock<mutex>& lock )
0372 {
0373     __TBB_ASSERT( lock.owns, NULL );
0374     lock.owns = false;
0375     if( !internal_condition_variable_wait( my_cv, lock.mutex() ) ) {
0376         int ec = GetLastError();
0377         // on Windows 7, SleepConditionVariableCS() may return ERROR_TIMEOUT while the doc says it returns WAIT_TIMEOUT
0378         __TBB_ASSERT_EX( ec!=WAIT_TIMEOUT&&ec!=ERROR_TIMEOUT, NULL );
0379         lock.owns = true;
0380         throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
0381     }
0382     lock.owns = true;
0383 }
0384 
0385 inline cv_status condition_variable::wait_for( unique_lock<mutex>& lock, const tick_count::interval_t& i )
0386 {
0387     cv_status rc = no_timeout;
0388     __TBB_ASSERT( lock.owns, NULL );
0389     lock.owns = false;
0390     // condvar_wait could be SleepConditionVariableCS (or SleepConditionVariableSRW) or our own pre-vista cond_var_wait()
0391     if( !internal_condition_variable_wait( my_cv, lock.mutex(), &i ) ) {
0392         int ec = GetLastError();
0393         if( ec==WAIT_TIMEOUT || ec==ERROR_TIMEOUT )
0394             rc = timeout;
0395         else {
0396             lock.owns = true;
0397             throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
0398         }
0399     }
0400     lock.owns = true;
0401     return rc;
0402 }
0403 
0404 #else /* !(_WIN32||_WIN64) */
0405 inline void condition_variable::wait( unique_lock<mutex>& lock )
0406 {
0407     __TBB_ASSERT( lock.owns, NULL );
0408     lock.owns = false;
0409     if( pthread_cond_wait( &my_cv, lock.mutex()->native_handle() ) ) {
0410         lock.owns = true;
0411         throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
0412     }
0413     // upon successful return, the mutex has been locked and is owned by the calling thread.
0414     lock.owns = true;
0415 }
0416 
0417 inline cv_status condition_variable::wait_for( unique_lock<mutex>& lock, const tick_count::interval_t& i )
0418 {
0419 #if __linux__
0420     struct timespec req;
0421     double sec = i.seconds();
0422     clock_gettime( CLOCK_REALTIME, &req );
0423     req.tv_sec  += static_cast<long>(sec);
0424     req.tv_nsec += static_cast<long>( (sec - static_cast<long>(sec))*1e9 );
0425 #else /* generic Unix */
0426     struct timeval tv;
0427     struct timespec req;
0428     double sec = i.seconds();
0429     int status = gettimeofday(&tv, NULL);
0430     __TBB_ASSERT_EX( status==0, "gettimeofday failed" );
0431     req.tv_sec  = tv.tv_sec + static_cast<long>(sec);
0432     req.tv_nsec = tv.tv_usec*1000 + static_cast<long>( (sec - static_cast<long>(sec))*1e9 );
0433 #endif /*(choice of OS) */
0434     if( req.tv_nsec>=1e9 ) {
0435         req.tv_sec  += 1;
0436         req.tv_nsec -= static_cast<long int>(1e9);
0437     }
0438     __TBB_ASSERT( 0<=req.tv_nsec && req.tv_nsec<1e9, NULL );
0439 
0440     int ec;
0441     cv_status rc = no_timeout;
0442     __TBB_ASSERT( lock.owns, NULL );
0443     lock.owns = false;
0444     if( ( ec=pthread_cond_timedwait( &my_cv, lock.mutex()->native_handle(), &req ) ) ) {
0445         if( ec==ETIMEDOUT )
0446             rc = timeout;
0447         else {
0448             __TBB_ASSERT( lock.try_lock()==false, NULL );
0449             lock.owns = true;
0450             throw_exception_v4( tbb::internal::eid_condvar_wait_failed );
0451         }
0452     }
0453     lock.owns = true;
0454     return rc;
0455 }
0456 #endif /* !(_WIN32||_WIN64) */
0457 
0458 } // namespace interface5
0459 
0460 __TBB_DEFINE_PROFILING_SET_NAME(interface5::condition_variable)
0461 
0462 } // namespace tbb
0463 
0464 #if TBB_IMPLEMENT_CPP0X
0465 
0466 namespace std {
0467 
0468 using tbb::interface5::defer_lock_t;
0469 using tbb::interface5::try_to_lock_t;
0470 using tbb::interface5::adopt_lock_t;
0471 using tbb::interface5::defer_lock;
0472 using tbb::interface5::try_to_lock;
0473 using tbb::interface5::adopt_lock;
0474 using tbb::interface5::lock_guard;
0475 using tbb::interface5::unique_lock;
0476 using tbb::interface5::swap;   /* this is for void std::swap(unique_lock<M>&,unique_lock<M>&) */
0477 using tbb::interface5::condition_variable;
0478 using tbb::interface5::cv_status;
0479 using tbb::interface5::timeout;
0480 using tbb::interface5::no_timeout;
0481 
0482 } // namespace std
0483 
0484 #endif /* TBB_IMPLEMENT_CPP0X */
0485 
0486 #include "../internal/_warning_suppress_disable_notice.h"
0487 #undef __TBB_condition_variable_H_include_area
0488 
0489 #endif /* __TBB_condition_variable_H */