Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-16 10:10:03

0001 #ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
0002 #define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
0003 // Distributed under the Boost Software License, Version 1.0. (See
0004 // accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 // (C) Copyright 2007-8 Anthony Williams
0007 // (C) Copyright 2011-2012 Vicente J. Botet Escriba
0008 
0009 #include <boost/thread/win32/thread_primitives.hpp>
0010 #include <boost/thread/win32/thread_data.hpp>
0011 #include <boost/thread/win32/thread_data.hpp>
0012 #include <boost/thread/win32/interlocked_read.hpp>
0013 #include <boost/thread/cv_status.hpp>
0014 #if defined BOOST_THREAD_USES_DATETIME
0015 #include <boost/thread/xtime.hpp>
0016 #endif
0017 #include <boost/thread/mutex.hpp>
0018 #include <boost/thread/thread_time.hpp>
0019 #include <boost/thread/lock_guard.hpp>
0020 #include <boost/thread/lock_types.hpp>
0021 #include <boost/thread/detail/platform_time.hpp>
0022 
0023 #include <boost/assert.hpp>
0024 #include <boost/intrusive_ptr.hpp>
0025 
0026 #ifdef BOOST_THREAD_USES_CHRONO
0027 #include <boost/chrono/system_clocks.hpp>
0028 #include <boost/chrono/ceil.hpp>
0029 #endif
0030 
0031 #include <limits.h>
0032 #include <algorithm>
0033 #include <vector>
0034 
0035 #include <boost/config/abi_prefix.hpp>
0036 
0037 namespace boost
0038 {
0039     namespace detail
0040     {
0041         class basic_cv_list_entry;
0042         void intrusive_ptr_add_ref(basic_cv_list_entry * p);
0043         void intrusive_ptr_release(basic_cv_list_entry * p);
0044 
0045         class basic_cv_list_entry
0046         {
0047         private:
0048             detail::win32::handle_manager semaphore;
0049             detail::win32::handle_manager wake_sem;
0050             long waiters;
0051             bool notified;
0052             long references;
0053 
0054         public:
0055             BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry)
0056             explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_):
0057                 semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
0058                 wake_sem(wake_sem_.duplicate()),
0059                 waiters(1),notified(false),references(0)
0060             {}
0061 
0062             static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry)
0063             {
0064                 return !detail::interlocked_read_acquire(&entry->waiters);
0065             }
0066 
0067             void add_waiter()
0068             {
0069                 BOOST_INTERLOCKED_INCREMENT(&waiters);
0070             }
0071 
0072             void remove_waiter()
0073             {
0074                 BOOST_INTERLOCKED_DECREMENT(&waiters);
0075             }
0076 
0077             void release(unsigned count_to_release)
0078             {
0079                 notified=true;
0080                 winapi::ReleaseSemaphore(semaphore,count_to_release,0);
0081             }
0082 
0083             void release_waiters()
0084             {
0085                 release(detail::interlocked_read_acquire(&waiters));
0086             }
0087 
0088             bool is_notified() const
0089             {
0090                 return notified;
0091             }
0092 
0093             bool interruptible_wait(detail::internal_platform_timepoint const &timeout)
0094             {
0095                 return this_thread::interruptible_wait(semaphore, timeout);
0096             }
0097 
0098             bool woken()
0099             {
0100                 unsigned long const woken_result=winapi::WaitForSingleObjectEx(wake_sem,0,0);
0101                 BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
0102                 return woken_result==0;
0103             }
0104 
0105             friend void intrusive_ptr_add_ref(basic_cv_list_entry * p);
0106             friend void intrusive_ptr_release(basic_cv_list_entry * p);
0107         };
0108 
0109         inline void intrusive_ptr_add_ref(basic_cv_list_entry * p)
0110         {
0111             BOOST_INTERLOCKED_INCREMENT(&p->references);
0112         }
0113 
0114         inline void intrusive_ptr_release(basic_cv_list_entry * p)
0115         {
0116             if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
0117             {
0118                 delete p;
0119             }
0120         }
0121 
0122         class basic_condition_variable
0123         {
0124             boost::mutex internal_mutex;
0125             long total_count;
0126             unsigned active_generation_count;
0127 
0128             typedef basic_cv_list_entry list_entry;
0129 
0130             typedef boost::intrusive_ptr<list_entry> entry_ptr;
0131             typedef std::vector<entry_ptr> generation_list;
0132 
0133             generation_list generations;
0134             detail::win32::handle_manager wake_sem;
0135 
0136             void wake_waiters(long count_to_wake)
0137             {
0138                 detail::interlocked_write_release(&total_count,total_count-count_to_wake);
0139                 winapi::ReleaseSemaphore(wake_sem,count_to_wake,0);
0140             }
0141 
0142             template<typename lock_type>
0143             struct relocker
0144             {
0145                 BOOST_THREAD_NO_COPYABLE(relocker)
0146                 lock_type& _lock;
0147                 bool _unlocked;
0148 
0149                 relocker(lock_type& lock_):
0150                     _lock(lock_), _unlocked(false)
0151                 {}
0152                 void unlock()
0153                 {
0154                   if ( ! _unlocked )
0155                   {
0156                     _lock.unlock();
0157                     _unlocked=true;
0158                   }
0159                 }
0160                 void lock()
0161                 {
0162                   if ( _unlocked )
0163                   {
0164                     _lock.lock();
0165                     _unlocked=false;
0166                   }
0167                 }
0168                 ~relocker() BOOST_NOEXCEPT_IF(false)
0169                 {
0170                   lock();
0171                 }
0172             };
0173 
0174 
0175             entry_ptr get_wait_entry()
0176             {
0177                 boost::lock_guard<boost::mutex> lk(internal_mutex);
0178                 if(!wake_sem)
0179                 {
0180                     wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
0181                     BOOST_ASSERT(wake_sem);
0182                 }
0183 
0184                 detail::interlocked_write_release(&total_count,total_count+1);
0185                 if(generations.empty() || generations.back()->is_notified())
0186                 {
0187                     entry_ptr new_entry(new list_entry(wake_sem));
0188                     generations.push_back(new_entry);
0189                     return new_entry;
0190                 }
0191                 else
0192                 {
0193                     generations.back()->add_waiter();
0194                     return generations.back();
0195                 }
0196             }
0197 
0198             struct entry_manager
0199             {
0200                 entry_ptr entry;
0201                 boost::mutex& internal_mutex;
0202 
0203 
0204                 BOOST_THREAD_NO_COPYABLE(entry_manager)
0205 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
0206                 entry_manager(entry_ptr&& entry_, boost::mutex& mutex_):
0207                     entry(static_cast< entry_ptr&& >(entry_)), internal_mutex(mutex_)
0208                 {}
0209 #else
0210                 entry_manager(entry_ptr const& entry_, boost::mutex& mutex_):
0211                     entry(entry_), internal_mutex(mutex_)
0212                 {}
0213 #endif
0214 
0215                 void remove_waiter_and_reset()
0216                 {
0217                   if (entry) {
0218                     boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
0219                     entry->remove_waiter();
0220                     entry.reset();
0221                   }
0222                 }
0223                 ~entry_manager() BOOST_NOEXCEPT_IF(false)
0224                 {
0225                   remove_waiter_and_reset();
0226                 }
0227 
0228                 list_entry* operator->()
0229                 {
0230                     return entry.get();
0231                 }
0232             };
0233 
0234         protected:
0235             basic_condition_variable(const basic_condition_variable& other);
0236             basic_condition_variable& operator=(const basic_condition_variable& other);
0237 
0238         public:
0239             basic_condition_variable():
0240                 total_count(0),active_generation_count(0),wake_sem(0)
0241             {}
0242 
0243             ~basic_condition_variable()
0244             {}
0245 
0246             // When this function returns true:
0247             // * A notification (or sometimes a spurious OS signal) has been received
0248             // * Do not assume that the timeout has not been reached
0249             // * Do not assume that the predicate has been changed
0250             //
0251             // When this function returns false:
0252             // * The timeout has been reached
0253             // * Do not assume that a notification has not been received
0254             // * Do not assume that the predicate has not been changed
0255             template<typename lock_type>
0256             bool do_wait_until(lock_type& lock, detail::internal_platform_timepoint const &timeout)
0257             {
0258               relocker<lock_type> locker(lock);
0259               entry_manager entry(get_wait_entry(), internal_mutex);
0260               locker.unlock();
0261 
0262               bool woken=false;
0263               while(!woken)
0264               {
0265                   if(!entry->interruptible_wait(timeout))
0266                   {
0267                       return false;
0268                   }
0269 
0270                   woken=entry->woken();
0271               }
0272               // do it here to avoid throwing on the destructor
0273               entry.remove_waiter_and_reset();
0274               locker.lock();
0275               return true;
0276             }
0277 
0278             void notify_one() BOOST_NOEXCEPT
0279             {
0280                 if(detail::interlocked_read_acquire(&total_count))
0281                 {
0282                     boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
0283                     if(!total_count)
0284                     {
0285                         return;
0286                     }
0287                     wake_waiters(1);
0288 
0289                     for(generation_list::iterator it=generations.begin(),
0290                             end=generations.end();
0291                         it!=end;++it)
0292                     {
0293                         (*it)->release(1);
0294                     }
0295                     generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end());
0296                 }
0297             }
0298 
0299             void notify_all() BOOST_NOEXCEPT
0300             {
0301                 if(detail::interlocked_read_acquire(&total_count))
0302                 {
0303                     boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
0304                     if(!total_count)
0305                     {
0306                         return;
0307                     }
0308                     wake_waiters(total_count);
0309                     for(generation_list::iterator it=generations.begin(),
0310                             end=generations.end();
0311                         it!=end;++it)
0312                     {
0313                         (*it)->release_waiters();
0314                     }
0315                     generations.clear();
0316                     wake_sem=detail::win32::handle(0);
0317                 }
0318             }
0319 
0320         };
0321     }
0322 
0323     class condition_variable:
0324         private detail::basic_condition_variable
0325     {
0326     public:
0327         BOOST_THREAD_NO_COPYABLE(condition_variable)
0328         condition_variable()
0329         {}
0330 
0331         using detail::basic_condition_variable::do_wait_until;
0332         using detail::basic_condition_variable::notify_one;
0333         using detail::basic_condition_variable::notify_all;
0334 
0335         void wait(unique_lock<mutex>& m)
0336         {
0337             do_wait_until(m, detail::internal_platform_timepoint::getMax());
0338         }
0339 
0340         template<typename predicate_type>
0341         void wait(unique_lock<mutex>& m,predicate_type pred)
0342         {
0343             while (!pred())
0344             {
0345                 wait(m);
0346             }
0347         }
0348 
0349 #if defined BOOST_THREAD_USES_DATETIME
0350         bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time)
0351         {
0352             // The system time may jump while this function is waiting. To compensate for this and time
0353             // out near the correct time, we could call do_wait_until() in a loop with a short timeout
0354             // and recheck the time remaining each time through the loop. However, because we can't
0355             // check the predicate each time do_wait_until() completes, this introduces the possibility
0356             // of not exiting the function when a notification occurs, since do_wait_until() may report
0357             // that it timed out even though a notification was received. The best this function can do
0358             // is report correctly whether or not it reached the timeout time.
0359             const detail::real_platform_timepoint ts(abs_time);
0360             const detail::platform_duration d(ts - detail::real_platform_clock::now());
0361             do_wait_until(m, detail::internal_platform_clock::now() + d);
0362             return ts > detail::real_platform_clock::now();
0363         }
0364         bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time)
0365         {
0366             return timed_wait(m, system_time(abs_time));
0367         }
0368         template<typename duration_type>
0369         bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
0370         {
0371             if (wait_duration.is_pos_infinity())
0372             {
0373                 wait(m);
0374                 return true;
0375             }
0376             if (wait_duration.is_special())
0377             {
0378                 return true;
0379             }
0380             const detail::platform_duration d(wait_duration);
0381             return do_wait_until(m, detail::internal_platform_clock::now() + d);
0382         }
0383 
0384         template<typename predicate_type>
0385         bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred)
0386         {
0387             // The system time may jump while this function is waiting. To compensate for this
0388             // and time out near the correct time, we call do_wait_until() in a loop with a
0389             // short timeout and recheck the time remaining each time through the loop.
0390             const detail::real_platform_timepoint ts(abs_time);
0391             while (!pred())
0392             {
0393                 detail::platform_duration d(ts - detail::real_platform_clock::now());
0394                 if (d <= detail::platform_duration::zero()) break; // timeout occurred
0395                 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0396                 do_wait_until(m, detail::internal_platform_clock::now() + d);
0397             }
0398             return pred();
0399         }
0400         template<typename predicate_type>
0401         bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred)
0402         {
0403             return timed_wait(m, system_time(abs_time), pred);
0404         }
0405         template<typename duration_type,typename predicate_type>
0406         bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
0407         {
0408             if (wait_duration.is_pos_infinity())
0409             {
0410                 while (!pred())
0411                 {
0412                     wait(m);
0413                 }
0414                 return true;
0415             }
0416             if (wait_duration.is_special())
0417             {
0418                 return pred();
0419             }
0420             const detail::platform_duration d(wait_duration);
0421             const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
0422             while (!pred())
0423             {
0424                 if (!do_wait_until(m, ts)) break; // timeout occurred
0425             }
0426             return pred();
0427         }
0428 #endif
0429 #ifdef BOOST_THREAD_USES_CHRONO
0430         template <class Duration>
0431         cv_status
0432         wait_until(
0433                 unique_lock<mutex>& lock,
0434                 const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
0435         {
0436             const detail::internal_platform_timepoint ts(t);
0437             if (do_wait_until(lock, ts)) return cv_status::no_timeout;
0438             else return cv_status::timeout;
0439         }
0440 
0441         template <class Clock, class Duration>
0442         cv_status
0443         wait_until(
0444                 unique_lock<mutex>& lock,
0445                 const chrono::time_point<Clock, Duration>& t)
0446         {
0447             // The system time may jump while this function is waiting. To compensate for this and time
0448             // out near the correct time, we could call do_wait_until() in a loop with a short timeout
0449             // and recheck the time remaining each time through the loop. However, because we can't
0450             // check the predicate each time do_wait_until() completes, this introduces the possibility
0451             // of not exiting the function when a notification occurs, since do_wait_until() may report
0452             // that it timed out even though a notification was received. The best this function can do
0453             // is report correctly whether or not it reached the timeout time.
0454             typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0455             common_duration d(t - Clock::now());
0456             do_wait_until(lock, detail::internal_chrono_clock::now() + d);
0457             if (t > Clock::now()) return cv_status::no_timeout;
0458             else return cv_status::timeout;
0459         }
0460 
0461         template <class Rep, class Period>
0462         cv_status
0463         wait_for(
0464                 unique_lock<mutex>& lock,
0465                 const chrono::duration<Rep, Period>& d)
0466         {
0467             return wait_until(lock, chrono::steady_clock::now() + d);
0468         }
0469 
0470         template <class Duration, class Predicate>
0471         bool
0472         wait_until(
0473                 unique_lock<mutex>& lock,
0474                 const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
0475                 Predicate pred)
0476         {
0477             const detail::internal_platform_timepoint ts(t);
0478             while (!pred())
0479             {
0480                 if (!do_wait_until(lock, ts)) break; // timeout occurred
0481             }
0482             return pred();
0483         }
0484 
0485         template <class Clock, class Duration, class Predicate>
0486         bool
0487         wait_until(
0488                 unique_lock<mutex>& lock,
0489                 const chrono::time_point<Clock, Duration>& t,
0490                 Predicate pred)
0491         {
0492             // The system time may jump while this function is waiting. To compensate for this
0493             // and time out near the correct time, we call do_wait_until() in a loop with a
0494             // short timeout and recheck the time remaining each time through the loop.
0495             typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0496             while (!pred())
0497             {
0498                 common_duration d(t - Clock::now());
0499                 if (d <= common_duration::zero()) break; // timeout occurred
0500                 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
0501                 do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
0502             }
0503             return pred();
0504         }
0505 
0506         template <class Rep, class Period, class Predicate>
0507         bool
0508         wait_for(
0509                 unique_lock<mutex>& lock,
0510                 const chrono::duration<Rep, Period>& d,
0511                 Predicate pred)
0512         {
0513             return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
0514         }
0515 #endif
0516     };
0517 
0518     class condition_variable_any:
0519         private detail::basic_condition_variable
0520     {
0521     public:
0522         BOOST_THREAD_NO_COPYABLE(condition_variable_any)
0523         condition_variable_any()
0524         {}
0525 
0526         using detail::basic_condition_variable::do_wait_until;
0527         using detail::basic_condition_variable::notify_one;
0528         using detail::basic_condition_variable::notify_all;
0529 
0530         template<typename lock_type>
0531         void wait(lock_type& m)
0532         {
0533             do_wait_until(m, detail::internal_platform_timepoint::getMax());
0534         }
0535 
0536         template<typename lock_type,typename predicate_type>
0537         void wait(lock_type& m,predicate_type pred)
0538         {
0539             while (!pred())
0540             {
0541                 wait(m);
0542             }
0543         }
0544 
0545 #if defined BOOST_THREAD_USES_DATETIME
0546         template<typename lock_type>
0547         bool timed_wait(lock_type& m,boost::system_time const& abs_time)
0548         {
0549             // The system time may jump while this function is waiting. To compensate for this and time
0550             // out near the correct time, we could call do_wait_until() in a loop with a short timeout
0551             // and recheck the time remaining each time through the loop. However, because we can't
0552             // check the predicate each time do_wait_until() completes, this introduces the possibility
0553             // of not exiting the function when a notification occurs, since do_wait_until() may report
0554             // that it timed out even though a notification was received. The best this function can do
0555             // is report correctly whether or not it reached the timeout time.
0556             const detail::real_platform_timepoint ts(abs_time);
0557             const detail::platform_duration d(ts - detail::real_platform_clock::now());
0558             do_wait_until(m, detail::internal_platform_clock::now() + d);
0559             return ts > detail::real_platform_clock::now();
0560         }
0561 
0562         template<typename lock_type>
0563         bool timed_wait(lock_type& m,boost::xtime const& abs_time)
0564         {
0565             return timed_wait(m, system_time(abs_time));
0566         }
0567 
0568         template<typename lock_type,typename duration_type>
0569         bool timed_wait(lock_type& m,duration_type const& wait_duration)
0570         {
0571             if (wait_duration.is_pos_infinity())
0572             {
0573                 wait(m);
0574                 return true;
0575             }
0576             if (wait_duration.is_special())
0577             {
0578                 return true;
0579             }
0580             const detail::platform_duration d(wait_duration);
0581             return do_wait_until(m, detail::internal_platform_clock::now() + d);
0582         }
0583 
0584         template<typename lock_type,typename predicate_type>
0585         bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred)
0586         {
0587             // The system time may jump while this function is waiting. To compensate for this
0588             // and time out near the correct time, we call do_wait_until() in a loop with a
0589             // short timeout and recheck the time remaining each time through the loop.
0590             const detail::real_platform_timepoint ts(abs_time);
0591             while (!pred())
0592             {
0593                 detail::platform_duration d(ts - detail::real_platform_clock::now());
0594                 if (d <= detail::platform_duration::zero()) break; // timeout occurred
0595                 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0596                 do_wait_until(m, detail::internal_platform_clock::now() + d);
0597             }
0598             return pred();
0599         }
0600 
0601         template<typename lock_type,typename predicate_type>
0602         bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred)
0603         {
0604             return timed_wait(m, system_time(abs_time), pred);
0605         }
0606 
0607         template<typename lock_type,typename duration_type,typename predicate_type>
0608         bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
0609         {
0610             if (wait_duration.is_pos_infinity())
0611             {
0612                 while (!pred())
0613                 {
0614                     wait(m);
0615                 }
0616                 return true;
0617             }
0618             if (wait_duration.is_special())
0619             {
0620                 return pred();
0621             }
0622             const detail::platform_duration d(wait_duration);
0623             const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
0624             while (!pred())
0625             {
0626                 if (!do_wait_until(m, ts)) break; // timeout occurred
0627             }
0628             return pred();
0629         }
0630 #endif
0631 #ifdef BOOST_THREAD_USES_CHRONO
0632         template <class lock_type,class Duration>
0633         cv_status
0634         wait_until(
0635                 lock_type& lock,
0636                 const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
0637         {
0638             const detail::internal_platform_timepoint ts(t);
0639             if (do_wait_until(lock, ts)) return cv_status::no_timeout;
0640             else return cv_status::timeout;
0641         }
0642 
0643         template <class lock_type, class Clock, class Duration>
0644         cv_status
0645         wait_until(
0646                 lock_type& lock,
0647                 const chrono::time_point<Clock, Duration>& t)
0648         {
0649             // The system time may jump while this function is waiting. To compensate for this and time
0650             // out near the correct time, we could call do_wait_until() in a loop with a short timeout
0651             // and recheck the time remaining each time through the loop. However, because we can't
0652             // check the predicate each time do_wait_until() completes, this introduces the possibility
0653             // of not exiting the function when a notification occurs, since do_wait_until() may report
0654             // that it timed out even though a notification was received. The best this function can do
0655             // is report correctly whether or not it reached the timeout time.
0656             typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0657             common_duration d(t - Clock::now());
0658             do_wait_until(lock, detail::internal_chrono_clock::now() + d);
0659             if (t > Clock::now()) return cv_status::no_timeout;
0660             else return cv_status::timeout;
0661         }
0662 
0663         template <class lock_type,  class Rep, class Period>
0664         cv_status
0665         wait_for(
0666                 lock_type& lock,
0667                 const chrono::duration<Rep, Period>& d)
0668         {
0669             return wait_until(lock, chrono::steady_clock::now() + d);
0670         }
0671 
0672         template <class lock_type, class Clock, class Duration, class Predicate>
0673         bool
0674         wait_until(
0675                 lock_type& lock,
0676                 const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
0677                 Predicate pred)
0678         {
0679             const detail::internal_platform_timepoint ts(t);
0680             while (!pred())
0681             {
0682                 if (!do_wait_until(lock, ts)) break; // timeout occurred
0683             }
0684             return pred();
0685         }
0686 
0687         template <class lock_type, class Clock, class Duration, class Predicate>
0688         bool
0689         wait_until(
0690                 lock_type& lock,
0691                 const chrono::time_point<Clock, Duration>& t,
0692                 Predicate pred)
0693         {
0694             // The system time may jump while this function is waiting. To compensate for this
0695             // and time out near the correct time, we call do_wait_until() in a loop with a
0696             // short timeout and recheck the time remaining each time through the loop.
0697             typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0698             while (!pred())
0699             {
0700                 common_duration d(t - Clock::now());
0701                 if (d <= common_duration::zero()) break; // timeout occurred
0702                 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
0703                 do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d));
0704             }
0705             return pred();
0706         }
0707 
0708         template <class lock_type, class Rep, class Period, class Predicate>
0709         bool
0710         wait_for(
0711                 lock_type& lock,
0712                 const chrono::duration<Rep, Period>& d,
0713                 Predicate pred)
0714         {
0715             return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
0716         }
0717 #endif
0718     };
0719 
0720         BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
0721 }
0722 
0723 #include <boost/config/abi_suffix.hpp>
0724 
0725 #endif