Chris@16: #ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP Chris@16: #define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: // (C) Copyright 2007-8 Anthony Williams Chris@16: // (C) Copyright 2011-2012 Vicente J. Botet Escriba Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #if defined BOOST_THREAD_USES_DATETIME Chris@16: #include Chris@16: #endif Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: #include Chris@16: Chris@16: #ifdef BOOST_THREAD_USES_CHRONO Chris@16: #include Chris@16: #include Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: namespace detail Chris@16: { Chris@16: class basic_cv_list_entry; Chris@16: void intrusive_ptr_add_ref(basic_cv_list_entry * p); Chris@16: void intrusive_ptr_release(basic_cv_list_entry * p); Chris@16: Chris@16: class basic_cv_list_entry Chris@16: { Chris@16: private: Chris@16: detail::win32::handle_manager semaphore; Chris@16: detail::win32::handle_manager wake_sem; Chris@16: long waiters; Chris@16: bool notified; Chris@16: long references; Chris@16: Chris@16: public: Chris@16: BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry) Chris@16: explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_): Chris@16: semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)), Chris@16: wake_sem(wake_sem_.duplicate()), Chris@16: waiters(1),notified(false),references(0) Chris@16: {} Chris@16: Chris@16: static bool no_waiters(boost::intrusive_ptr const& entry) Chris@16: { Chris@16: return !detail::interlocked_read_acquire(&entry->waiters); Chris@16: } Chris@16: Chris@16: void add_waiter() Chris@16: { Chris@16: BOOST_INTERLOCKED_INCREMENT(&waiters); Chris@16: } Chris@16: Chris@16: void remove_waiter() Chris@16: { Chris@16: BOOST_INTERLOCKED_DECREMENT(&waiters); Chris@16: } Chris@16: Chris@16: void release(unsigned count_to_release) Chris@16: { Chris@16: notified=true; Chris@16: detail::win32::ReleaseSemaphore(semaphore,count_to_release,0); Chris@16: } Chris@16: Chris@16: void release_waiters() Chris@16: { Chris@16: release(detail::interlocked_read_acquire(&waiters)); Chris@16: } Chris@16: Chris@16: bool is_notified() const Chris@16: { Chris@16: return notified; Chris@16: } Chris@16: Chris@16: bool wait(timeout abs_time) Chris@16: { Chris@16: return this_thread::interruptible_wait(semaphore,abs_time); Chris@16: } Chris@16: Chris@16: bool woken() Chris@16: { Chris@101: unsigned long const woken_result=detail::win32::WaitForSingleObjectEx(wake_sem,0,0); Chris@16: BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0)); Chris@16: return woken_result==0; Chris@16: } Chris@16: Chris@16: friend void intrusive_ptr_add_ref(basic_cv_list_entry * p); Chris@16: friend void intrusive_ptr_release(basic_cv_list_entry * p); Chris@16: }; Chris@16: Chris@16: inline void intrusive_ptr_add_ref(basic_cv_list_entry * p) Chris@16: { Chris@16: BOOST_INTERLOCKED_INCREMENT(&p->references); Chris@16: } Chris@16: Chris@16: inline void intrusive_ptr_release(basic_cv_list_entry * p) Chris@16: { Chris@16: if(!BOOST_INTERLOCKED_DECREMENT(&p->references)) Chris@16: { Chris@16: delete p; Chris@16: } Chris@16: } Chris@16: Chris@16: class basic_condition_variable Chris@16: { Chris@16: boost::mutex internal_mutex; Chris@16: long total_count; Chris@16: unsigned active_generation_count; Chris@16: Chris@16: typedef basic_cv_list_entry list_entry; Chris@16: Chris@16: typedef boost::intrusive_ptr entry_ptr; Chris@16: typedef std::vector generation_list; Chris@16: Chris@16: generation_list generations; Chris@16: detail::win32::handle_manager wake_sem; Chris@16: Chris@16: void wake_waiters(long count_to_wake) Chris@16: { Chris@16: detail::interlocked_write_release(&total_count,total_count-count_to_wake); Chris@16: detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0); Chris@16: } Chris@16: Chris@16: template Chris@16: struct relocker Chris@16: { Chris@16: BOOST_THREAD_NO_COPYABLE(relocker) Chris@16: lock_type& lock; Chris@16: bool unlocked; Chris@16: Chris@16: relocker(lock_type& lock_): Chris@16: lock(lock_),unlocked(false) Chris@16: {} Chris@16: void unlock() Chris@16: { Chris@16: lock.unlock(); Chris@16: unlocked=true; Chris@16: } Chris@16: ~relocker() Chris@16: { Chris@16: if(unlocked) Chris@16: { Chris@16: lock.lock(); Chris@16: } Chris@16: Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: entry_ptr get_wait_entry() Chris@16: { Chris@16: boost::lock_guard internal_lock(internal_mutex); Chris@16: Chris@16: if(!wake_sem) Chris@16: { Chris@16: wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX); Chris@16: BOOST_ASSERT(wake_sem); Chris@16: } Chris@16: Chris@16: detail::interlocked_write_release(&total_count,total_count+1); Chris@16: if(generations.empty() || generations.back()->is_notified()) Chris@16: { Chris@16: entry_ptr new_entry(new list_entry(wake_sem)); Chris@16: generations.push_back(new_entry); Chris@16: return new_entry; Chris@16: } Chris@16: else Chris@16: { Chris@16: generations.back()->add_waiter(); Chris@16: return generations.back(); Chris@16: } Chris@16: } Chris@16: Chris@16: struct entry_manager Chris@16: { Chris@16: entry_ptr const entry; Chris@16: boost::mutex& internal_mutex; Chris@16: Chris@16: BOOST_THREAD_NO_COPYABLE(entry_manager) Chris@16: entry_manager(entry_ptr const& entry_, boost::mutex& mutex_): Chris@16: entry(entry_), internal_mutex(mutex_) Chris@16: {} Chris@16: Chris@16: ~entry_manager() Chris@16: { Chris@16: boost::lock_guard internal_lock(internal_mutex); Chris@16: entry->remove_waiter(); Chris@16: } Chris@16: Chris@16: list_entry* operator->() Chris@16: { Chris@16: return entry.get(); Chris@16: } Chris@16: }; Chris@16: Chris@16: Chris@16: protected: Chris@16: template Chris@16: bool do_wait(lock_type& lock,timeout abs_time) Chris@16: { Chris@16: relocker locker(lock); Chris@16: Chris@16: entry_manager entry(get_wait_entry(), internal_mutex); Chris@16: Chris@16: locker.unlock(); Chris@16: Chris@16: bool woken=false; Chris@16: while(!woken) Chris@16: { Chris@16: if(!entry->wait(abs_time)) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: Chris@16: woken=entry->woken(); Chris@16: } Chris@16: return woken; Chris@16: } Chris@16: Chris@16: template Chris@16: bool do_wait(lock_type& m,timeout const& abs_time,predicate_type pred) Chris@16: { Chris@16: while (!pred()) Chris@16: { Chris@16: if(!do_wait(m, abs_time)) Chris@16: return pred(); Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: basic_condition_variable(const basic_condition_variable& other); Chris@16: basic_condition_variable& operator=(const basic_condition_variable& other); Chris@16: Chris@16: public: Chris@16: basic_condition_variable(): Chris@16: total_count(0),active_generation_count(0),wake_sem(0) Chris@16: {} Chris@16: Chris@16: ~basic_condition_variable() Chris@16: {} Chris@16: Chris@16: void notify_one() BOOST_NOEXCEPT Chris@16: { Chris@16: if(detail::interlocked_read_acquire(&total_count)) Chris@16: { Chris@16: boost::lock_guard internal_lock(internal_mutex); Chris@16: if(!total_count) Chris@16: { Chris@16: return; Chris@16: } Chris@16: wake_waiters(1); Chris@16: Chris@16: for(generation_list::iterator it=generations.begin(), Chris@16: end=generations.end(); Chris@16: it!=end;++it) Chris@16: { Chris@16: (*it)->release(1); Chris@16: } Chris@16: generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end()); Chris@16: } Chris@16: } Chris@16: Chris@16: void notify_all() BOOST_NOEXCEPT Chris@16: { Chris@16: if(detail::interlocked_read_acquire(&total_count)) Chris@16: { Chris@16: boost::lock_guard internal_lock(internal_mutex); Chris@16: if(!total_count) Chris@16: { Chris@16: return; Chris@16: } Chris@16: wake_waiters(total_count); Chris@16: for(generation_list::iterator it=generations.begin(), Chris@16: end=generations.end(); Chris@16: it!=end;++it) Chris@16: { Chris@16: (*it)->release_waiters(); Chris@16: } Chris@16: generations.clear(); Chris@16: wake_sem=detail::win32::handle(0); Chris@16: } Chris@16: } Chris@16: Chris@16: }; Chris@16: } Chris@16: Chris@16: class condition_variable: Chris@16: private detail::basic_condition_variable Chris@16: { Chris@16: public: Chris@16: BOOST_THREAD_NO_COPYABLE(condition_variable) Chris@16: condition_variable() Chris@16: {} Chris@16: Chris@16: using detail::basic_condition_variable::notify_one; Chris@16: using detail::basic_condition_variable::notify_all; Chris@16: Chris@16: void wait(unique_lock& m) Chris@16: { Chris@16: do_wait(m,detail::timeout::sentinel()); Chris@16: } Chris@16: Chris@16: template Chris@16: void wait(unique_lock& m,predicate_type pred) Chris@16: { Chris@16: while(!pred()) wait(m); Chris@16: } Chris@16: Chris@16: Chris@16: #if defined BOOST_THREAD_USES_DATETIME Chris@16: bool timed_wait(unique_lock& m,boost::system_time const& abs_time) Chris@16: { Chris@16: return do_wait(m,abs_time); Chris@16: } Chris@16: Chris@16: bool timed_wait(unique_lock& m,boost::xtime const& abs_time) Chris@16: { Chris@16: return do_wait(m,system_time(abs_time)); Chris@16: } Chris@16: template Chris@16: bool timed_wait(unique_lock& m,duration_type const& wait_duration) Chris@16: { Chris@101: if (wait_duration.is_pos_infinity()) Chris@101: { Chris@101: wait(m); // or do_wait(m,detail::timeout::sentinel()); Chris@101: return true; Chris@101: } Chris@101: if (wait_duration.is_special()) Chris@101: { Chris@101: return true; Chris@101: } Chris@101: return do_wait(m,wait_duration.total_milliseconds()); Chris@16: } Chris@16: Chris@16: template Chris@16: bool timed_wait(unique_lock& m,boost::system_time const& abs_time,predicate_type pred) Chris@16: { Chris@16: return do_wait(m,abs_time,pred); Chris@16: } Chris@16: template Chris@16: bool timed_wait(unique_lock& m,boost::xtime const& abs_time,predicate_type pred) Chris@16: { Chris@16: return do_wait(m,system_time(abs_time),pred); Chris@16: } Chris@16: template Chris@16: bool timed_wait(unique_lock& m,duration_type const& wait_duration,predicate_type pred) Chris@16: { Chris@16: return do_wait(m,wait_duration.total_milliseconds(),pred); Chris@16: } Chris@16: #endif Chris@16: #ifdef BOOST_THREAD_USES_CHRONO Chris@16: Chris@16: template Chris@16: cv_status Chris@16: wait_until( Chris@16: unique_lock& lock, Chris@16: const chrono::time_point& t) Chris@16: { Chris@16: using namespace chrono; Chris@16: chrono::time_point now = Clock::now(); Chris@16: if (t<=now) { Chris@16: return cv_status::timeout; Chris@16: } Chris@16: do_wait(lock, ceil(t-now).count()); Chris@16: return Clock::now() < t ? cv_status::no_timeout : Chris@16: cv_status::timeout; Chris@16: } Chris@16: Chris@16: template Chris@16: cv_status Chris@16: wait_for( Chris@16: unique_lock& lock, Chris@16: const chrono::duration& d) Chris@16: { Chris@16: using namespace chrono; Chris@16: if (d<=chrono::duration::zero()) { Chris@16: return cv_status::timeout; Chris@16: } Chris@16: Chris@16: steady_clock::time_point c_now = steady_clock::now(); Chris@16: do_wait(lock, ceil(d).count()); Chris@16: return steady_clock::now() - c_now < d ? cv_status::no_timeout : Chris@16: cv_status::timeout; Chris@16: } Chris@16: Chris@16: template Chris@16: bool Chris@16: wait_until( Chris@16: unique_lock& lock, Chris@16: const chrono::time_point& t, Chris@16: Predicate pred) Chris@16: { Chris@16: while (!pred()) Chris@16: { Chris@16: if (wait_until(lock, t) == cv_status::timeout) Chris@16: return pred(); Chris@16: } Chris@16: return true; Chris@16: } Chris@16: template Chris@16: bool Chris@16: wait_for( Chris@16: unique_lock& lock, Chris@16: const chrono::duration& d, Chris@16: Predicate pred) Chris@16: { Chris@16: return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); Chris@16: } Chris@16: #endif Chris@16: }; Chris@16: Chris@16: class condition_variable_any: Chris@16: private detail::basic_condition_variable Chris@16: { Chris@16: public: Chris@16: BOOST_THREAD_NO_COPYABLE(condition_variable_any) Chris@16: condition_variable_any() Chris@16: {} Chris@16: Chris@16: using detail::basic_condition_variable::notify_one; Chris@16: using detail::basic_condition_variable::notify_all; Chris@16: Chris@16: template Chris@16: void wait(lock_type& m) Chris@16: { Chris@16: do_wait(m,detail::timeout::sentinel()); Chris@16: } Chris@16: Chris@16: template Chris@16: void wait(lock_type& m,predicate_type pred) Chris@16: { Chris@16: while(!pred()) wait(m); Chris@16: } Chris@16: Chris@16: #if defined BOOST_THREAD_USES_DATETIME Chris@16: template Chris@16: bool timed_wait(lock_type& m,boost::system_time const& abs_time) Chris@16: { Chris@16: return do_wait(m,abs_time); Chris@16: } Chris@16: Chris@16: template Chris@16: bool timed_wait(lock_type& m,boost::xtime const& abs_time) Chris@16: { Chris@16: return do_wait(m,system_time(abs_time)); Chris@16: } Chris@16: Chris@16: template Chris@16: bool timed_wait(lock_type& m,duration_type const& wait_duration) Chris@16: { Chris@16: return do_wait(m,wait_duration.total_milliseconds()); Chris@16: } Chris@16: Chris@16: template Chris@16: bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred) Chris@16: { Chris@16: return do_wait(m,abs_time,pred); Chris@16: } Chris@16: Chris@16: template Chris@16: bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred) Chris@16: { Chris@16: return do_wait(m,system_time(abs_time),pred); Chris@16: } Chris@16: Chris@16: template Chris@16: bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) Chris@16: { Chris@16: return do_wait(m,wait_duration.total_milliseconds(),pred); Chris@16: } Chris@16: #endif Chris@16: #ifdef BOOST_THREAD_USES_CHRONO Chris@16: Chris@16: template Chris@16: cv_status Chris@16: wait_until( Chris@16: lock_type& lock, Chris@16: const chrono::time_point& t) Chris@16: { Chris@16: using namespace chrono; Chris@16: chrono::time_point now = Clock::now(); Chris@16: if (t<=now) { Chris@16: return cv_status::timeout; Chris@16: } Chris@16: do_wait(lock, ceil(t-now).count()); Chris@16: return Clock::now() < t ? cv_status::no_timeout : Chris@16: cv_status::timeout; Chris@16: } Chris@16: Chris@16: template Chris@16: cv_status Chris@16: wait_for( Chris@16: lock_type& lock, Chris@16: const chrono::duration& d) Chris@16: { Chris@16: using namespace chrono; Chris@16: if (d<=chrono::duration::zero()) { Chris@16: return cv_status::timeout; Chris@16: } Chris@16: steady_clock::time_point c_now = steady_clock::now(); Chris@16: do_wait(lock, ceil(d).count()); Chris@16: return steady_clock::now() - c_now < d ? cv_status::no_timeout : Chris@16: cv_status::timeout; Chris@16: } Chris@16: Chris@16: template Chris@16: bool Chris@16: wait_until( Chris@16: lock_type& lock, Chris@16: const chrono::time_point& t, Chris@16: Predicate pred) Chris@16: { Chris@16: while (!pred()) Chris@16: { Chris@16: if (wait_until(lock, t) == cv_status::timeout) Chris@16: return pred(); Chris@16: } Chris@16: return true; Chris@16: } Chris@16: Chris@16: template Chris@16: bool Chris@16: wait_for( Chris@16: lock_type& lock, Chris@16: const chrono::duration& d, Chris@16: Predicate pred) Chris@16: { Chris@16: return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred)); Chris@16: } Chris@16: #endif Chris@16: }; Chris@16: Chris@16: BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); Chris@16: } Chris@16: Chris@16: #include Chris@16: Chris@16: #endif