diff options
Diffstat (limited to 'boost/thread/win32')
-rw-r--r-- | boost/thread/win32/basic_recursive_mutex.hpp | 40 | ||||
-rw-r--r-- | boost/thread/win32/basic_timed_mutex.hpp | 150 | ||||
-rw-r--r-- | boost/thread/win32/condition_variable.hpp | 341 | ||||
-rw-r--r-- | boost/thread/win32/once.hpp | 52 | ||||
-rw-r--r-- | boost/thread/win32/shared_mutex.hpp | 496 | ||||
-rw-r--r-- | boost/thread/win32/thread_data.hpp | 200 | ||||
-rw-r--r-- | boost/thread/win32/thread_heap_alloc.hpp | 6 | ||||
-rw-r--r-- | boost/thread/win32/thread_primitives.hpp | 180 |
8 files changed, 727 insertions, 738 deletions
diff --git a/boost/thread/win32/basic_recursive_mutex.hpp b/boost/thread/win32/basic_recursive_mutex.hpp index 351f9acc71..6913c5bf62 100644 --- a/boost/thread/win32/basic_recursive_mutex.hpp +++ b/boost/thread/win32/basic_recursive_mutex.hpp @@ -4,7 +4,7 @@ // basic_recursive_mutex.hpp // // (C) Copyright 2006-8 Anthony Williams -// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// (C) Copyright 2011-2012,2017-2018 Vicente J. Botet Escriba // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -44,13 +44,13 @@ namespace boost bool try_lock() BOOST_NOEXCEPT { - long const current_thread_id=boost::detail::winapi::GetCurrentThreadId(); + long const current_thread_id=boost::winapi::GetCurrentThreadId(); return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id); } void lock() { - long const current_thread_id=boost::detail::winapi::GetCurrentThreadId(); + long const current_thread_id=boost::winapi::GetCurrentThreadId(); if(!try_recursive_lock(current_thread_id)) { mutex.lock(); @@ -61,29 +61,30 @@ namespace boost #if defined BOOST_THREAD_USES_DATETIME bool timed_lock(::boost::system_time const& target) { - long const current_thread_id=boost::detail::winapi::GetCurrentThreadId(); + long const current_thread_id=boost::winapi::GetCurrentThreadId(); return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target); } template<typename Duration> - bool timed_lock(Duration const& timeout) + bool timed_lock(Duration const& target) { - return timed_lock(get_system_time()+timeout); + long const current_thread_id=boost::detail::winapi::GetCurrentThreadId(); + return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target); } #endif #ifdef BOOST_THREAD_USES_CHRONO - template <class Rep, class Period> - bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) - { + template <class Rep, class Period> + bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) + { long const current_thread_id=boost::detail::winapi::GetCurrentThreadId(); return try_recursive_lock(current_thread_id) || try_timed_lock_for(current_thread_id,rel_time); - } - template <class Clock, class Duration> - bool try_lock_until(const chrono::time_point<Clock, Duration>& t) - { + } + template <class Clock, class Duration> + bool try_lock_until(const chrono::time_point<Clock, Duration>& t) + { long const current_thread_id=boost::detail::winapi::GetCurrentThreadId(); return try_recursive_lock(current_thread_id) || try_timed_lock_until(current_thread_id,t); - } + } #endif void unlock() { @@ -127,6 +128,17 @@ namespace boost } return false; } + template<typename Duration> + bool try_timed_lock(long current_thread_id,Duration const& target) + { + if(mutex.timed_lock(target)) + { + BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id); + recursion_count=1; + return true; + } + return false; + } #endif template <typename TP> bool try_timed_lock_until(long current_thread_id,TP const& target) diff --git a/boost/thread/win32/basic_timed_mutex.hpp b/boost/thread/win32/basic_timed_mutex.hpp index b579d50530..b332dab752 100644 --- a/boost/thread/win32/basic_timed_mutex.hpp +++ b/boost/thread/win32/basic_timed_mutex.hpp @@ -22,6 +22,8 @@ #include <boost/chrono/system_clocks.hpp> #include <boost/chrono/ceil.hpp> #endif +#include <boost/thread/detail/platform_time.hpp> + #include <boost/config/abi_prefix.hpp> namespace boost @@ -59,7 +61,7 @@ namespace boost } } - + // Take the lock flag if it's available bool try_lock() BOOST_NOEXCEPT { return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit); @@ -76,21 +78,21 @@ namespace boost if(old_count&lock_flag_value) { - bool lock_acquired=false; void* const sem=get_event(); do { - unsigned const retval(winapi::WaitForSingleObjectEx(sem, ::boost::detail::win32::infinite,0)); - BOOST_VERIFY(0 == retval || ::boost::detail::win32::wait_abandoned == retval); -// BOOST_VERIFY(winapi::WaitForSingleObject( -// sem,::boost::detail::win32::infinite)==0); - clear_waiting_and_try_lock(old_count); - lock_acquired=!(old_count&lock_flag_value); + if(winapi::WaitForSingleObjectEx(sem,::boost::detail::win32::infinite,0)==0) + { + clear_waiting_and_try_lock(old_count); + } } - while(!lock_acquired); + while(old_count&lock_flag_value); } } + + // Loop until the number of waiters has been incremented or we've taken the lock flag + // The loop is necessary since this function may be called by multiple threads simultaneously void mark_waiting_and_try_lock(long& old_count) { for(;;) @@ -102,12 +104,19 @@ namespace boost { if(was_locked) old_count=new_count; + // else we've taken the lock flag + // don't update old_count so that the calling function can see that + // the old lock flag was 0 and know that we've taken the lock flag break; } old_count=current; } } + // Loop until someone else has taken the lock flag and cleared the event set flag or + // until we've taken the lock flag and cleared the event set flag and decremented the + // number of waiters + // The loop is necessary since this function may be called by multiple threads simultaneously void clear_waiting_and_try_lock(long& old_count) { old_count&=~lock_flag_value; @@ -118,117 +127,124 @@ namespace boost long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count); if(current==old_count) { + // if someone else has taken the lock flag + // no need to update old_count since old_count == new_count (ignoring + // event_set_flag_value which the calling function doesn't care about) + // else we've taken the lock flag + // don't update old_count so that the calling function can see that + // the old lock flag was 0 and know that we've taken the lock flag break; } old_count=current; } } + private: + unsigned long getMs(detail::platform_duration const& d) + { + return static_cast<unsigned long>(d.getMs()); + } + + template <typename Duration> + unsigned long getMs(Duration const& d) + { + return static_cast<unsigned long>(chrono::ceil<chrono::milliseconds>(d).count()); + } -#if defined BOOST_THREAD_USES_DATETIME - bool timed_lock(::boost::system_time const& wait_until) + template <typename Clock, typename Timepoint, typename Duration> + bool do_lock_until(Timepoint const& t, Duration const& max) { if(try_lock()) { return true; } + long old_count=active_count; mark_waiting_and_try_lock(old_count); if(old_count&lock_flag_value) { - bool lock_acquired=false; void* const sem=get_event(); + // If the clock is the system clock, it may jump while this function + // is waiting. To compensate for this and time out near the correct + // time, we call WaitForSingleObjectEx() in a loop with a short + // timeout and recheck the time remaining each time through the loop. do { - if(winapi::WaitForSingleObjectEx(sem,::boost::detail::get_milliseconds_until(wait_until),0)!=0) + Duration d(t - Clock::now()); + if(d <= Duration::zero()) // timeout occurred { BOOST_INTERLOCKED_DECREMENT(&active_count); return false; } - clear_waiting_and_try_lock(old_count); - lock_acquired=!(old_count&lock_flag_value); + if(max != Duration::zero()) + { + d = (std::min)(d, max); + } + if(winapi::WaitForSingleObjectEx(sem,getMs(d),0)==0) + { + clear_waiting_and_try_lock(old_count); + } } - while(!lock_acquired); + while(old_count&lock_flag_value); } return true; } + public: + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(::boost::system_time const& wait_until) + { + const detail::real_platform_timepoint t(wait_until); + return do_lock_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } template<typename Duration> bool timed_lock(Duration const& timeout) { - return timed_lock(get_system_time()+timeout); + const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(timeout)); + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_until<detail::mono_platform_clock>(t, detail::platform_duration::zero()); } bool timed_lock(boost::xtime const& timeout) { - return timed_lock(system_time(timeout)); + return timed_lock(boost::system_time(timeout)); } #endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) { - return try_lock_until(chrono::steady_clock::now() + rel_time); - } - template <class Clock, class Duration> - bool try_lock_until(const chrono::time_point<Clock, Duration>& t) - { - using namespace chrono; - system_clock::time_point s_now = system_clock::now(); - typename Clock::time_point c_now = Clock::now(); - return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now)); + const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time); + typedef typename chrono::duration<Rep, Period> Duration; + typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration; + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_until<chrono::steady_clock>(t, common_duration::zero()); } template <class Duration> - bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t) + bool try_lock_until(const chrono::time_point<chrono::steady_clock, Duration>& t) { - using namespace chrono; - typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt; - return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch()))); + typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration; + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_until<chrono::steady_clock>(t, common_duration::zero()); } - bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp) + template <class Clock, class Duration> + bool try_lock_until(const chrono::time_point<Clock, Duration>& t) { - if(try_lock()) - { - return true; - } - long old_count=active_count; - mark_waiting_and_try_lock(old_count); - - if(old_count&lock_flag_value) - { - bool lock_acquired=false; - void* const sem=get_event(); - - do - { - chrono::time_point<chrono::system_clock, chrono::system_clock::duration> now = chrono::system_clock::now(); - if (tp<=now) { - BOOST_INTERLOCKED_DECREMENT(&active_count); - return false; - } - chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-now); - - if(winapi::WaitForSingleObjectEx(sem,static_cast<unsigned long>(rel_time.count()),0)!=0) - { - BOOST_INTERLOCKED_DECREMENT(&active_count); - return false; - } - clear_waiting_and_try_lock(old_count); - lock_acquired=!(old_count&lock_flag_value); - } - while(!lock_acquired); - } - return true; + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; + return do_lock_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); } #endif void unlock() { - long const offset=lock_flag_value; + // Clear the lock flag using atomic addition (works since long is always 32 bits on Windows) long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value); - if(!(old_count&event_set_flag_value) && (old_count>offset)) + // If someone is waiting to take the lock, set the event set flag and, if + // the event set flag hadn't already been set, send an event. + if(!(old_count&event_set_flag_value) && (old_count>lock_flag_value)) { if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit)) { @@ -238,6 +254,8 @@ namespace boost } private: + // Create an event in a thread-safe way + // The first thread to create the event wins and all other thread will use that event void* get_event() { void* current_event=::boost::detail::interlocked_read_acquire(&event); diff --git a/boost/thread/win32/condition_variable.hpp b/boost/thread/win32/condition_variable.hpp index 5ff342f1fa..5cf975a534 100644 --- a/boost/thread/win32/condition_variable.hpp +++ b/boost/thread/win32/condition_variable.hpp @@ -18,6 +18,7 @@ #include <boost/thread/thread_time.hpp> #include <boost/thread/lock_guard.hpp> #include <boost/thread/lock_types.hpp> +#include <boost/thread/detail/platform_time.hpp> #include <boost/assert.hpp> #include <boost/intrusive_ptr.hpp> @@ -76,7 +77,7 @@ namespace boost void release(unsigned count_to_release) { notified=true; - detail::winapi::ReleaseSemaphore(semaphore,count_to_release,0); + winapi::ReleaseSemaphore(semaphore,count_to_release,0); } void release_waiters() @@ -89,14 +90,14 @@ namespace boost return notified; } - bool wait(timeout abs_time) + bool interruptible_wait(detail::internal_platform_timepoint const &timeout) { - return this_thread::interruptible_wait(semaphore,abs_time); + return this_thread::interruptible_wait(semaphore, timeout); } bool woken() { - unsigned long const woken_result=detail::winapi::WaitForSingleObjectEx(wake_sem,0,0); + unsigned long const woken_result=winapi::WaitForSingleObjectEx(wake_sem,0,0); BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0)); return woken_result==0; } @@ -135,7 +136,7 @@ namespace boost void wake_waiters(long count_to_wake) { detail::interlocked_write_release(&total_count,total_count-count_to_wake); - detail::winapi::ReleaseSemaphore(wake_sem,count_to_wake,0); + winapi::ReleaseSemaphore(wake_sem,count_to_wake,0); } template<typename lock_type> @@ -230,10 +231,29 @@ namespace boost } }; - protected: + basic_condition_variable(const basic_condition_variable& other); + basic_condition_variable& operator=(const basic_condition_variable& other); + + public: + basic_condition_variable(): + total_count(0),active_generation_count(0),wake_sem(0) + {} + + ~basic_condition_variable() + {} + + // When this function returns true: + // * A notification (or sometimes a spurious OS signal) has been received + // * Do not assume that the timeout has not been reached + // * Do not assume that the predicate has been changed + // + // When this function returns false: + // * The timeout has been reached + // * Do not assume that a notification has not been received + // * Do not assume that the predicate has not been changed template<typename lock_type> - bool do_wait(lock_type& lock,timeout abs_time) + bool do_wait_until(lock_type& lock, detail::internal_platform_timepoint const &timeout) { relocker<lock_type> locker(lock); entry_manager entry(get_wait_entry(), internal_mutex); @@ -242,7 +262,7 @@ namespace boost bool woken=false; while(!woken) { - if(!entry->wait(abs_time)) + if(!entry->interruptible_wait(timeout)) { return false; } @@ -252,31 +272,9 @@ namespace boost // do it here to avoid throwing on the destructor entry.remove_waiter_and_reset(); locker.lock(); - return woken; - } - - template<typename lock_type,typename predicate_type> - bool do_wait(lock_type& m,timeout const& abs_time,predicate_type pred) - { - while (!pred()) - { - if(!do_wait(m, abs_time)) - return pred(); - } - return true; + return true; } - basic_condition_variable(const basic_condition_variable& other); - basic_condition_variable& operator=(const basic_condition_variable& other); - - public: - basic_condition_variable(): - total_count(0),active_generation_count(0),wake_sem(0) - {} - - ~basic_condition_variable() - {} - void notify_one() BOOST_NOEXCEPT { if(detail::interlocked_read_acquire(&total_count)) @@ -330,75 +328,115 @@ namespace boost condition_variable() {} + using detail::basic_condition_variable::do_wait_until; using detail::basic_condition_variable::notify_one; using detail::basic_condition_variable::notify_all; void wait(unique_lock<mutex>& m) { - do_wait(m,detail::timeout::sentinel()); + do_wait_until(m, detail::internal_platform_timepoint::getMax()); } template<typename predicate_type> void wait(unique_lock<mutex>& m,predicate_type pred) { - while(!pred()) wait(m); + while (!pred()) + { + wait(m); + } } - #if defined BOOST_THREAD_USES_DATETIME bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time) { - return do_wait(m,abs_time); + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + const detail::real_platform_timepoint ts(abs_time); + const detail::platform_duration d(ts - detail::real_platform_clock::now()); + do_wait_until(m, detail::internal_platform_clock::now() + d); + return ts > detail::real_platform_clock::now(); } - bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time) { - return do_wait(m,system_time(abs_time)); + return timed_wait(m, system_time(abs_time)); } template<typename duration_type> bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration) { - if (wait_duration.is_pos_infinity()) - { - wait(m); // or do_wait(m,detail::timeout::sentinel()); - return true; - } - if (wait_duration.is_special()) - { - return true; - } - return do_wait(m,wait_duration.total_milliseconds()); + if (wait_duration.is_pos_infinity()) + { + wait(m); + return true; + } + if (wait_duration.is_special()) + { + return true; + } + const detail::platform_duration d(wait_duration); + return do_wait_until(m, detail::internal_platform_clock::now() + d); } template<typename predicate_type> bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred) { - return do_wait(m,abs_time,pred); + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + const detail::real_platform_timepoint ts(abs_time); + while (!pred()) + { + detail::platform_duration d(ts - detail::real_platform_clock::now()); + if (d <= detail::platform_duration::zero()) break; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + do_wait_until(m, detail::internal_platform_clock::now() + d); + } + return pred(); } template<typename predicate_type> bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred) { - return do_wait(m,system_time(abs_time),pred); + return timed_wait(m, system_time(abs_time), pred); } template<typename duration_type,typename predicate_type> bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred) { if (wait_duration.is_pos_infinity()) { - while (!pred()) - { - wait(m); // or do_wait(m,detail::timeout::sentinel()); - } - return true; + while (!pred()) + { + wait(m); + } + return true; } if (wait_duration.is_special()) { - return pred(); + return pred(); } - return do_wait(m,wait_duration.total_milliseconds(),pred); + const detail::platform_duration d(wait_duration); + const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d); + while (!pred()) + { + if (!do_wait_until(m, ts)) break; // timeout occurred + } + return pred(); } #endif #ifdef BOOST_THREAD_USES_CHRONO + template <class Duration> + cv_status + wait_until( + unique_lock<mutex>& lock, + const chrono::time_point<detail::internal_chrono_clock, Duration>& t) + { + const detail::internal_platform_timepoint ts(t); + if (do_wait_until(lock, ts)) return cv_status::no_timeout; + else return cv_status::timeout; + } template <class Clock, class Duration> cv_status @@ -406,14 +444,18 @@ namespace boost unique_lock<mutex>& lock, const chrono::time_point<Clock, Duration>& t) { - using namespace chrono; - chrono::time_point<Clock, Duration> now = Clock::now(); - if (t<=now) { - return cv_status::timeout; - } - do_wait(lock, ceil<milliseconds>(t-now).count()); - return Clock::now() < t ? cv_status::no_timeout : - cv_status::timeout; + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; + common_duration d(t - Clock::now()); + do_wait_until(lock, detail::internal_chrono_clock::now() + d); + if (t > Clock::now()) return cv_status::no_timeout; + else return cv_status::timeout; } template <class Rep, class Period> @@ -422,15 +464,22 @@ namespace boost unique_lock<mutex>& lock, const chrono::duration<Rep, Period>& d) { - using namespace chrono; - if (d<=chrono::duration<Rep, Period>::zero()) { - return cv_status::timeout; - } + return wait_until(lock, chrono::steady_clock::now() + d); + } - steady_clock::time_point c_now = steady_clock::now(); - do_wait(lock, ceil<milliseconds>(d).count()); - return steady_clock::now() - c_now < d ? cv_status::no_timeout : - cv_status::timeout; + template <class Duration, class Predicate> + bool + wait_until( + unique_lock<mutex>& lock, + const chrono::time_point<detail::internal_chrono_clock, Duration>& t, + Predicate pred) + { + const detail::internal_platform_timepoint ts(t); + while (!pred()) + { + if (!do_wait_until(lock, ts)) break; // timeout occurred + } + return pred(); } template <class Clock, class Duration, class Predicate> @@ -440,13 +489,20 @@ namespace boost const chrono::time_point<Clock, Duration>& t, Predicate pred) { + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; while (!pred()) { - if (wait_until(lock, t) == cv_status::timeout) - return pred(); + common_duration d(t - Clock::now()); + if (d <= common_duration::zero()) break; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d)); } - return true; + return pred(); } + template <class Rep, class Period, class Predicate> bool wait_for( @@ -467,59 +523,122 @@ namespace boost condition_variable_any() {} + using detail::basic_condition_variable::do_wait_until; using detail::basic_condition_variable::notify_one; using detail::basic_condition_variable::notify_all; template<typename lock_type> void wait(lock_type& m) { - do_wait(m,detail::timeout::sentinel()); + do_wait_until(m, detail::internal_platform_timepoint::getMax()); } template<typename lock_type,typename predicate_type> void wait(lock_type& m,predicate_type pred) { - while(!pred()) wait(m); + while (!pred()) + { + wait(m); + } } #if defined BOOST_THREAD_USES_DATETIME template<typename lock_type> bool timed_wait(lock_type& m,boost::system_time const& abs_time) { - return do_wait(m,abs_time); + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + const detail::real_platform_timepoint ts(abs_time); + const detail::platform_duration d(ts - detail::real_platform_clock::now()); + do_wait_until(m, detail::internal_platform_clock::now() + d); + return ts > detail::real_platform_clock::now(); } template<typename lock_type> bool timed_wait(lock_type& m,boost::xtime const& abs_time) { - return do_wait(m,system_time(abs_time)); + return timed_wait(m, system_time(abs_time)); } template<typename lock_type,typename duration_type> bool timed_wait(lock_type& m,duration_type const& wait_duration) { - return do_wait(m,wait_duration.total_milliseconds()); + if (wait_duration.is_pos_infinity()) + { + wait(m); + return true; + } + if (wait_duration.is_special()) + { + return true; + } + const detail::platform_duration d(wait_duration); + return do_wait_until(m, detail::internal_platform_clock::now() + d); } template<typename lock_type,typename predicate_type> bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred) { - return do_wait(m,abs_time,pred); + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + const detail::real_platform_timepoint ts(abs_time); + while (!pred()) + { + detail::platform_duration d(ts - detail::real_platform_clock::now()); + if (d <= detail::platform_duration::zero()) break; // timeout occurred + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + do_wait_until(m, detail::internal_platform_clock::now() + d); + } + return pred(); } template<typename lock_type,typename predicate_type> bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred) { - return do_wait(m,system_time(abs_time),pred); + return timed_wait(m, system_time(abs_time), pred); } template<typename lock_type,typename duration_type,typename predicate_type> bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred) { - return do_wait(m,wait_duration.total_milliseconds(),pred); + if (wait_duration.is_pos_infinity()) + { + while (!pred()) + { + wait(m); + } + return true; + } + if (wait_duration.is_special()) + { + return pred(); + } + const detail::platform_duration d(wait_duration); + const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d); + while (!pred()) + { + if (!do_wait_until(m, ts)) break; // timeout occurred + } + return pred(); } #endif #ifdef BOOST_THREAD_USES_CHRONO + template <class lock_type,class Duration> + cv_status + wait_until( + lock_type& lock, + const chrono::time_point<detail::internal_chrono_clock, Duration>& t) + { + const detail::internal_platform_timepoint ts(t); + if (do_wait_until(lock, ts)) return cv_status::no_timeout; + else return cv_status::timeout; + } template <class lock_type, class Clock, class Duration> cv_status @@ -527,14 +646,18 @@ namespace boost lock_type& lock, const chrono::time_point<Clock, Duration>& t) { - using namespace chrono; - chrono::time_point<Clock, Duration> now = Clock::now(); - if (t<=now) { - return cv_status::timeout; - } - do_wait(lock, ceil<milliseconds>(t-now).count()); - return Clock::now() < t ? cv_status::no_timeout : - cv_status::timeout; + // The system time may jump while this function is waiting. To compensate for this and time + // out near the correct time, we could call do_wait_until() in a loop with a short timeout + // and recheck the time remaining each time through the loop. However, because we can't + // check the predicate each time do_wait_until() completes, this introduces the possibility + // of not exiting the function when a notification occurs, since do_wait_until() may report + // that it timed out even though a notification was received. The best this function can do + // is report correctly whether or not it reached the timeout time. + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; + common_duration d(t - Clock::now()); + do_wait_until(lock, detail::internal_chrono_clock::now() + d); + if (t > Clock::now()) return cv_status::no_timeout; + else return cv_status::timeout; } template <class lock_type, class Rep, class Period> @@ -543,14 +666,22 @@ namespace boost lock_type& lock, const chrono::duration<Rep, Period>& d) { - using namespace chrono; - if (d<=chrono::duration<Rep, Period>::zero()) { - return cv_status::timeout; - } - steady_clock::time_point c_now = steady_clock::now(); - do_wait(lock, ceil<milliseconds>(d).count()); - return steady_clock::now() - c_now < d ? cv_status::no_timeout : - cv_status::timeout; + return wait_until(lock, chrono::steady_clock::now() + d); + } + + template <class lock_type, class Clock, class Duration, class Predicate> + bool + wait_until( + lock_type& lock, + const chrono::time_point<detail::internal_chrono_clock, Duration>& t, + Predicate pred) + { + const detail::internal_platform_timepoint ts(t); + while (!pred()) + { + if (!do_wait_until(lock, ts)) break; // timeout occurred + } + return pred(); } template <class lock_type, class Clock, class Duration, class Predicate> @@ -560,12 +691,18 @@ namespace boost const chrono::time_point<Clock, Duration>& t, Predicate pred) { + // The system time may jump while this function is waiting. To compensate for this + // and time out near the correct time, we call do_wait_until() in a loop with a + // short timeout and recheck the time remaining each time through the loop. + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; while (!pred()) { - if (wait_until(lock, t) == cv_status::timeout) - return pred(); + common_duration d(t - Clock::now()); + if (d <= common_duration::zero()) break; // timeout occurred + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + do_wait_until(lock, detail::internal_platform_clock::now() + detail::platform_duration(d)); } - return true; + return pred(); } template <class lock_type, class Rep, class Period, class Predicate> diff --git a/boost/thread/win32/once.hpp b/boost/thread/win32/once.hpp index e7c565fbfa..3c515bae7d 100644 --- a/boost/thread/win32/once.hpp +++ b/boost/thread/win32/once.hpp @@ -136,9 +136,9 @@ namespace boost } #ifdef BOOST_NO_ANSI_APIS - return ::boost::detail::winapi::OpenEventW( + return ::boost::winapi::OpenEventW( #else - return ::boost::detail::winapi::OpenEventA( + return ::boost::winapi::OpenEventA( #endif ::boost::detail::win32::synchronize | ::boost::detail::win32::event_modify_state, @@ -186,7 +186,7 @@ namespace boost } if(ctx.event_handle) { - ::boost::detail::winapi::ResetEvent(ctx.event_handle); + ::boost::winapi::ResetEvent(ctx.event_handle); } return true; } @@ -207,7 +207,7 @@ namespace boost } if(ctx.event_handle) { - ::boost::detail::winapi::SetEvent(ctx.event_handle); + ::boost::winapi::SetEvent(ctx.event_handle); } } inline void rollback_once_region(once_flag& flag, once_context& ctx) BOOST_NOEXCEPT @@ -219,13 +219,13 @@ namespace boost } if(ctx.event_handle) { - ::boost::detail::winapi::SetEvent(ctx.event_handle); + ::boost::winapi::SetEvent(ctx.event_handle); } } } #if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) -//#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) +//#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR) inline void call_once(once_flag& flag, void (*f)()) { // Try for a quick win: if the procedure has already been called @@ -264,7 +264,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite, 0)); } } @@ -308,7 +308,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -355,7 +355,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -400,7 +400,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -443,7 +443,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -486,7 +486,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -529,7 +529,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -574,7 +574,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -617,7 +617,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -660,7 +660,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -703,13 +703,13 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } #endif #if 1 -#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR) inline void call_once(once_flag& flag, void (*f)()) { // Try for a quick win: if the procedure has already been called @@ -748,7 +748,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -793,7 +793,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -839,7 +839,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -886,7 +886,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -930,7 +930,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -977,7 +977,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -1024,7 +1024,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } @@ -1073,7 +1073,7 @@ namespace boost continue; } } - BOOST_VERIFY(!::boost::detail::winapi::WaitForSingleObjectEx( + BOOST_VERIFY(!::boost::winapi::WaitForSingleObjectEx( ctx.event_handle,::boost::detail::win32::infinite,0)); } } diff --git a/boost/thread/win32/shared_mutex.hpp b/boost/thread/win32/shared_mutex.hpp index d1bd971770..76ee2579b3 100644 --- a/boost/thread/win32/shared_mutex.hpp +++ b/boost/thread/win32/shared_mutex.hpp @@ -2,7 +2,7 @@ #define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP // (C) Copyright 2006-8 Anthony Williams -// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// (C) Copyright 2011-2012,2017-2018 Vicente J. Botet Escriba // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -19,6 +19,7 @@ #include <boost/chrono/ceil.hpp> #endif #include <boost/thread/detail/delete.hpp> +#include <boost/thread/detail/platform_time.hpp> #include <boost/config/abi_prefix.hpp> @@ -29,7 +30,7 @@ namespace boost private: struct state_data { - unsigned shared_count:11, + unsigned long shared_count:11, shared_waiting:11, exclusive:1, upgrade:1, @@ -38,19 +39,16 @@ namespace boost friend bool operator==(state_data const& lhs,state_data const& rhs) { - return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs); + return *reinterpret_cast<unsigned long const*>(&lhs)==*reinterpret_cast<unsigned long const*>(&rhs); } }; - - template<typename T> - T interlocked_compare_exchange(T* target,T new_value,T comparand) + state_data interlocked_compare_exchange(state_data* target, state_data new_value, state_data comparand) { - BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long)); long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target), *reinterpret_cast<long*>(&new_value), *reinterpret_cast<long*>(&comparand)); - return *reinterpret_cast<T const*>(&res); + return *reinterpret_cast<state_data const*>(&res); } enum @@ -67,19 +65,19 @@ namespace boost { if(old_state.exclusive_waiting) { - BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0); + BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0); } if(old_state.shared_waiting || old_state.exclusive_waiting) { - BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); + BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); } } void release_shared_waiters(state_data old_state) { if(old_state.shared_waiting || old_state.exclusive_waiting) { - BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); + BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0); } } @@ -107,9 +105,9 @@ namespace boost ~shared_mutex() { - detail::winapi::CloseHandle(upgrade_sem); - detail::winapi::CloseHandle(semaphores[unlock_sem]); - detail::winapi::CloseHandle(semaphores[exclusive_sem]); + winapi::CloseHandle(upgrade_sem); + winapi::CloseHandle(semaphores[unlock_sem]); + winapi::CloseHandle(semaphores[exclusive_sem]); } bool try_lock_shared() @@ -139,21 +137,60 @@ namespace boost void lock_shared() { + for(;;) + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.exclusive || new_state.exclusive_waiting_blocked) + { + ++new_state.shared_waiting; + if(!new_state.shared_waiting) + { + boost::throw_exception(boost::lock_error()); + } + } + else + { + ++new_state.shared_count; + if(!new_state.shared_count) + { + boost::throw_exception(boost::lock_error()); + } + } -#if defined BOOST_THREAD_USES_DATETIME - BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel())); -#else - BOOST_VERIFY(try_lock_shared_until(chrono::steady_clock::now())); -#endif + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) + { + return; + } + + BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::win32::infinite,0)==0); + } } -#if defined BOOST_THREAD_USES_DATETIME - template<typename TimeDuration> - bool timed_lock_shared(TimeDuration const & relative_time) + private: + unsigned long getMs(detail::platform_duration const& d) { - return timed_lock_shared(get_system_time()+relative_time); + return static_cast<unsigned long>(d.getMs()); } - bool timed_lock_shared(boost::system_time const& wait_until) + + template <typename Duration> + unsigned long getMs(Duration const& d) + { + return static_cast<unsigned long>(chrono::ceil<chrono::milliseconds>(d).count()); + } + + template <typename Clock, typename Timepoint, typename Duration> + bool do_lock_shared_until(Timepoint const& t, Duration const& max) { for(;;) { @@ -191,7 +228,30 @@ namespace boost return true; } - unsigned long const res=detail::winapi::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until), 0); + // If the clock is the system clock, it may jump while this function + // is waiting. To compensate for this and time out near the correct + // time, we call WaitForSingleObjectEx() in a loop with a short + // timeout and recheck the time remaining each time through the loop. + unsigned long res=0; + for(;;) + { + Duration d(t - Clock::now()); + if(d <= Duration::zero()) // timeout occurred + { + res=detail::win32::timeout; + break; + } + if(max != Duration::zero()) + { + d = (std::min)(d, max); + } + res=winapi::WaitForSingleObjectEx(semaphores[unlock_sem],getMs(d),0); + if(res!=detail::win32::timeout) // semaphore released + { + break; + } + } + if(res==detail::win32::timeout) { for(;;) @@ -231,114 +291,45 @@ namespace boost BOOST_ASSERT(res==0); } } + public: + +#if defined BOOST_THREAD_USES_DATETIME + template<typename TimeDuration> + bool timed_lock_shared(TimeDuration const & relative_time) + { + const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time)); + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_shared_until<detail::mono_platform_clock>(t, detail::platform_duration::zero()); + } + bool timed_lock_shared(boost::system_time const& wait_until) + { + const detail::real_platform_timepoint t(wait_until); + return do_lock_shared_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } #endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time) { - return try_lock_shared_until(chrono::steady_clock::now() + rel_time); - } - template <class Clock, class Duration> - bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t) - { - using namespace chrono; - system_clock::time_point s_now = system_clock::now(); - typename Clock::time_point c_now = Clock::now(); - return try_lock_shared_until(s_now + ceil<system_clock::duration>(t - c_now)); + const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time); + typedef typename chrono::duration<Rep, Period> Duration; + typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration; + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero()); } template <class Duration> - bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, Duration>& t) + bool try_lock_shared_until(const chrono::time_point<chrono::steady_clock, Duration>& t) { - using namespace chrono; - typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt; - return try_lock_shared_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch()))); + typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration; + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_shared_until<chrono::steady_clock>(t, common_duration::zero()); } - bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp) + template <class Clock, class Duration> + bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t) { - for(;;) - { - state_data old_state=state; - for(;;) - { - state_data new_state=old_state; - if(new_state.exclusive || new_state.exclusive_waiting_blocked) - { - ++new_state.shared_waiting; - if(!new_state.shared_waiting) - { - boost::throw_exception(boost::lock_error()); - } - } - else - { - ++new_state.shared_count; - if(!new_state.shared_count) - { - boost::throw_exception(boost::lock_error()); - } - } - - state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); - if(current_state==old_state) - { - break; - } - old_state=current_state; - } - - if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) - { - return true; - } - - chrono::system_clock::time_point n = chrono::system_clock::now(); - unsigned long res; - if (tp>n) { - chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-n); - res=detail::winapi::WaitForSingleObjectEx(semaphores[unlock_sem], - static_cast<unsigned long>(rel_time.count()), 0); - } else { - res=detail::win32::timeout; - } - if(res==detail::win32::timeout) - { - for(;;) - { - state_data new_state=old_state; - if(new_state.exclusive || new_state.exclusive_waiting_blocked) - { - if(new_state.shared_waiting) - { - --new_state.shared_waiting; - } - } - else - { - ++new_state.shared_count; - if(!new_state.shared_count) - { - return false; - } - } - - state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); - if(current_state==old_state) - { - break; - } - old_state=current_state; - } - - if(!(old_state.exclusive| old_state.exclusive_waiting_blocked)) - { - return true; - } - return false; - } - - BOOST_ASSERT(res==0); - } + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; + return do_lock_shared_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); } #endif @@ -375,7 +366,7 @@ namespace boost { if(old_state.upgrade) { - BOOST_VERIFY(detail::winapi::ReleaseSemaphore(upgrade_sem,1,0)!=0); + BOOST_VERIFY(winapi::ReleaseSemaphore(upgrade_sem,1,0)!=0); } else { @@ -388,24 +379,6 @@ namespace boost } } - void lock() - { - -#if defined BOOST_THREAD_USES_DATETIME - BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel())); -#else - BOOST_VERIFY(try_lock_until(chrono::steady_clock::now())); -#endif - } - -#if defined BOOST_THREAD_USES_DATETIME - template<typename TimeDuration> - bool timed_lock(TimeDuration const & relative_time) - { - return timed_lock(get_system_time()+relative_time); - } -#endif - bool try_lock() { state_data old_state=state; @@ -431,14 +404,11 @@ namespace boost return true; } - -#if defined BOOST_THREAD_USES_DATETIME - bool timed_lock(boost::system_time const& wait_until) + void lock() { for(;;) { state_data old_state=state; - for(;;) { state_data new_state=old_state; @@ -467,14 +437,86 @@ namespace boost if(!old_state.shared_count && !old_state.exclusive) { - return true; + return; } + #ifndef UNDER_CE const bool wait_all = true; #else const bool wait_all = false; #endif - unsigned long const wait_res=detail::winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until), 0); + BOOST_VERIFY(winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::win32::infinite,0)<2); + } + } + + private: + template <typename Clock, typename Timepoint, typename Duration> + bool do_lock_until(Timepoint const& t, Duration const& max) + { + for(;;) + { + state_data old_state=state; + for(;;) + { + state_data new_state=old_state; + if(new_state.shared_count || new_state.exclusive) + { + ++new_state.exclusive_waiting; + if(!new_state.exclusive_waiting) + { + boost::throw_exception(boost::lock_error()); + } + + new_state.exclusive_waiting_blocked=true; + } + else + { + new_state.exclusive=true; + } + + state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); + if(current_state==old_state) + { + break; + } + old_state=current_state; + } + + if(!old_state.shared_count && !old_state.exclusive) + { + return true; + } + + // If the clock is the system clock, it may jump while this function + // is waiting. To compensate for this and time out near the correct + // time, we call WaitForMultipleObjectsEx() in a loop with a short + // timeout and recheck the time remaining each time through the loop. + unsigned long wait_res=0; + for(;;) + { + Duration d(t - Clock::now()); + if(d <= Duration::zero()) // timeout occurred + { + wait_res=detail::win32::timeout; + break; + } + if(max != Duration::zero()) + { + d = (std::min)(d, max); + } + #ifndef UNDER_CE + wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,true,getMs(d),0); + #else + wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,false,getMs(d),0); + #endif + //wait_res=winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all,getMs(d), 0); + + if(wait_res!=detail::win32::timeout) // semaphore released + { + break; + } + } + if(wait_res==detail::win32::timeout) { for(;;) @@ -500,7 +542,7 @@ namespace boost state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); if (must_notify) { - BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0); + BOOST_VERIFY(winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0); } if(current_state==old_state) @@ -515,123 +557,48 @@ namespace boost } return false; } + BOOST_ASSERT(wait_res<2); } } + public: + +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(boost::system_time const& wait_until) + { + const detail::real_platform_timepoint t(wait_until); + return do_lock_until<detail::real_platform_clock>(t, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + } + template<typename TimeDuration> + bool timed_lock(TimeDuration const & relative_time) + { + const detail::mono_platform_timepoint t(detail::mono_platform_clock::now() + detail::platform_duration(relative_time)); + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_until<detail::mono_platform_clock>(t, detail::platform_duration::zero()); + } #endif #ifdef BOOST_THREAD_USES_CHRONO template <class Rep, class Period> bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) { - return try_lock_until(chrono::steady_clock::now() + rel_time); - } - template <class Clock, class Duration> - bool try_lock_until(const chrono::time_point<Clock, Duration>& t) - { - using namespace chrono; - system_clock::time_point s_now = system_clock::now(); - typename Clock::time_point c_now = Clock::now(); - return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now)); + const chrono::steady_clock::time_point t(chrono::steady_clock::now() + rel_time); + typedef typename chrono::duration<Rep, Period> Duration; + typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration; + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_until<chrono::steady_clock>(t, common_duration::zero()); } template <class Duration> - bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t) + bool try_lock_until(const chrono::time_point<chrono::steady_clock, Duration>& t) { - using namespace chrono; - typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt; - return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch()))); + typedef typename common_type<Duration, typename chrono::steady_clock::duration>::type common_duration; + // The reference clock is steady and so no need to poll periodically, thus 0 ms max (i.e. no max) + return do_lock_until<chrono::steady_clock>(t, common_duration::zero()); } - bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp) + template <class Clock, class Duration> + bool try_lock_until(const chrono::time_point<Clock, Duration>& t) { - for(;;) - { - state_data old_state=state; - - for(;;) - { - state_data new_state=old_state; - if(new_state.shared_count || new_state.exclusive) - { - ++new_state.exclusive_waiting; - if(!new_state.exclusive_waiting) - { - boost::throw_exception(boost::lock_error()); - } - - new_state.exclusive_waiting_blocked=true; - } - else - { - new_state.exclusive=true; - } - - state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); - if(current_state==old_state) - { - break; - } - old_state=current_state; - } - - if(!old_state.shared_count && !old_state.exclusive) - { - return true; - } - #ifndef UNDER_CE - const bool wait_all = true; - #else - const bool wait_all = false; - #endif - - chrono::system_clock::time_point n = chrono::system_clock::now(); - unsigned long wait_res; - if (tp>n) { - chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now()); - wait_res=detail::winapi::WaitForMultipleObjectsEx(2,semaphores,wait_all, - static_cast<unsigned long>(rel_time.count()), 0); - } else { - wait_res=detail::win32::timeout; - } - if(wait_res==detail::win32::timeout) - { - for(;;) - { - bool must_notify = false; - state_data new_state=old_state; - if(new_state.shared_count || new_state.exclusive) - { - if(new_state.exclusive_waiting) - { - if(!--new_state.exclusive_waiting) - { - new_state.exclusive_waiting_blocked=false; - must_notify = true; - } - } - } - else - { - new_state.exclusive=true; - } - - state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state); - if (must_notify) - { - BOOST_VERIFY(detail::winapi::ReleaseSemaphore(semaphores[unlock_sem],1,0)!=0); - } - if(current_state==old_state) - { - break; - } - old_state=current_state; - } - if(!old_state.shared_count && !old_state.exclusive) - { - return true; - } - return false; - } - BOOST_ASSERT(wait_res<2); - } + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; + return do_lock_until<Clock>(t, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); } #endif @@ -698,7 +665,7 @@ namespace boost return; } - BOOST_VERIFY(!detail::winapi::WaitForSingleObjectEx(semaphores[unlock_sem],detail::winapi::infinite, 0)); + BOOST_VERIFY(winapi::WaitForSingleObjectEx(semaphores[unlock_sem],winapi::infinite,0)==0); } } @@ -790,7 +757,7 @@ namespace boost { if(!last_reader) { - BOOST_VERIFY(!detail::winapi::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite, 0)); + BOOST_VERIFY(winapi::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite,0)==0); } break; } @@ -823,27 +790,6 @@ namespace boost } release_waiters(old_state); } -// bool try_unlock_upgrade_and_lock() -// { -// return false; -// } -//#ifdef BOOST_THREAD_USES_CHRONO -// template <class Rep, class Period> -// bool -// try_unlock_upgrade_and_lock_for( -// const chrono::duration<Rep, Period>& rel_time) -// { -// return try_unlock_upgrade_and_lock_until( -// chrono::steady_clock::now() + rel_time); -// } -// template <class Clock, class Duration> -// bool -// try_unlock_upgrade_and_lock_until( -// const chrono::time_point<Clock, Duration>& abs_time) -// { -// return false; -// } -//#endif void unlock_and_lock_shared() { diff --git a/boost/thread/win32/thread_data.hpp b/boost/thread/win32/thread_data.hpp index ed74198fbe..f87889efa7 100644 --- a/boost/thread/win32/thread_data.hpp +++ b/boost/thread/win32/thread_data.hpp @@ -10,6 +10,7 @@ #include <boost/thread/thread_time.hpp> #include <boost/thread/win32/thread_primitives.hpp> #include <boost/thread/win32/thread_heap_alloc.hpp> +#include <boost/thread/detail/platform_time.hpp> #include <boost/predef/platform.h> @@ -153,7 +154,7 @@ namespace boost #if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void interrupt() { - BOOST_VERIFY(detail::winapi::SetEvent(interruption_handle)!=0); + BOOST_VERIFY(winapi::SetEvent(interruption_handle)!=0); } #endif typedef detail::win32::handle native_handle_type; @@ -174,146 +175,111 @@ namespace boost BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr; - - struct BOOST_SYMBOL_VISIBLE timeout - { - win32::ticks_type start; - uintmax_t milliseconds; - bool relative; - boost::system_time abs_time; - - static unsigned long const max_non_infinite_wait=0xfffffffe; - - timeout(uintmax_t milliseconds_): - start(win32::GetTickCount64_()()), - milliseconds(milliseconds_), - relative(true) - //, - // abs_time(boost::get_system_time()) - {} - - timeout(boost::system_time const& abs_time_): - start(win32::GetTickCount64_()()), - milliseconds(0), - relative(false), - abs_time(abs_time_) - {} - - struct BOOST_SYMBOL_VISIBLE remaining_time - { - bool more; - unsigned long milliseconds; - - remaining_time(uintmax_t remaining): - more(remaining>max_non_infinite_wait), - milliseconds(more?max_non_infinite_wait:(unsigned long)remaining) - {} - }; - - remaining_time remaining_milliseconds() const - { - if(is_sentinel()) - { - return remaining_time(win32::infinite); - } - else if(relative) - { - win32::ticks_type const now=win32::GetTickCount64_()(); - win32::ticks_type const elapsed=now-start; - return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0); - } - else - { - system_time const now=get_system_time(); - if(abs_time<=now) - { - return remaining_time(0); - } - return remaining_time((abs_time-now).total_milliseconds()+1); - } - } - - bool is_sentinel() const - { - return milliseconds==~uintmax_t(0); - } - - - static timeout sentinel() - { - return timeout(sentinel_type()); - } - private: - struct sentinel_type - {}; - - explicit timeout(sentinel_type): - start(0),milliseconds(~uintmax_t(0)),relative(true) - {} - }; - - inline uintmax_t pin_to_zero(intmax_t value) - { - return (value<0)?0u:(uintmax_t)value; - } } namespace this_thread { void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; - bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time); - inline void interruptible_wait(uintmax_t milliseconds) + bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout); + +#if defined BOOST_THREAD_USES_DATETIME + template<typename TimeDuration> + BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) { - interruptible_wait(detail::win32::invalid_handle_value,milliseconds); + interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(rel_time)); } - inline BOOST_SYMBOL_VISIBLE void interruptible_wait(system_time const& abs_time) + + inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time) { - interruptible_wait(detail::win32::invalid_handle_value,abs_time); + const detail::real_platform_timepoint ts(abs_time); + detail::platform_duration d(ts - detail::real_platform_clock::now()); + while (d > detail::platform_duration::zero()) + { + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + d); + d = ts - detail::real_platform_clock::now(); + } } - template<typename TimeDuration> - inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + void sleep_for(const chrono::duration<Rep, Period>& d) { - interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds())); + interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(d)); } - inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time) + + template <class Duration> + void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t) { - interruptible_wait(abs_time); + sleep_for(t - chrono::steady_clock::now()); } -// #11322 sleep_for() nanoseconds overload will always return too early on windows -//#ifdef BOOST_THREAD_USES_CHRONO -// inline void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) -// { -// interruptible_wait(chrono::duration_cast<chrono::milliseconds>(ns).count()); -// } -//#endif + + template <class Clock, class Duration> + void sleep_until(const chrono::time_point<Clock, Duration>& t) + { + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; + common_duration d(t - Clock::now()); + while (d > common_duration::zero()) + { + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + sleep_for(d); + d = t - Clock::now(); + } + } +#endif + namespace no_interruption_point { - bool BOOST_THREAD_DECL non_interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time); - inline void non_interruptible_wait(uintmax_t milliseconds) + bool BOOST_THREAD_DECL non_interruptible_wait(detail::win32::handle handle_to_wait_for, detail::internal_platform_timepoint const &timeout); + +#if defined BOOST_THREAD_USES_DATETIME + template<typename TimeDuration> + BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) { - non_interruptible_wait(detail::win32::invalid_handle_value,milliseconds); + non_interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(rel_time)); } - inline BOOST_SYMBOL_VISIBLE void non_interruptible_wait(system_time const& abs_time) + + inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time) { - non_interruptible_wait(detail::win32::invalid_handle_value,abs_time); + const detail::real_platform_timepoint ts(abs_time); + detail::platform_duration d(ts - detail::real_platform_clock::now()); + while (d > detail::platform_duration::zero()) + { + d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); + non_interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + d); + d = ts - detail::real_platform_clock::now(); + } } - template<typename TimeDuration> - inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) +#endif + +#ifdef BOOST_THREAD_USES_CHRONO + template <class Rep, class Period> + void sleep_for(const chrono::duration<Rep, Period>& d) { - non_interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds())); + non_interruptible_wait(detail::win32::invalid_handle_value, detail::internal_platform_clock::now() + detail::platform_duration(d)); } - inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time) + + template <class Duration> + void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t) { - non_interruptible_wait(abs_time); + sleep_for(t - chrono::steady_clock::now()); } -// #11322 sleep_for() nanoseconds overload will always return too early on windows -//#ifdef BOOST_THREAD_USES_CHRONO -// inline void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) -// { -// non_interruptible_wait(chrono::duration_cast<chrono::milliseconds>(ns).count()); -// } -//#endif + + template <class Clock, class Duration> + void sleep_until(const chrono::time_point<Clock, Duration>& t) + { + typedef typename common_type<Duration, typename Clock::duration>::type common_duration; + common_duration d(t - Clock::now()); + while (d > common_duration::zero()) + { + d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); + sleep_for(d); + d = t - Clock::now(); + } + } +#endif } } diff --git a/boost/thread/win32/thread_heap_alloc.hpp b/boost/thread/win32/thread_heap_alloc.hpp index 96621355c5..176d269e05 100644 --- a/boost/thread/win32/thread_heap_alloc.hpp +++ b/boost/thread/win32/thread_heap_alloc.hpp @@ -12,7 +12,7 @@ #include <boost/throw_exception.hpp> #include <boost/core/no_exceptions_support.hpp> -#include <boost/detail/winapi/heap_memory.hpp> +#include <boost/winapi/heap_memory.hpp> #include <boost/config/abi_prefix.hpp> @@ -22,7 +22,7 @@ namespace boost { inline void* allocate_raw_heap_memory(unsigned size) { - void* const heap_memory=detail::winapi::HeapAlloc(detail::winapi::GetProcessHeap(),0,size); + void* const heap_memory=winapi::HeapAlloc(winapi::GetProcessHeap(),0,size); if(!heap_memory) { boost::throw_exception(std::bad_alloc()); @@ -32,7 +32,7 @@ namespace boost inline void free_raw_heap_memory(void* heap_memory) { - BOOST_VERIFY(detail::winapi::HeapFree(detail::winapi::GetProcessHeap(),0,heap_memory)!=0); + BOOST_VERIFY(winapi::HeapFree(winapi::GetProcessHeap(),0,heap_memory)!=0); } #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) && ! defined (BOOST_NO_CXX11_RVALUE_REFERENCES) template<typename T,typename... Args> diff --git a/boost/thread/win32/thread_primitives.hpp b/boost/thread/win32/thread_primitives.hpp index f93cc2438e..5e378f7664 100644 --- a/boost/thread/win32/thread_primitives.hpp +++ b/boost/thread/win32/thread_primitives.hpp @@ -16,23 +16,22 @@ #include <boost/assert.hpp> #include <boost/thread/exceptions.hpp> #include <boost/detail/interlocked.hpp> -#include <boost/detail/winapi/config.hpp> - -#include <boost/detail/winapi/semaphore.hpp> -#include <boost/detail/winapi/dll.hpp> -#include <boost/detail/winapi/system.hpp> -#include <boost/detail/winapi/time.hpp> -#include <boost/detail/winapi/event.hpp> -#include <boost/detail/winapi/thread.hpp> -#include <boost/detail/winapi/get_current_thread.hpp> -#include <boost/detail/winapi/get_current_thread_id.hpp> -#include <boost/detail/winapi/get_current_process.hpp> -#include <boost/detail/winapi/get_current_process_id.hpp> -#include <boost/detail/winapi/wait.hpp> -#include <boost/detail/winapi/handles.hpp> -#include <boost/detail/winapi/access_rights.hpp> - -//#include <boost/detail/winapi/synchronization.hpp> + +#include <boost/winapi/config.hpp> +#include <boost/winapi/basic_types.hpp> +#include <boost/winapi/semaphore.hpp> +#include <boost/winapi/system.hpp> +#include <boost/winapi/event.hpp> +#include <boost/winapi/thread.hpp> +#include <boost/winapi/get_current_thread.hpp> +#include <boost/winapi/get_current_thread_id.hpp> +#include <boost/winapi/get_current_process.hpp> +#include <boost/winapi/get_current_process_id.hpp> +#include <boost/winapi/wait.hpp> +#include <boost/winapi/handles.hpp> +#include <boost/winapi/access_rights.hpp> + +//#include <boost/winapi/synchronization.hpp> #include <boost/thread/win32/interlocked_read.hpp> #include <algorithm> @@ -46,20 +45,19 @@ namespace boost { namespace win32 { - typedef ::boost::detail::winapi::HANDLE_ handle; - typedef ::boost::detail::winapi::SYSTEM_INFO_ system_info; - typedef unsigned __int64 ticks_type; - typedef ::boost::detail::winapi::FARPROC_ farproc_t; - unsigned const infinite=::boost::detail::winapi::INFINITE_; - unsigned const timeout=::boost::detail::winapi::WAIT_TIMEOUT_; - handle const invalid_handle_value=::boost::detail::winapi::INVALID_HANDLE_VALUE_; - unsigned const event_modify_state=::boost::detail::winapi::EVENT_MODIFY_STATE_; - unsigned const synchronize=::boost::detail::winapi::SYNCHRONIZE_; - unsigned const wait_abandoned=::boost::detail::winapi::WAIT_ABANDONED_; + typedef ::boost::winapi::HANDLE_ handle; + typedef ::boost::winapi::SYSTEM_INFO_ system_info; + typedef ::boost::winapi::ULONGLONG_ ticks_type; + unsigned const infinite=::boost::winapi::INFINITE_; + unsigned const timeout=::boost::winapi::WAIT_TIMEOUT_; + handle const invalid_handle_value=::boost::winapi::INVALID_HANDLE_VALUE_; + unsigned const event_modify_state=::boost::winapi::EVENT_MODIFY_STATE_; + unsigned const synchronize=::boost::winapi::SYNCHRONIZE_; + unsigned const wait_abandoned=::boost::winapi::WAIT_ABANDONED_; unsigned const create_event_initial_set = 0x00000002; unsigned const create_event_manual_reset = 0x00000001; - unsigned const event_all_access = ::boost::detail::winapi::EVENT_ALL_ACCESS_; - unsigned const semaphore_all_access = boost::detail::winapi::SEMAPHORE_ALL_ACCESS_; + unsigned const event_all_access = ::boost::winapi::EVENT_ALL_ACCESS_; + unsigned const semaphore_all_access = boost::winapi::SEMAPHORE_ALL_ACCESS_; } } } @@ -72,96 +70,8 @@ namespace boost { namespace win32 { - namespace detail { typedef ticks_type (__stdcall *gettickcount64_t)(); } -#if !BOOST_PLAT_WINDOWS_RUNTIME - extern "C" - { -#ifdef _MSC_VER - long _InterlockedCompareExchange(long volatile *, long, long); -#pragma intrinsic(_InterlockedCompareExchange) -#elif defined(__MINGW64_VERSION_MAJOR) - long _InterlockedCompareExchange(long volatile *, long, long); -#else - // Mingw doesn't provide intrinsics -#define _InterlockedCompareExchange InterlockedCompareExchange -#endif - } - // Borrowed from https://stackoverflow.com/questions/8211820/userland-interrupt-timer-access-such-as-via-kequeryinterrupttime-or-similar - inline ticks_type __stdcall GetTickCount64emulation() - { - static long count = -1l; - unsigned long previous_count, current_tick32, previous_count_zone, current_tick32_zone; - ticks_type current_tick64; - - previous_count = (unsigned long) boost::detail::interlocked_read_acquire(&count); - current_tick32 = ::boost::detail::winapi::GetTickCount(); - - if(previous_count == (unsigned long)-1l) - { - // count has never been written - unsigned long initial_count; - initial_count = current_tick32 >> 28; - previous_count = (unsigned long) _InterlockedCompareExchange(&count, (long)initial_count, -1l); - - current_tick64 = initial_count; - current_tick64 <<= 28; - current_tick64 += current_tick32 & 0x0FFFFFFF; - return current_tick64; - } - - previous_count_zone = previous_count & 15; - current_tick32_zone = current_tick32 >> 28; - - if(current_tick32_zone == previous_count_zone) - { - // The top four bits of the 32-bit tick count haven't changed since count was last written. - current_tick64 = previous_count; - current_tick64 <<= 28; - current_tick64 += current_tick32 & 0x0FFFFFFF; - return current_tick64; - } - - if(current_tick32_zone == previous_count_zone + 1 || (current_tick32_zone == 0 && previous_count_zone == 15)) - { - // The top four bits of the 32-bit tick count have been incremented since count was last written. - unsigned long new_count = previous_count + 1; - _InterlockedCompareExchange(&count, (long)new_count, (long)previous_count); - current_tick64 = new_count; - current_tick64 <<= 28; - current_tick64 += current_tick32 & 0x0FFFFFFF; - return current_tick64; - } - - // Oops, we weren't called often enough, we're stuck - return 0xFFFFFFFF; - } -#else -#endif - inline detail::gettickcount64_t GetTickCount64_() - { - static detail::gettickcount64_t gettickcount64impl; - if(gettickcount64impl) - return gettickcount64impl; - - // GetTickCount and GetModuleHandle are not allowed in the Windows Runtime, - // and kernel32 isn't used in Windows Phone. -#if BOOST_PLAT_WINDOWS_RUNTIME - gettickcount64impl = &::boost::detail::winapi::GetTickCount64; -#else - farproc_t addr=GetProcAddress( -#if !defined(BOOST_NO_ANSI_APIS) - ::boost::detail::winapi::GetModuleHandleA("KERNEL32.DLL"), -#else - ::boost::detail::winapi::GetModuleHandleW(L"KERNEL32.DLL"), -#endif - "GetTickCount64"); - if(addr) - gettickcount64impl=(detail::gettickcount64_t) addr; - else - gettickcount64impl=&GetTickCount64emulation; -#endif - return gettickcount64impl; - } + namespace detail { typedef ticks_type (WINAPI *gettickcount64_t)(); } + extern BOOST_THREAD_DECL boost::detail::win32::detail::gettickcount64_t gettickcount64; enum event_type { @@ -185,11 +95,11 @@ namespace boost initial_event_state state) { #if !defined(BOOST_NO_ANSI_APIS) - handle const res = ::boost::detail::winapi::CreateEventA(0, type, state, mutex_name); + handle const res = ::boost::winapi::CreateEventA(0, type, state, mutex_name); #elif BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA - handle const res = ::boost::detail::winapi::CreateEventW(0, type, state, mutex_name); + handle const res = ::boost::winapi::CreateEventW(0, type, state, mutex_name); #else - handle const res = ::boost::detail::winapi::CreateEventExW( + handle const res = ::boost::winapi::CreateEventExW( 0, mutex_name, type ? create_event_manual_reset : 0 | state ? create_event_initial_set : 0, @@ -211,12 +121,12 @@ namespace boost inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count) { #if !defined(BOOST_NO_ANSI_APIS) - handle const res=::boost::detail::winapi::CreateSemaphoreA(0,initial_count,max_count,0); + handle const res=::boost::winapi::CreateSemaphoreA(0,initial_count,max_count,0); #else #if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA - handle const res=::boost::detail::winapi::CreateSemaphoreEx(0,initial_count,max_count,0,0); + handle const res=::boost::winapi::CreateSemaphoreEx(0,initial_count,max_count,0,0); #else - handle const res=::boost::detail::winapi::CreateSemaphoreExW(0,initial_count,max_count,0,0,semaphore_all_access); + handle const res=::boost::winapi::CreateSemaphoreExW(0,initial_count,max_count,0,0,semaphore_all_access); #endif #endif return res; @@ -234,10 +144,10 @@ namespace boost inline handle duplicate_handle(handle source) { - handle const current_process=::boost::detail::winapi::GetCurrentProcess(); + handle const current_process=::boost::winapi::GetCurrentProcess(); long const same_access_flag=2; handle new_handle=0; - bool const success=::boost::detail::winapi::DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0; + bool const success=::boost::winapi::DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0; if(!success) { boost::throw_exception(thread_resource_error()); @@ -247,15 +157,15 @@ namespace boost inline void release_semaphore(handle semaphore,long count) { - BOOST_VERIFY(::boost::detail::winapi::ReleaseSemaphore(semaphore,count,0)!=0); + BOOST_VERIFY(::boost::winapi::ReleaseSemaphore(semaphore,count,0)!=0); } inline void get_system_info(system_info *info) { #if BOOST_PLAT_WINDOWS_RUNTIME - ::boost::detail::winapi::GetNativeSystemInfo(info); + ::boost::winapi::GetNativeSystemInfo(info); #else - ::boost::detail::winapi::GetSystemInfo(info); + ::boost::winapi::GetSystemInfo(info); #endif } @@ -266,15 +176,15 @@ namespace boost #if BOOST_PLAT_WINDOWS_RUNTIME std::this_thread::yield(); #else - ::boost::detail::winapi::Sleep(0); + ::boost::winapi::Sleep(0); #endif } else { #if BOOST_PLAT_WINDOWS_RUNTIME - ::boost::detail::winapi::WaitForSingleObjectEx(::boost::detail::winapi::GetCurrentThread(), milliseconds, 0); + ::boost::winapi::WaitForSingleObjectEx(::boost::winapi::GetCurrentThread(), milliseconds, 0); #else - ::boost::detail::winapi::Sleep(milliseconds); + ::boost::winapi::Sleep(milliseconds); #endif } } @@ -290,7 +200,7 @@ namespace boost { if (m_completionHandle != ::boost::detail::win32::invalid_handle_value) { - ::boost::detail::winapi::CloseHandle(m_completionHandle); + ::boost::winapi::CloseHandle(m_completionHandle); } } @@ -318,7 +228,7 @@ namespace boost { if(handle_to_manage && handle_to_manage!=invalid_handle_value) { - BOOST_VERIFY(::boost::detail::winapi::CloseHandle(handle_to_manage)); + BOOST_VERIFY(::boost::winapi::CloseHandle(handle_to_manage)); } } |