summaryrefslogtreecommitdiff
path: root/boost/thread
diff options
context:
space:
mode:
Diffstat (limited to 'boost/thread')
-rw-r--r--boost/thread/concurrent_queues/detail/sync_deque_base.hpp50
-rw-r--r--boost/thread/concurrent_queues/detail/sync_queue_base.hpp50
-rw-r--r--boost/thread/concurrent_queues/sync_deque.hpp12
-rw-r--r--boost/thread/concurrent_queues/sync_priority_queue.hpp24
-rw-r--r--boost/thread/concurrent_queues/sync_queue.hpp20
-rw-r--r--boost/thread/concurrent_queues/sync_timed_queue.hpp180
-rw-r--r--boost/thread/detail/config.hpp54
-rw-r--r--boost/thread/detail/platform.hpp2
-rw-r--r--boost/thread/detail/platform_time.hpp478
-rw-r--r--boost/thread/detail/thread.hpp138
-rw-r--r--boost/thread/future.hpp149
-rw-r--r--boost/thread/pthread/condition_variable.hpp277
-rw-r--r--boost/thread/pthread/condition_variable_fwd.hpp271
-rw-r--r--boost/thread/pthread/mutex.hpp104
-rw-r--r--boost/thread/pthread/pthread_helpers.hpp42
-rw-r--r--boost/thread/pthread/recursive_mutex.hpp98
-rw-r--r--boost/thread/pthread/shared_mutex.hpp241
-rw-r--r--boost/thread/pthread/shared_mutex_assert.hpp724
-rw-r--r--boost/thread/pthread/thread_data.hpp161
-rw-r--r--boost/thread/pthread/timespec.hpp138
-rw-r--r--boost/thread/shared_mutex.hpp9
-rw-r--r--boost/thread/thread_only.hpp2
-rw-r--r--boost/thread/v2/shared_mutex.hpp1168
-rw-r--r--boost/thread/v2/thread.hpp155
-rw-r--r--boost/thread/win32/basic_recursive_mutex.hpp40
-rw-r--r--boost/thread/win32/basic_timed_mutex.hpp150
-rw-r--r--boost/thread/win32/condition_variable.hpp341
-rw-r--r--boost/thread/win32/once.hpp52
-rw-r--r--boost/thread/win32/shared_mutex.hpp496
-rw-r--r--boost/thread/win32/thread_data.hpp200
-rw-r--r--boost/thread/win32/thread_heap_alloc.hpp6
-rw-r--r--boost/thread/win32/thread_primitives.hpp180
32 files changed, 2794 insertions, 3218 deletions
diff --git a/boost/thread/concurrent_queues/detail/sync_deque_base.hpp b/boost/thread/concurrent_queues/detail/sync_deque_base.hpp
index beffaf73b1..e3ecad15de 100644
--- a/boost/thread/concurrent_queues/detail/sync_deque_base.hpp
+++ b/boost/thread/concurrent_queues/detail/sync_deque_base.hpp
@@ -11,6 +11,8 @@
//
//////////////////////////////////////////////////////////////////////////////
+#include <boost/bind.hpp>
+
#include <boost/thread/detail/config.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/detail/move.hpp>
@@ -84,10 +86,13 @@ namespace detail
inline void throw_if_closed(unique_lock<mutex>&);
inline void throw_if_closed(lock_guard<mutex>&);
- inline void wait_until_not_empty(unique_lock<mutex>& lk);
+ inline bool not_empty_or_closed(unique_lock<mutex>& ) const;
+
inline bool wait_until_not_empty_or_closed(unique_lock<mutex>& lk);
template <class WClock, class Duration>
- queue_op_status wait_until_not_empty_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&);
+ queue_op_status wait_until_not_empty_or_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp);
+ template <class WClock, class Duration>
+ queue_op_status wait_until_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp);
inline void notify_not_empty_if_needed(unique_lock<mutex>& )
{
@@ -176,39 +181,38 @@ namespace detail
}
template <class ValueType, class Queue>
- void sync_deque_base<ValueType, Queue>::wait_until_not_empty(unique_lock<mutex>& lk)
+ bool sync_deque_base<ValueType, Queue>::not_empty_or_closed(unique_lock<mutex>& ) const
{
- for (;;)
- {
- if (! empty(lk)) break;
- throw_if_closed(lk);
- not_empty_.wait(lk);
- }
+ return ! data_.empty() || closed_;
}
+
template <class ValueType, class Queue>
bool sync_deque_base<ValueType, Queue>::wait_until_not_empty_or_closed(unique_lock<mutex>& lk)
{
- for (;;)
- {
- if (! empty(lk)) break;
- if (closed(lk)) return true;
- not_empty_.wait(lk);
- }
- return false;
+ not_empty_.wait(lk, boost::bind(&sync_deque_base<ValueType, Queue>::not_empty_or_closed, boost::ref(*this), boost::ref(lk)));
+ if (! empty(lk)) return false; // success
+ return true; // closed
}
template <class ValueType, class Queue>
template <class WClock, class Duration>
- queue_op_status sync_deque_base<ValueType, Queue>::wait_until_not_empty_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp)
+ queue_op_status sync_deque_base<ValueType, Queue>::wait_until_not_empty_or_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp)
{
- for (;;)
- {
- if (! empty(lk)) return queue_op_status::success;
- throw_if_closed(lk);
- if (not_empty_.wait_until(lk, tp) == cv_status::timeout ) return queue_op_status::timeout;
- }
+ if (! not_empty_.wait_until(lk, tp, boost::bind(&sync_deque_base<ValueType, Queue>::not_empty_or_closed, boost::ref(*this), boost::ref(lk))))
+ return queue_op_status::timeout;
+ if (! empty(lk)) return queue_op_status::success;
+ return queue_op_status::closed;
}
+ template <class ValueType, class Queue>
+ template <class WClock, class Duration>
+ queue_op_status sync_deque_base<ValueType, Queue>::wait_until_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp)
+ {
+ bool (sync_queue_base<ValueType, Queue>::*closed_function_ptr)(unique_lock<mutex>&) const = &sync_queue_base<ValueType, Queue>::closed;
+ if (! not_empty_.wait_until(lk, tp, boost::bind(closed_function_ptr, boost::ref(*this), boost::ref(lk))))
+ return queue_op_status::timeout;
+ return queue_op_status::closed;
+ }
} // detail
} // concurrent
diff --git a/boost/thread/concurrent_queues/detail/sync_queue_base.hpp b/boost/thread/concurrent_queues/detail/sync_queue_base.hpp
index 6ecb8211e3..c570da9505 100644
--- a/boost/thread/concurrent_queues/detail/sync_queue_base.hpp
+++ b/boost/thread/concurrent_queues/detail/sync_queue_base.hpp
@@ -11,6 +11,8 @@
//
//////////////////////////////////////////////////////////////////////////////
+#include <boost/bind.hpp>
+
#include <boost/thread/detail/config.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/detail/move.hpp>
@@ -84,10 +86,13 @@ namespace detail
inline void throw_if_closed(unique_lock<mutex>&);
inline void throw_if_closed(lock_guard<mutex>&);
- inline void wait_until_not_empty(unique_lock<mutex>& lk);
+ inline bool not_empty_or_closed(unique_lock<mutex>& ) const;
+
inline bool wait_until_not_empty_or_closed(unique_lock<mutex>& lk);
template <class WClock, class Duration>
- queue_op_status wait_until_not_empty_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&);
+ queue_op_status wait_until_not_empty_or_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp);
+ template <class WClock, class Duration>
+ queue_op_status wait_until_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp);
inline void notify_not_empty_if_needed(unique_lock<mutex>& )
{
@@ -176,39 +181,38 @@ namespace detail
}
template <class ValueType, class Queue>
- void sync_queue_base<ValueType, Queue>::wait_until_not_empty(unique_lock<mutex>& lk)
+ bool sync_queue_base<ValueType, Queue>::not_empty_or_closed(unique_lock<mutex>& ) const
{
- for (;;)
- {
- if (! empty(lk)) break;
- throw_if_closed(lk);
- not_empty_.wait(lk);
- }
+ return ! data_.empty() || closed_;
}
+
template <class ValueType, class Queue>
bool sync_queue_base<ValueType, Queue>::wait_until_not_empty_or_closed(unique_lock<mutex>& lk)
{
- for (;;)
- {
- if (! empty(lk)) break;
- if (closed(lk)) return true;
- not_empty_.wait(lk);
- }
- return false;
+ not_empty_.wait(lk, boost::bind(&sync_queue_base<ValueType, Queue>::not_empty_or_closed, boost::ref(*this), boost::ref(lk)));
+ if (! empty(lk)) return false; // success
+ return true; // closed
}
template <class ValueType, class Queue>
template <class WClock, class Duration>
- queue_op_status sync_queue_base<ValueType, Queue>::wait_until_not_empty_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp)
+ queue_op_status sync_queue_base<ValueType, Queue>::wait_until_not_empty_or_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp)
{
- for (;;)
- {
- if (! empty(lk)) return queue_op_status::success;
- throw_if_closed(lk);
- if (not_empty_.wait_until(lk, tp) == cv_status::timeout ) return queue_op_status::timeout;
- }
+ if (! not_empty_.wait_until(lk, tp, boost::bind(&sync_queue_base<ValueType, Queue>::not_empty_or_closed, boost::ref(*this), boost::ref(lk))))
+ return queue_op_status::timeout;
+ if (! empty(lk)) return queue_op_status::success;
+ return queue_op_status::closed;
}
+ template <class ValueType, class Queue>
+ template <class WClock, class Duration>
+ queue_op_status sync_queue_base<ValueType, Queue>::wait_until_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp)
+ {
+ bool (sync_queue_base<ValueType, Queue>::*closed_function_ptr)(unique_lock<mutex>&) const = &sync_queue_base<ValueType, Queue>::closed;
+ if (! not_empty_.wait_until(lk, tp, boost::bind(closed_function_ptr, boost::ref(*this), boost::ref(lk))))
+ return queue_op_status::timeout;
+ return queue_op_status::closed;
+ }
} // detail
} // concurrent
diff --git a/boost/thread/concurrent_queues/sync_deque.hpp b/boost/thread/concurrent_queues/sync_deque.hpp
index c84dae022a..c6159c4be0 100644
--- a/boost/thread/concurrent_queues/sync_deque.hpp
+++ b/boost/thread/concurrent_queues/sync_deque.hpp
@@ -149,11 +149,7 @@ namespace concurrent
template <class ValueType, class Container>
queue_op_status sync_deque<ValueType, Container>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
{
- if (super::empty(lk))
- {
- if (super::closed(lk)) return queue_op_status::closed;
- }
- bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
+ const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
if (has_been_closed) return queue_op_status::closed;
pull_front(elem, lk);
return queue_op_status::success;
@@ -188,7 +184,8 @@ namespace concurrent
void sync_deque<ValueType, Container>::pull_front(ValueType& elem)
{
unique_lock<mutex> lk(super::mtx_);
- super::wait_until_not_empty(lk);
+ const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
+ if (has_been_closed) super::throw_if_closed(lk);
pull_front(elem, lk);
}
@@ -197,7 +194,8 @@ namespace concurrent
ValueType sync_deque<ValueType, Container>::pull_front()
{
unique_lock<mutex> lk(super::mtx_);
- super::wait_until_not_empty(lk);
+ const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
+ if (has_been_closed) super::throw_if_closed(lk);
return pull_front(lk);
}
diff --git a/boost/thread/concurrent_queues/sync_priority_queue.hpp b/boost/thread/concurrent_queues/sync_priority_queue.hpp
index a556910cd6..2c6881f90f 100644
--- a/boost/thread/concurrent_queues/sync_priority_queue.hpp
+++ b/boost/thread/concurrent_queues/sync_priority_queue.hpp
@@ -82,7 +82,7 @@ namespace detail {
return boost::move(result);
}
- Type const& top()
+ Type const& top() const
{
return _elements.front();
}
@@ -249,7 +249,8 @@ namespace concurrent
T sync_priority_queue<T,Container,Cmp>::pull()
{
unique_lock<mutex> lk(super::mtx_);
- super::wait_until_not_empty(lk);
+ const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
+ if (has_been_closed) super::throw_if_closed(lk);
return pull(lk);
}
@@ -269,7 +270,8 @@ namespace concurrent
void sync_priority_queue<T,Container,Cmp>::pull(T& elem)
{
unique_lock<mutex> lk(super::mtx_);
- super::wait_until_not_empty(lk);
+ const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
+ if (has_been_closed) super::throw_if_closed(lk);
pull(lk, elem);
}
@@ -280,10 +282,9 @@ namespace concurrent
sync_priority_queue<T,Cont,Cmp>::pull_until(const chrono::time_point<WClock,Duration>& tp, T& elem)
{
unique_lock<mutex> lk(super::mtx_);
- if (queue_op_status::timeout == super::wait_until_not_empty_until(lk, tp))
- return queue_op_status::timeout;
- pull(lk, elem);
- return queue_op_status::success;
+ const queue_op_status rc = super::wait_until_not_empty_or_closed_until(lk, tp);
+ if (rc == queue_op_status::success) pull(lk, elem);
+ return rc;
}
//////////////////////
@@ -292,7 +293,7 @@ namespace concurrent
queue_op_status
sync_priority_queue<T,Cont,Cmp>::pull_for(const chrono::duration<Rep,Period>& dura, T& elem)
{
- return pull_until(clock::now() + dura, elem);
+ return pull_until(chrono::steady_clock::now() + dura, elem);
}
//////////////////////
@@ -334,11 +335,7 @@ namespace concurrent
template <class T,class Container, class Cmp>
queue_op_status sync_priority_queue<T,Container,Cmp>::wait_pull(unique_lock<mutex>& lk, T& elem)
{
- if (super::empty(lk))
- {
- if (super::closed(lk)) return queue_op_status::closed;
- }
- bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
+ const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
if (has_been_closed) return queue_op_status::closed;
pull(lk, elem);
return queue_op_status::success;
@@ -352,7 +349,6 @@ namespace concurrent
}
//////////////////////
-
template <class T,class Container, class Cmp>
queue_op_status sync_priority_queue<T,Container,Cmp>::nonblocking_pull(T& elem)
{
diff --git a/boost/thread/concurrent_queues/sync_queue.hpp b/boost/thread/concurrent_queues/sync_queue.hpp
index 1dbbef05dd..b36b57e607 100644
--- a/boost/thread/concurrent_queues/sync_queue.hpp
+++ b/boost/thread/concurrent_queues/sync_queue.hpp
@@ -10,7 +10,6 @@
// See http://www.boost.org/libs/thread for documentation.
//
//////////////////////////////////////////////////////////////////////////////
-#include <iostream>
#include <boost/thread/detail/config.hpp>
#include <boost/thread/concurrent_queues/detail/sync_queue_base.hpp>
@@ -51,7 +50,6 @@ namespace concurrent
inline ~sync_queue();
// Modifiers
-
inline void push(const value_type& x);
inline queue_op_status try_push(const value_type& x);
inline queue_op_status nonblocking_push(const value_type& x);
@@ -151,19 +149,9 @@ namespace concurrent
template <class ValueType, class Container>
queue_op_status sync_queue<ValueType, Container>::wait_pull(ValueType& elem, unique_lock<mutex>& lk)
{
- //std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
- if (super::empty(lk))
- {
- //std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
- if (super::closed(lk)) return queue_op_status::closed;
- }
- //std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
- bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
- //std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
+ const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
if (has_been_closed) return queue_op_status::closed;
- //std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
pull(elem, lk);
- //std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
return queue_op_status::success;
}
@@ -196,7 +184,8 @@ namespace concurrent
void sync_queue<ValueType, Container>::pull(ValueType& elem)
{
unique_lock<mutex> lk(super::mtx_);
- super::wait_until_not_empty(lk);
+ const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
+ if (has_been_closed) super::throw_if_closed(lk);
pull(elem, lk);
}
@@ -205,7 +194,8 @@ namespace concurrent
ValueType sync_queue<ValueType, Container>::pull()
{
unique_lock<mutex> lk(super::mtx_);
- super::wait_until_not_empty(lk);
+ const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
+ if (has_been_closed) super::throw_if_closed(lk);
return pull(lk);
}
diff --git a/boost/thread/concurrent_queues/sync_timed_queue.hpp b/boost/thread/concurrent_queues/sync_timed_queue.hpp
index 596a625ef5..a4394c0729 100644
--- a/boost/thread/concurrent_queues/sync_timed_queue.hpp
+++ b/boost/thread/concurrent_queues/sync_timed_queue.hpp
@@ -53,11 +53,6 @@ namespace detail
return *this;
}
- bool time_not_reached() const
- {
- return time > clock::now();
- }
-
bool operator <(const scheduled_type & other) const
{
return this->time > other.time;
@@ -123,6 +118,13 @@ namespace detail
queue_op_status try_push(BOOST_THREAD_RV_REF(T) elem, chrono::duration<Rep,Period> const& dura);
private:
+ inline bool not_empty_and_time_reached(unique_lock<mutex>& lk) const;
+ inline bool not_empty_and_time_reached(lock_guard<mutex>& lk) const;
+
+ bool wait_to_pull(unique_lock<mutex>&);
+ template <class WClock, class Duration>
+ queue_op_status wait_to_pull_until(unique_lock<mutex>&, chrono::time_point<WClock, Duration> const& tp);
+
T pull(unique_lock<mutex>&);
T pull(lock_guard<mutex>&);
@@ -134,15 +136,6 @@ namespace detail
queue_op_status wait_pull(unique_lock<mutex>& lk, T& elem);
- bool wait_until_not_empty_time_reached_or_closed(unique_lock<mutex>&);
- T pull_when_time_reached(unique_lock<mutex>&);
- template <class WClock, class Duration>
- queue_op_status pull_when_time_reached_until(unique_lock<mutex>&, chrono::time_point<WClock,Duration> const& tp, T& elem);
- bool time_not_reached(unique_lock<mutex>&);
- bool time_not_reached(lock_guard<mutex>&);
- bool empty_or_time_not_reached(unique_lock<mutex>&);
- bool empty_or_time_not_reached(lock_guard<mutex>&);
-
sync_timed_queue(const sync_timed_queue&);
sync_timed_queue& operator=(const sync_timed_queue&);
sync_timed_queue(BOOST_THREAD_RV_REF(sync_timed_queue));
@@ -210,82 +203,55 @@ namespace detail
///////////////////////////
template <class T, class Clock, class TimePoint>
- bool sync_timed_queue<T, Clock, TimePoint>::time_not_reached(unique_lock<mutex>&)
+ bool sync_timed_queue<T, Clock, TimePoint>::not_empty_and_time_reached(unique_lock<mutex>& lk) const
{
- return super::data_.top().time_not_reached();
+ return ! super::empty(lk) && clock::now() >= super::data_.top().time;
}
template <class T, class Clock, class TimePoint>
- bool sync_timed_queue<T, Clock, TimePoint>::time_not_reached(lock_guard<mutex>&)
+ bool sync_timed_queue<T, Clock, TimePoint>::not_empty_and_time_reached(lock_guard<mutex>& lk) const
{
- return super::data_.top().time_not_reached();
+ return ! super::empty(lk) && clock::now() >= super::data_.top().time;
}
///////////////////////////
template <class T, class Clock, class TimePoint>
- bool sync_timed_queue<T, Clock, TimePoint>::wait_until_not_empty_time_reached_or_closed(unique_lock<mutex>& lk)
+ bool sync_timed_queue<T, Clock, TimePoint>::wait_to_pull(unique_lock<mutex>& lk)
{
for (;;)
{
- if (super::closed(lk)) return true;
- while (! super::empty(lk)) {
- if (! time_not_reached(lk)) return false;
- time_point tp = super::data_.top().time;
- super::not_empty_.wait_until(lk, tp);
- if (super::closed(lk)) return true;
- }
- if (super::closed(lk)) return true;
- super::not_empty_.wait(lk);
- }
- //return false;
- }
+ if (not_empty_and_time_reached(lk)) return false; // success
+ if (super::closed(lk)) return true; // closed
- ///////////////////////////
- template <class T, class Clock, class TimePoint>
- T sync_timed_queue<T, Clock, TimePoint>::pull_when_time_reached(unique_lock<mutex>& lk)
- {
- while (time_not_reached(lk))
- {
- super::throw_if_closed(lk);
- time_point tp = super::data_.top().time;
- super::not_empty_.wait_until(lk,tp);
- super::wait_until_not_empty(lk);
+ super::wait_until_not_empty_or_closed(lk);
+
+ if (not_empty_and_time_reached(lk)) return false; // success
+ if (super::closed(lk)) return true; // closed
+
+ const time_point tp(super::data_.top().time);
+ super::wait_until_closed_until(lk, tp);
}
- return pull(lk);
}
template <class T, class Clock, class TimePoint>
template <class WClock, class Duration>
- queue_op_status
- sync_timed_queue<T, Clock, TimePoint>::pull_when_time_reached_until(unique_lock<mutex>& lk, chrono::time_point<WClock, Duration> const& tp, T& elem)
+ queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_to_pull_until(unique_lock<mutex>& lk, chrono::time_point<WClock, Duration> const& tp)
{
- chrono::time_point<WClock, Duration> tpmin = (tp < super::data_.top().time) ? tp : super::data_.top().time;
- while (time_not_reached(lk))
+ for (;;)
{
- super::throw_if_closed(lk);
- if (cv_status::timeout == super::not_empty_.wait_until(lk, tpmin)) {
- if (time_not_reached(lk)) return queue_op_status::not_ready;
- return queue_op_status::timeout;
- }
- }
- pull(lk, elem);
- return queue_op_status::success;
- }
+ if (not_empty_and_time_reached(lk)) return queue_op_status::success;
+ if (super::closed(lk)) return queue_op_status::closed;
+ if (clock::now() >= tp) return super::empty(lk) ? queue_op_status::timeout : queue_op_status::not_ready;
- ///////////////////////////
- template <class T, class Clock, class TimePoint>
- bool sync_timed_queue<T, Clock, TimePoint>::empty_or_time_not_reached(unique_lock<mutex>& lk)
- {
- if ( super::empty(lk) ) return true;
- if ( time_not_reached(lk) ) return true;
- return false;
- }
- template <class T, class Clock, class TimePoint>
- bool sync_timed_queue<T, Clock, TimePoint>::empty_or_time_not_reached(lock_guard<mutex>& lk)
- {
- if ( super::empty(lk) ) return true;
- if ( time_not_reached(lk) ) return true;
- return false;
+ super::wait_until_not_empty_or_closed_until(lk, tp);
+
+ if (not_empty_and_time_reached(lk)) return queue_op_status::success;
+ if (super::closed(lk)) return queue_op_status::closed;
+ if (clock::now() >= tp) return super::empty(lk) ? queue_op_status::timeout : queue_op_status::not_ready;
+
+ const time_point tpmin(tp < super::data_.top().time ? tp : super::data_.top().time);
+ super::wait_until_closed_until(lk, tpmin);
+ }
}
///////////////////////////
@@ -312,8 +278,9 @@ namespace detail
T sync_timed_queue<T, Clock, TimePoint>::pull()
{
unique_lock<mutex> lk(super::mtx_);
- super::wait_until_not_empty(lk);
- return pull_when_time_reached(lk);
+ const bool has_been_closed = wait_to_pull(lk);
+ if (has_been_closed) super::throw_if_closed(lk);
+ return pull(lk);
}
///////////////////////////
@@ -341,8 +308,9 @@ namespace detail
void sync_timed_queue<T, Clock, TimePoint>::pull(T& elem)
{
unique_lock<mutex> lk(super::mtx_);
- super::wait_until_not_empty(lk);
- elem = pull_when_time_reached(lk);
+ const bool has_been_closed = wait_to_pull(lk);
+ if (has_been_closed) super::throw_if_closed(lk);
+ pull(lk, elem);
}
//////////////////////
@@ -352,10 +320,9 @@ namespace detail
sync_timed_queue<T, Clock, TimePoint>::pull_until(chrono::time_point<WClock, Duration> const& tp, T& elem)
{
unique_lock<mutex> lk(super::mtx_);
-
- if (queue_op_status::timeout == super::wait_until_not_empty_until(lk, tp))
- return queue_op_status::timeout;
- return pull_when_time_reached_until(lk, tp, elem);
+ const queue_op_status rc = wait_to_pull_until(lk, tp);
+ if (rc == queue_op_status::success) pull(lk, elem);
+ return rc;
}
//////////////////////
@@ -371,35 +338,26 @@ namespace detail
template <class T, class Clock, class TimePoint>
queue_op_status sync_timed_queue<T, Clock, TimePoint>::try_pull(unique_lock<mutex>& lk, T& elem)
{
- if ( super::empty(lk) )
+ if (not_empty_and_time_reached(lk))
{
- if (super::closed(lk)) return queue_op_status::closed;
- return queue_op_status::empty;
- }
- if ( time_not_reached(lk) )
- {
- if (super::closed(lk)) return queue_op_status::closed;
- return queue_op_status::not_ready;
+ pull(lk, elem);
+ return queue_op_status::success;
}
-
- pull(lk, elem);
- return queue_op_status::success;
+ if (super::closed(lk)) return queue_op_status::closed;
+ if (super::empty(lk)) return queue_op_status::empty;
+ return queue_op_status::not_ready;
}
template <class T, class Clock, class TimePoint>
queue_op_status sync_timed_queue<T, Clock, TimePoint>::try_pull(lock_guard<mutex>& lk, T& elem)
{
- if ( super::empty(lk) )
+ if (not_empty_and_time_reached(lk))
{
- if (super::closed(lk)) return queue_op_status::closed;
- return queue_op_status::empty;
- }
- if ( time_not_reached(lk) )
- {
- if (super::closed(lk)) return queue_op_status::closed;
- return queue_op_status::not_ready;
+ pull(lk, elem);
+ return queue_op_status::success;
}
- pull(lk, elem);
- return queue_op_status::success;
+ if (super::closed(lk)) return queue_op_status::closed;
+ if (super::empty(lk)) return queue_op_status::empty;
+ return queue_op_status::not_ready;
}
template <class T, class Clock, class TimePoint>
@@ -413,11 +371,7 @@ namespace detail
template <class T, class Clock, class TimePoint>
queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_pull(unique_lock<mutex>& lk, T& elem)
{
- if (super::empty(lk))
- {
- if (super::closed(lk)) return queue_op_status::closed;
- }
- bool has_been_closed = wait_until_not_empty_time_reached_or_closed(lk);
+ const bool has_been_closed = wait_to_pull(lk);
if (has_been_closed) return queue_op_status::closed;
pull(lk, elem);
return queue_op_status::success;
@@ -430,26 +384,6 @@ namespace detail
return wait_pull(lk, elem);
}
-// ///////////////////////////
-// template <class T, class Clock, class TimePoint>
-// queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_pull(unique_lock<mutex> &lk, T& elem)
-// {
-// if (super::empty(lk))
-// {
-// if (super::closed(lk)) return queue_op_status::closed;
-// }
-// bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
-// if (has_been_closed) return queue_op_status::closed;
-// pull(lk, elem);
-// return queue_op_status::success;
-// }
-// template <class T, class Clock, class TimePoint>
-// queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_pull(T& elem)
-// {
-// unique_lock<mutex> lk(super::mtx_);
-// return wait_pull(lk, elem);
-// }
-
///////////////////////////
template <class T, class Clock, class TimePoint>
queue_op_status sync_timed_queue<T, Clock, TimePoint>::nonblocking_pull(T& elem)
diff --git a/boost/thread/detail/config.hpp b/boost/thread/detail/config.hpp
index ebd73a7e92..70c74687f6 100644
--- a/boost/thread/detail/config.hpp
+++ b/boost/thread/detail/config.hpp
@@ -12,7 +12,6 @@
#include <boost/detail/workaround.hpp>
#include <boost/thread/detail/platform.hpp>
-//#define BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
//#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
// ATTRIBUTE_MAY_ALIAS
@@ -30,6 +29,34 @@
#define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS
#endif
+#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
+# warning Boost.Thread will use the Windows API for time
+#elif defined(BOOST_THREAD_CHRONO_MAC_API)
+# warning Boost.Thread will use the Mac API for time
+#elif defined(BOOST_THREAD_CHRONO_POSIX_API)
+# warning Boost.Thread will use the POSIX API for time
+#endif
+
+# if defined( BOOST_THREAD_CHRONO_WINDOWS_API ) && defined( BOOST_THREAD_CHRONO_POSIX_API )
+# error both BOOST_THREAD_CHRONO_WINDOWS_API and BOOST_THREAD_CHRONO_POSIX_API are defined
+# elif defined( BOOST_THREAD_CHRONO_WINDOWS_API ) && defined( BOOST_THREAD_CHRONO_MAC_API )
+# error both BOOST_THREAD_CHRONO_WINDOWS_API and BOOST_THREAD_CHRONO_MAC_API are defined
+# elif defined( BOOST_THREAD_CHRONO_MAC_API ) && defined( BOOST_THREAD_CHRONO_POSIX_API )
+# error both BOOST_THREAD_CHRONO_MAC_API and BOOST_THREAD_CHRONO_POSIX_API are defined
+# elif !defined( BOOST_THREAD_CHRONO_WINDOWS_API ) && !defined( BOOST_THREAD_CHRONO_MAC_API ) && !defined( BOOST_THREAD_CHRONO_POSIX_API )
+# if (defined(_WIN32) || defined(__WIN32__) || defined(WIN32))
+# define BOOST_THREAD_CHRONO_WINDOWS_API
+# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+# define BOOST_THREAD_CHRONO_MAC_API
+# else
+# define BOOST_THREAD_CHRONO_POSIX_API
+# endif
+# endif
+
+#if !defined(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)
+#define BOOST_THREAD_POLL_INTERVAL_MILLISECONDS 100
+#endif
+
#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
#define BOOST_THREAD_ASSERT_PRECONDITION(EXPR, EX) \
if (EXPR) {} else boost::throw_exception(EX)
@@ -96,7 +123,7 @@
/// RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
//#if defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_MSVC
-#define BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
+#define BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
//#endif
// Default version
@@ -385,6 +412,29 @@
# endif
#endif
+#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
+ #define BOOST_THREAD_HAS_MONO_CLOCK
+ #define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+#elif defined(BOOST_THREAD_CHRONO_MAC_API)
+ #define BOOST_THREAD_HAS_MONO_CLOCK
+#else
+ #include <time.h> // check for CLOCK_MONOTONIC
+ #if defined(CLOCK_MONOTONIC)
+ #define BOOST_THREAD_HAS_MONO_CLOCK
+ #define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+ #endif
+#endif
+
+#if defined(BOOST_THREAD_PLATFORM_WIN32)
+#elif ! defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+#if defined BOOST_PTHREAD_HAS_TIMEDLOCK
+#define BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
+#elif (defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS-0)>=200112L) \
+ || (defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
+#define BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
+#endif
+#endif
+
// provided for backwards compatibility, since this
// macro was used for several releases by mistake.
#if defined(BOOST_THREAD_DYN_DLL) && ! defined(BOOST_THREAD_DYN_LINK)
diff --git a/boost/thread/detail/platform.hpp b/boost/thread/detail/platform.hpp
index 1f33b1a67a..172a601a02 100644
--- a/boost/thread/detail/platform.hpp
+++ b/boost/thread/detail/platform.hpp
@@ -31,7 +31,9 @@
#elif defined(__CYGWIN__)
# define BOOST_THREAD_CYGWIN
#elif (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && !defined(BOOST_DISABLE_WIN32)
+#if ! defined BOOST_THREAD_WIN32
# define BOOST_THREAD_WIN32
+#endif
#elif defined(__BEOS__)
# define BOOST_THREAD_BEOS
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
diff --git a/boost/thread/detail/platform_time.hpp b/boost/thread/detail/platform_time.hpp
new file mode 100644
index 0000000000..2180f13c05
--- /dev/null
+++ b/boost/thread/detail/platform_time.hpp
@@ -0,0 +1,478 @@
+#ifndef BOOST_THREAD_DETAIL_PLATFORM_TIME_HPP
+#define BOOST_THREAD_DETAIL_PLATFORM_TIME_HPP
+// (C) Copyright 2007-8 Anthony Williams
+// (C) Copyright 2012 Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/detail/config.hpp>
+#include <boost/thread/thread_time.hpp>
+#if defined BOOST_THREAD_USES_DATETIME
+#include <boost/date_time/posix_time/conversion.hpp>
+#endif
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+#ifdef BOOST_THREAD_USES_CHRONO
+#include <boost/chrono/duration.hpp>
+#include <boost/chrono/system_clocks.hpp>
+#include <boost/chrono/ceil.hpp>
+#endif
+
+#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
+#include <boost/detail/winapi/time.hpp>
+#include <boost/detail/winapi/timers.hpp>
+#include <boost/thread/win32/thread_primitives.hpp>
+#elif defined(BOOST_THREAD_CHRONO_MAC_API)
+#include <sys/time.h> //for gettimeofday and timeval
+#include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t
+
+#else
+#include <time.h> // for clock_gettime
+#endif
+
+#include <limits>
+
+#include <boost/config/abi_prefix.hpp>
+
+namespace boost
+{
+//typedef boost::int_least64_t time_max_t;
+typedef boost::intmax_t time_max_t;
+
+#if defined BOOST_THREAD_CHRONO_MAC_API
+namespace threads
+{
+
+namespace chrono_details
+{
+
+// steady_clock
+
+// Note, in this implementation steady_clock and high_resolution_clock
+// are the same clock. They are both based on mach_absolute_time().
+// mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
+// nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom
+// are run time constants supplied by the OS. This clock has no relationship
+// to the Gregorian calendar. It's main use is as a high resolution timer.
+
+// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize
+// for that case as an optimization.
+
+inline time_max_t
+steady_simplified()
+{
+ return mach_absolute_time();
+}
+
+inline double compute_steady_factor(kern_return_t& err)
+{
+ mach_timebase_info_data_t MachInfo;
+ err = mach_timebase_info(&MachInfo);
+ if ( err != 0 ) {
+ return 0;
+ }
+ return static_cast<double>(MachInfo.numer) / MachInfo.denom;
+}
+
+inline time_max_t steady_full()
+{
+ kern_return_t err;
+ const double factor = chrono_details::compute_steady_factor(err);
+ if (err != 0)
+ {
+ BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
+ }
+ return static_cast<time_max_t>(mach_absolute_time() * factor);
+}
+
+
+typedef time_max_t (*FP)();
+
+inline FP init_steady_clock(kern_return_t & err)
+{
+ mach_timebase_info_data_t MachInfo;
+ err = mach_timebase_info(&MachInfo);
+ if ( err != 0 )
+ {
+ return 0;
+ }
+
+ if (MachInfo.numer == MachInfo.denom)
+ {
+ return &chrono_details::steady_simplified;
+ }
+ return &chrono_details::steady_full;
+}
+
+}
+}
+#endif
+
+ namespace detail
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ inline timespec ns_to_timespec(boost::time_max_t const& ns)
+ {
+ boost::time_max_t s = ns / 1000000000l;
+ timespec ts;
+ ts.tv_sec = static_cast<long> (s);
+ ts.tv_nsec = static_cast<long> (ns - s * 1000000000l);
+ return ts;
+ }
+ inline boost::time_max_t timespec_to_ns(timespec const& ts)
+ {
+ return static_cast<boost::time_max_t>(ts.tv_sec) * 1000000000l + ts.tv_nsec;
+ }
+#endif
+
+ struct platform_duration
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ explicit platform_duration(timespec const& v) : ts_val(v) {}
+ timespec const& getTs() const { return ts_val; }
+
+ explicit platform_duration(boost::time_max_t const& ns = 0) : ts_val(ns_to_timespec(ns)) {}
+ boost::time_max_t getNs() const { return timespec_to_ns(ts_val); }
+#else
+ explicit platform_duration(boost::time_max_t const& ns = 0) : ns_val(ns) {}
+ boost::time_max_t getNs() const { return ns_val; }
+#endif
+
+#if defined BOOST_THREAD_USES_DATETIME
+ platform_duration(boost::posix_time::time_duration const& rel_time)
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ ts_val.tv_sec = rel_time.total_seconds();
+ ts_val.tv_nsec = static_cast<long>(rel_time.fractional_seconds() * (1000000000l / rel_time.ticks_per_second()));
+#else
+ ns_val = static_cast<boost::time_max_t>(rel_time.total_seconds()) * 1000000000l;
+ ns_val += rel_time.fractional_seconds() * (1000000000l / rel_time.ticks_per_second());
+#endif
+ }
+#endif
+
+#if defined BOOST_THREAD_USES_CHRONO
+ template <class Rep, class Period>
+ platform_duration(chrono::duration<Rep, Period> const& d)
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ ts_val = ns_to_timespec(chrono::ceil<chrono::nanoseconds>(d).count());
+#else
+ ns_val = chrono::ceil<chrono::nanoseconds>(d).count();
+#endif
+ }
+#endif
+
+ boost::time_max_t getMs() const
+ {
+ const boost::time_max_t ns = getNs();
+ // ceil/floor away from zero
+ if (ns >= 0)
+ {
+ // return ceiling of positive numbers
+ return (ns + 999999) / 1000000;
+ }
+ else
+ {
+ // return floor of negative numbers
+ return (ns - 999999) / 1000000;
+ }
+ }
+
+ static platform_duration zero()
+ {
+ return platform_duration(0);
+ }
+
+ private:
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ timespec ts_val;
+#else
+ boost::time_max_t ns_val;
+#endif
+ };
+
+ inline bool operator==(platform_duration const& lhs, platform_duration const& rhs)
+ {
+ return lhs.getNs() == rhs.getNs();
+ }
+ inline bool operator!=(platform_duration const& lhs, platform_duration const& rhs)
+ {
+ return lhs.getNs() != rhs.getNs();
+ }
+ inline bool operator<(platform_duration const& lhs, platform_duration const& rhs)
+ {
+ return lhs.getNs() < rhs.getNs();
+ }
+ inline bool operator<=(platform_duration const& lhs, platform_duration const& rhs)
+ {
+ return lhs.getNs() <= rhs.getNs();
+ }
+ inline bool operator>(platform_duration const& lhs, platform_duration const& rhs)
+ {
+ return lhs.getNs() > rhs.getNs();
+ }
+ inline bool operator>=(platform_duration const& lhs, platform_duration const& rhs)
+ {
+ return lhs.getNs() >= rhs.getNs();
+ }
+
+ static inline platform_duration platform_milliseconds(long const& ms)
+ {
+ return platform_duration(ms * 1000000l);
+ }
+
+ struct real_platform_timepoint
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ explicit real_platform_timepoint(timespec const& v) : dur(v) {}
+ timespec const& getTs() const { return dur.getTs(); }
+#endif
+
+ explicit real_platform_timepoint(boost::time_max_t const& ns) : dur(ns) {}
+ boost::time_max_t getNs() const { return dur.getNs(); }
+
+#if defined BOOST_THREAD_USES_DATETIME
+ real_platform_timepoint(boost::system_time const& abs_time)
+ : dur(abs_time - boost::posix_time::from_time_t(0)) {}
+#endif
+
+#if defined BOOST_THREAD_USES_CHRONO
+ template <class Duration>
+ real_platform_timepoint(chrono::time_point<chrono::system_clock, Duration> const& abs_time)
+ : dur(abs_time.time_since_epoch()) {}
+#endif
+
+ private:
+ platform_duration dur;
+ };
+
+ inline bool operator==(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() == rhs.getNs();
+ }
+ inline bool operator!=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() != rhs.getNs();
+ }
+ inline bool operator<(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() < rhs.getNs();
+ }
+ inline bool operator<=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() <= rhs.getNs();
+ }
+ inline bool operator>(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() > rhs.getNs();
+ }
+ inline bool operator>=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() >= rhs.getNs();
+ }
+
+ inline real_platform_timepoint operator+(real_platform_timepoint const& lhs, platform_duration const& rhs)
+ {
+ return real_platform_timepoint(lhs.getNs() + rhs.getNs());
+ }
+ inline real_platform_timepoint operator+(platform_duration const& lhs, real_platform_timepoint const& rhs)
+ {
+ return real_platform_timepoint(lhs.getNs() + rhs.getNs());
+ }
+ inline platform_duration operator-(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
+ {
+ return platform_duration(lhs.getNs() - rhs.getNs());
+ }
+
+ struct real_platform_clock
+ {
+ static real_platform_timepoint now()
+ {
+#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
+ boost::detail::winapi::FILETIME_ ft;
+ boost::detail::winapi::GetSystemTimeAsFileTime(&ft); // never fails
+ boost::time_max_t ns = ((((static_cast<boost::time_max_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) - 116444736000000000LL) * 100LL);
+ return real_platform_timepoint(ns);
+#elif defined(BOOST_THREAD_CHRONO_MAC_API)
+ timeval tv;
+ ::gettimeofday(&tv, 0);
+ timespec ts;
+ ts.tv_sec = tv.tv_sec;
+ ts.tv_nsec = tv.tv_usec * 1000;
+ return real_platform_timepoint(ts);
+#else
+ timespec ts;
+ if ( ::clock_gettime( CLOCK_REALTIME, &ts ) )
+ {
+ BOOST_ASSERT(0 && "Boost::Thread - clock_gettime(CLOCK_REALTIME) Internal Error");
+ return real_platform_timepoint(0);
+ }
+ return real_platform_timepoint(ts);
+#endif
+ }
+ };
+
+#if defined(BOOST_THREAD_HAS_MONO_CLOCK)
+
+ struct mono_platform_timepoint
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+
+ explicit mono_platform_timepoint(timespec const& v) : dur(v) {}
+ timespec const& getTs() const { return dur.getTs(); }
+#endif
+
+ explicit mono_platform_timepoint(boost::time_max_t const& ns) : dur(ns) {}
+ boost::time_max_t getNs() const { return dur.getNs(); }
+
+#if defined BOOST_THREAD_USES_CHRONO
+ // This conversion assumes that chrono::steady_clock::time_point and mono_platform_timepoint share the same epoch.
+ template <class Duration>
+ mono_platform_timepoint(chrono::time_point<chrono::steady_clock, Duration> const& abs_time)
+ : dur(abs_time.time_since_epoch()) {}
+#endif
+
+ // can't name this max() since that is a macro on some Windows systems
+ static mono_platform_timepoint getMax()
+ {
+#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
+ timespec ts;
+ ts.tv_sec = (std::numeric_limits<time_t>::max)();
+ ts.tv_nsec = 999999999;
+ return mono_platform_timepoint(ts);
+#else
+ boost::time_max_t ns = (std::numeric_limits<boost::time_max_t>::max)();
+ return mono_platform_timepoint(ns);
+#endif
+ }
+
+ private:
+ platform_duration dur;
+ };
+
+ inline bool operator==(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() == rhs.getNs();
+ }
+ inline bool operator!=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() != rhs.getNs();
+ }
+ inline bool operator<(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() < rhs.getNs();
+ }
+ inline bool operator<=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() <= rhs.getNs();
+ }
+ inline bool operator>(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() > rhs.getNs();
+ }
+ inline bool operator>=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return lhs.getNs() >= rhs.getNs();
+ }
+
+ inline mono_platform_timepoint operator+(mono_platform_timepoint const& lhs, platform_duration const& rhs)
+ {
+ return mono_platform_timepoint(lhs.getNs() + rhs.getNs());
+ }
+ inline mono_platform_timepoint operator+(platform_duration const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return mono_platform_timepoint(lhs.getNs() + rhs.getNs());
+ }
+ inline platform_duration operator-(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
+ {
+ return platform_duration(lhs.getNs() - rhs.getNs());
+ }
+
+ struct mono_platform_clock
+ {
+ static mono_platform_timepoint now()
+ {
+#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
+#if defined(BOOST_THREAD_USES_CHRONO)
+ // Use QueryPerformanceCounter() to match the implementation in Boost
+ // Chrono so that chrono::steady_clock::now() and this function share the
+ // same epoch and so can be converted between each other.
+ boost::detail::winapi::LARGE_INTEGER_ freq;
+ if ( !boost::detail::winapi::QueryPerformanceFrequency( &freq ) )
+ {
+ BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceFrequency Internal Error");
+ return mono_platform_timepoint(0);
+ }
+ if ( freq.QuadPart <= 0 )
+ {
+ BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceFrequency Internal Error");
+ return mono_platform_timepoint(0);
+ }
+
+ boost::detail::winapi::LARGE_INTEGER_ pcount;
+ unsigned times=0;
+ while ( ! boost::detail::winapi::QueryPerformanceCounter( &pcount ) )
+ {
+ if ( ++times > 3 )
+ {
+ BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceCounter Internal Error");
+ return mono_platform_timepoint(0);
+ }
+ }
+
+ long double ns = 1000000000.0L * pcount.QuadPart / freq.QuadPart;
+ return mono_platform_timepoint(static_cast<boost::time_max_t>(ns));
+#else
+ // Use GetTickCount64() because it's more reliable on older
+ // systems like Windows XP and Windows Server 2003.
+ win32::ticks_type msec = win32::gettickcount64();
+ return mono_platform_timepoint(msec * 1000000);
+#endif
+#elif defined(BOOST_THREAD_CHRONO_MAC_API)
+ kern_return_t err;
+ threads::chrono_details::FP fp = threads::chrono_details::init_steady_clock(err);
+ if ( err != 0 )
+ {
+ BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
+ }
+ return mono_platform_timepoint(fp());
+#else
+ timespec ts;
+ if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) )
+ {
+ BOOST_ASSERT(0 && "Boost::Thread - clock_gettime(CLOCK_MONOTONIC) Internal Error");
+ return mono_platform_timepoint(0);
+ }
+ return mono_platform_timepoint(ts);
+#endif
+ }
+ };
+
+#endif
+
+#if defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
+ typedef mono_platform_clock internal_platform_clock;
+ typedef mono_platform_timepoint internal_platform_timepoint;
+#else
+ typedef real_platform_clock internal_platform_clock;
+ typedef real_platform_timepoint internal_platform_timepoint;
+#endif
+
+#ifdef BOOST_THREAD_USES_CHRONO
+#ifdef BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+ typedef chrono::steady_clock internal_chrono_clock;
+#else
+ typedef chrono::system_clock internal_chrono_clock;
+#endif
+#endif
+
+ }
+}
+
+#include <boost/config/abi_suffix.hpp>
+
+#endif
diff --git a/boost/thread/detail/thread.hpp b/boost/thread/detail/thread.hpp
index b91adee0e9..52af1ba210 100644
--- a/boost/thread/detail/thread.hpp
+++ b/boost/thread/detail/thread.hpp
@@ -36,6 +36,7 @@
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/decay.hpp>
#include <boost/functional/hash.hpp>
+#include <boost/thread/detail/platform_time.hpp>
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
@@ -155,15 +156,7 @@ namespace boost
};
#endif
}
-namespace thread_detail {
-#ifdef BOOST_THREAD_USES_CHRONO
-#if defined(BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC)
- typedef chrono::steady_clock internal_clock_t;
-#else
- typedef chrono::system_clock internal_clock_t;
-#endif
-#endif
-}
+
class BOOST_THREAD_DECL thread
{
public:
@@ -462,105 +455,80 @@ namespace thread_detail {
}
class id;
-#ifdef BOOST_THREAD_PLATFORM_PTHREAD
- inline id get_id() const BOOST_NOEXCEPT;
-#else
id get_id() const BOOST_NOEXCEPT;
-#endif
-
bool joinable() const BOOST_NOEXCEPT;
private:
bool join_noexcept();
+ bool do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res);
+ bool do_try_join_until(detail::internal_platform_timepoint const &timeout);
public:
- inline void join();
+ void join();
#ifdef BOOST_THREAD_USES_CHRONO
-#if defined(BOOST_THREAD_PLATFORM_WIN32)
- template <class Rep, class Period>
- bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
- {
- chrono::milliseconds rel_time2= chrono::ceil<chrono::milliseconds>(rel_time);
- return do_try_join_until(rel_time2.count());
- }
-#else
- template <class Rep, class Period>
- bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
+ template <class Duration>
+ bool try_join_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
{
- return try_join_until(chrono::steady_clock::now() + rel_time);
+ return do_try_join_until(boost::detail::internal_platform_timepoint(t));
}
-#endif
template <class Clock, class Duration>
bool try_join_until(const chrono::time_point<Clock, Duration>& t)
{
- using namespace chrono;
- bool joined= false;
- do {
- thread_detail::internal_clock_t::time_point s_now = thread_detail::internal_clock_t::now();
- typename Clock::duration d = ceil<nanoseconds>(t-Clock::now());
- if (d <= Clock::duration::zero()) return false; // in case the Clock::time_point t is already reached
- joined = try_join_until(s_now + d);
- } while (! joined);
+ typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
+ common_duration d(t - Clock::now());
+ d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
+ while ( ! try_join_until(detail::internal_chrono_clock::now() + d) )
+ {
+ d = t - Clock::now();
+ if ( d <= common_duration::zero() ) return false; // timeout occurred
+ d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
+ }
return true;
}
- template <class Duration>
- bool try_join_until(const chrono::time_point<thread_detail::internal_clock_t, Duration>& t)
- {
- using namespace chrono;
- typedef time_point<thread_detail::internal_clock_t, nanoseconds> nano_sys_tmpt;
- return try_join_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
- }
-#endif
-#if defined(BOOST_THREAD_PLATFORM_WIN32)
- private:
- bool do_try_join_until_noexcept(uintmax_t milli, bool& res);
- inline bool do_try_join_until(uintmax_t milli);
- public:
- bool timed_join(const system_time& abs_time);
- //{
- // return do_try_join_until(get_milliseconds_until(wait_until));
- //}
-#ifdef BOOST_THREAD_USES_CHRONO
- bool try_join_until(const chrono::time_point<thread_detail::internal_clock_t, chrono::nanoseconds>& tp)
+ template <class Rep, class Period>
+ bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
{
- chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
- return do_try_join_until(rel_time.count());
+ return try_join_until(chrono::steady_clock::now() + rel_time);
}
#endif
-
-
-#else
- private:
- bool do_try_join_until_noexcept(struct timespec const &timeout, bool& res);
- inline bool do_try_join_until(struct timespec const &timeout);
- public:
#if defined BOOST_THREAD_USES_DATETIME
bool timed_join(const system_time& abs_time)
{
- struct timespec const ts=detail::to_timespec(abs_time);
+ const detail::real_platform_timepoint ts(abs_time);
+#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+ detail::platform_duration d(ts - detail::real_platform_clock::now());
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ while ( ! do_try_join_until(detail::internal_platform_clock::now() + d) )
+ {
+ d = ts - detail::real_platform_clock::now();
+ if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ }
+ return true;
+#else
return do_try_join_until(ts);
- }
#endif
-#ifdef BOOST_THREAD_USES_CHRONO
- bool try_join_until(const chrono::time_point<thread_detail::internal_clock_t, chrono::nanoseconds>& tp)
- {
- using namespace chrono;
- nanoseconds d = tp.time_since_epoch();
- timespec ts = boost::detail::to_timespec(d);
- return do_try_join_until(ts);
}
-#endif
-
-#endif
- public:
-#if defined BOOST_THREAD_USES_DATETIME
template<typename TimeDuration>
- inline bool timed_join(TimeDuration const& rel_time)
+ bool timed_join(TimeDuration const& rel_time)
{
- return timed_join(get_system_time()+rel_time);
+ detail::platform_duration d(rel_time);
+#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
+ const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ while ( ! do_try_join_until(detail::internal_platform_clock::now() + d) )
+ {
+ d = ts - detail::mono_platform_clock::now();
+ if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ }
+ return true;
+#else
+ return do_try_join_until(detail::internal_platform_clock::now() + d);
+#endif
}
#endif
void detach();
@@ -614,7 +582,7 @@ namespace thread_detail {
namespace this_thread
{
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
- inline thread::id get_id() BOOST_NOEXCEPT;
+ thread::id get_id() BOOST_NOEXCEPT;
#else
thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT;
#endif
@@ -745,7 +713,7 @@ namespace thread_detail {
};
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
- thread::id thread::get_id() const BOOST_NOEXCEPT
+ inline thread::id thread::get_id() const BOOST_NOEXCEPT
{
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
return const_cast<thread*>(this)->native_handle();
@@ -768,7 +736,7 @@ namespace thread_detail {
}
}
#endif
- void thread::join() {
+ inline void thread::join() {
if (this_thread::get_id() == get_id())
boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
@@ -777,11 +745,7 @@ namespace thread_detail {
);
}
-#ifdef BOOST_THREAD_PLATFORM_PTHREAD
- bool thread::do_try_join_until(struct timespec const &timeout)
-#else
- bool thread::do_try_join_until(uintmax_t timeout)
-#endif
+ inline bool thread::do_try_join_until(detail::internal_platform_timepoint const &timeout)
{
if (this_thread::get_id() == get_id())
boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
diff --git a/boost/thread/future.hpp b/boost/thread/future.hpp
index 1234cb85a7..e5fd1921b0 100644
--- a/boost/thread/future.hpp
+++ b/boost/thread/future.hpp
@@ -159,7 +159,7 @@ namespace boost
boost::function<void()> callback;
// This declaration should be only included conditionally, but is included to maintain the same layout.
continuations_type continuations;
- executor_ptr_type ex;
+ executor_ptr_type ex_;
// This declaration should be only included conditionally, but is included to maintain the same layout.
virtual void launch_continuation()
@@ -173,43 +173,49 @@ namespace boost
is_constructed(false),
policy_(launch::none),
continuations(),
- ex()
+ ex_()
{}
- shared_state_base(exceptional_ptr const& ex_):
- exception(ex_.ptr_),
+ shared_state_base(exceptional_ptr const& ex):
+ exception(ex.ptr_),
done(true),
is_valid_(true),
is_deferred_(false),
is_constructed(false),
policy_(launch::none),
continuations(),
- ex()
+ ex_()
{}
virtual ~shared_state_base()
{
}
+
+ bool is_done()
+ {
+ return done;
+ }
+
executor_ptr_type get_executor()
{
- return ex;
+ return ex_;
}
void set_executor_policy(executor_ptr_type aex)
{
set_executor();
- ex = aex;
+ ex_ = aex;
}
void set_executor_policy(executor_ptr_type aex, boost::lock_guard<boost::mutex>&)
{
set_executor();
- ex = aex;
+ ex_ = aex;
}
void set_executor_policy(executor_ptr_type aex, boost::unique_lock<boost::mutex>&)
{
set_executor();
- ex = aex;
+ ex_ = aex;
}
bool valid(boost::unique_lock<boost::mutex>&) { return is_valid_; }
@@ -262,6 +268,10 @@ namespace boost
external_waiters.erase(it);
}
+#if 0
+ // this inline definition results in ODR. See https://github.com/boostorg/thread/issues/193
+ // to avoid it, we define the function on the derived templates using the macro BOOST_THREAD_DO_CONTINUATION
+#define BOOST_THREAD_DO_CONTINUATION
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
void do_continuation(boost::unique_lock<boost::mutex>& lock)
{
@@ -279,6 +289,31 @@ namespace boost
{
}
#endif
+
+#else
+#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
+#define BOOST_THREAD_DO_CONTINUATION \
+ void do_continuation(boost::unique_lock<boost::mutex>& lock) \
+ { \
+ if (! this->continuations.empty()) { \
+ continuations_type the_continuations = this->continuations; \
+ this->continuations.clear(); \
+ relocker rlk(lock); \
+ for (continuations_type::iterator it = the_continuations.begin(); it != the_continuations.end(); ++it) { \
+ (*it)->launch_continuation(); \
+ } \
+ } \
+ }
+#else
+#define BOOST_THREAD_DO_CONTINUATION \
+ void do_continuation(boost::unique_lock<boost::mutex>&) \
+ { \
+ }
+#endif
+
+ virtual void do_continuation(boost::unique_lock<boost::mutex>&) = 0;
+#endif
+
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
virtual void set_continuation_ptr(continuation_ptr_type continuation, boost::unique_lock<boost::mutex>& lock)
{
@@ -348,10 +383,7 @@ namespace boost
is_deferred_=false;
execute(lk);
}
- while(!done)
- {
- waiters.wait(lk);
- }
+ waiters.wait(lk, boost::bind(&shared_state_base::is_done, boost::ref(*this)));
if(rethrow && exception)
{
boost::rethrow_exception(exception);
@@ -370,6 +402,17 @@ namespace boost
}
#if defined BOOST_THREAD_USES_DATETIME
+ template<typename Duration>
+ bool timed_wait(Duration const& rel_time)
+ {
+ boost::unique_lock<boost::mutex> lock(this->mutex);
+ if (is_deferred_)
+ return false;
+
+ do_callback(lock);
+ return waiters.timed_wait(lock, rel_time, boost::bind(&shared_state_base::is_done, boost::ref(*this)));
+ }
+
bool timed_wait_until(boost::system_time const& target_time)
{
boost::unique_lock<boost::mutex> lock(this->mutex);
@@ -377,15 +420,7 @@ namespace boost
return false;
do_callback(lock);
- while(!done)
- {
- bool const success=waiters.timed_wait(lock,target_time);
- if(!success && !done)
- {
- return false;
- }
- }
- return true;
+ return waiters.timed_wait(lock, target_time, boost::bind(&shared_state_base::is_done, boost::ref(*this)));
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
@@ -398,13 +433,9 @@ namespace boost
if (is_deferred_)
return future_status::deferred;
do_callback(lock);
- while(!done)
+ if(!waiters.wait_until(lock, abs_time, boost::bind(&shared_state_base::is_done, boost::ref(*this))))
{
- cv_status const st=waiters.wait_until(lock,abs_time);
- if(st==cv_status::timeout && !done)
- {
- return future_status::timeout;
- }
+ return future_status::timeout;
}
return future_status::ready;
}
@@ -546,10 +577,8 @@ namespace boost
detail::shared_state_base(ex), result()
{}
-
- ~shared_state()
- {
- }
+ // locating this definition on the template avoid the ODR issue. See https://github.com/boostorg/thread/issues/193
+ BOOST_THREAD_DO_CONTINUATION
void mark_finished_with_result_internal(source_reference_type result_, boost::unique_lock<boost::mutex>& lock)
{
@@ -732,9 +761,8 @@ namespace boost
detail::shared_state_base(ex), result(0)
{}
- ~shared_state()
- {
- }
+ // locating this definition on the template avoid the ODR issue. See https://github.com/boostorg/thread/issues/193
+ BOOST_THREAD_DO_CONTINUATION
void mark_finished_with_result_internal(source_reference_type result_, boost::unique_lock<boost::mutex>& lock)
{
@@ -811,6 +839,9 @@ namespace boost
detail::shared_state_base(ex)
{}
+ // locating this definition on the template avoid the ODR issue. See https://github.com/boostorg/thread/issues/193
+ BOOST_THREAD_DO_CONTINUATION
+
void mark_finished_with_result_internal(boost::unique_lock<boost::mutex>& lock)
{
mark_finished_internal(lock);
@@ -899,10 +930,7 @@ namespace boost
join();
#elif defined BOOST_THREAD_ASYNC_FUTURE_WAITS
unique_lock<boost::mutex> lk(this->mutex);
- while(!this->done)
- {
- this->waiters.wait(lk);
- }
+ this->waiters.wait(lk, boost::bind(&shared_state_base::is_done, boost::ref(*this)));
#endif
}
@@ -1007,10 +1035,8 @@ namespace boost
template<typename Rp, typename Fp>
struct future_deferred_shared_state: shared_state<Rp>
{
- typedef shared_state<Rp> base_type;
Fp func_;
- public:
explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f)
: func_(boost::move(f))
{
@@ -1035,10 +1061,8 @@ namespace boost
template<typename Rp, typename Fp>
struct future_deferred_shared_state<Rp&,Fp>: shared_state<Rp&>
{
- typedef shared_state<Rp&> base_type;
Fp func_;
- public:
explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f)
: func_(boost::move(f))
{
@@ -1060,10 +1084,8 @@ namespace boost
template<typename Fp>
struct future_deferred_shared_state<void,Fp>: shared_state<void>
{
- typedef shared_state<void> base_type;
Fp func_;
- public:
explicit future_deferred_shared_state(BOOST_THREAD_FWD_REF(Fp) f)
: func_(boost::move(f))
{
@@ -1091,7 +1113,6 @@ namespace boost
public:
typedef std::vector<int>::size_type count_type;
private:
- struct registered_waiter;
struct registered_waiter
{
boost::shared_ptr<detail::shared_state_base> future_;
@@ -1452,7 +1473,11 @@ namespace boost
template<typename Duration>
bool timed_wait(Duration const& rel_time) const
{
- return timed_wait_until(boost::get_system_time()+rel_time);
+ if(!future_)
+ {
+ boost::throw_exception(future_uninitialized());
+ }
+ return future_->timed_wait(rel_time);
}
bool timed_wait_until(boost::system_time const& abs_time) const
@@ -3155,7 +3180,7 @@ namespace boost
}
};
-#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
+#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR)
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
@@ -3497,7 +3522,7 @@ namespace boost
{}
// construction and destruction
-#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
+#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR)
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
@@ -3587,7 +3612,7 @@ namespace boost
#endif
#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS
-#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
+#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR)
template <class Allocator>
packaged_task(boost::allocator_arg_t, Allocator a, R(*f)())
{
@@ -3608,7 +3633,7 @@ namespace boost
task = task_ptr(::new(a2.allocate(1)) task_shared_state_type(f), D(a2, 1) );
future_obtained = false;
}
-#endif // BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
+#endif // BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
template <class F, class Allocator>
@@ -3825,7 +3850,7 @@ namespace detail
// future<R> async(launch policy, F&&, ArgTypes&&...);
////////////////////////////////
-#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
+#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
template <class R, class... ArgTypes>
@@ -3884,7 +3909,7 @@ namespace detail
}
}
#endif
-#endif // defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR)
+#endif // defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR)
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
@@ -4113,7 +4138,7 @@ namespace detail {
//#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
#if defined(BOOST_THREAD_PROVIDES_INVOKE) && ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ! defined(BOOST_NO_CXX11_HDR_TUPLE)
-#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
+#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
template <class Executor, class R, class... ArgTypes>
BOOST_THREAD_FUTURE<R>
@@ -4129,7 +4154,7 @@ namespace detail {
)
));
}
-#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
+#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
template <class Executor, class F, class ...ArgTypes>
BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type(
@@ -4148,7 +4173,7 @@ namespace detail {
}
#else // ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
-#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
+#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
template <class Executor, class R>
BOOST_THREAD_FUTURE<R>
@@ -4178,7 +4203,7 @@ namespace detail {
)
));
}
-#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
+#endif // defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
template <class Executor, class F>
BOOST_THREAD_FUTURE<typename boost::result_of<typename decay<F>::type()>::type>
@@ -4234,7 +4259,7 @@ namespace detail {
// future<R> async(F&&, ArgTypes&&...);
////////////////////////////////
-#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
+#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
template <class R, class... ArgTypes>
BOOST_THREAD_FUTURE<R>
@@ -4956,6 +4981,10 @@ namespace detail {
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type>(
lock, boost::move(*this), boost::forward<F>(func)
)));
+ } else if (underlying_cast<int>(policy) & int(launch::sync)) {
+ return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_sync_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type>(
+ lock, boost::move(*this), boost::forward<F>(func)
+ )));
#ifdef BOOST_THREAD_PROVIDES_EXECUTORS
} else if (underlying_cast<int>(policy) & int(launch::executor)) {
assert(this->future_->get_executor());
@@ -4976,6 +5005,10 @@ namespace detail {
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_deferred_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type>(
lock, boost::move(*this), boost::forward<F>(func)
)));
+ } else if (underlying_cast<int>(policy_) & int(launch::sync)) {
+ return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_future_sync_continuation_shared_state<BOOST_THREAD_FUTURE<R>, future_type>(
+ lock, boost::move(*this), boost::forward<F>(func)
+ )));
#ifdef BOOST_THREAD_PROVIDES_EXECUTORS
} else if (underlying_cast<int>(policy_) & int(launch::executor)) {
assert(this->future_->get_executor());
diff --git a/boost/thread/pthread/condition_variable.hpp b/boost/thread/pthread/condition_variable.hpp
index b66b710a24..285785ff59 100644
--- a/boost/thread/pthread/condition_variable.hpp
+++ b/boost/thread/pthread/condition_variable.hpp
@@ -6,8 +6,10 @@
// (C) Copyright 2007-10 Anthony Williams
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
-#include <boost/thread/pthread/timespec.hpp>
+#include <boost/thread/detail/platform_time.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
+#include <boost/thread/pthread/pthread_helpers.hpp>
+
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
#include <boost/thread/pthread/thread_data.hpp>
#endif
@@ -18,6 +20,8 @@
#endif
#include <boost/thread/detail/delete.hpp>
+#include <algorithm>
+
#include <boost/config/abi_prefix.hpp>
namespace boost
@@ -95,9 +99,18 @@ namespace boost
}
}
+ // 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
inline bool condition_variable::do_wait_until(
unique_lock<mutex>& m,
- struct timespec const &timeout)
+ detail::internal_platform_timepoint const &timeout)
{
#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
if (!m.owns_lock())
@@ -112,12 +125,12 @@ namespace boost
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
pthread_mutex_t* the_mutex = &internal_mutex;
guard.activate(m);
- cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout);
+ cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs());
check_for_interruption.unlock_if_locked();
guard.deactivate();
#else
pthread_mutex_t* the_mutex = m.mutex()->native_handle();
- cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout);
+ cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout.getTs());
#endif
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
@@ -164,11 +177,11 @@ namespace boost
{
boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_mutex_init"));
}
- int const res2 = detail::monotonic_pthread_cond_init(cond);
+ int const res2 = pthread::cond_init(cond);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
- boost::throw_exception(thread_resource_error(res2, "boost::condition_variable_any::condition_variable_any() failed in detail::monotonic_pthread_cond_init"));
+ boost::throw_exception(thread_resource_error(res2, "boost::condition_variable_any::condition_variable_any() failed in pthread::cond_init"));
}
}
~condition_variable_any()
@@ -205,15 +218,35 @@ namespace boost
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)
{
- struct timespec const timeout=detail::to_timespec(abs_time);
- return do_wait_until(m, timeout);
+#if defined BOOST_THREAD_WAIT_BUG
+ const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
+#else
+ const detail::real_platform_timepoint ts(abs_time);
+#endif
+#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+ // 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::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();
+#else
+ return do_wait_until(m, ts);
+#endif
}
template<typename lock_type>
bool timed_wait(lock_type& m,xtime const& abs_time)
@@ -224,18 +257,55 @@ namespace boost
template<typename lock_type,typename duration_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration)
{
- return timed_wait(m,get_system_time()+wait_duration);
+ if (wait_duration.is_pos_infinity())
+ {
+ wait(m);
+ return true;
+ }
+ if (wait_duration.is_special())
+ {
+ return true;
+ }
+ detail::platform_duration d(wait_duration);
+#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
+ // 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::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
+ do_wait_until(m, detail::internal_platform_clock::now() + d);
+ return ts > detail::mono_platform_clock::now();
+#else
+ return do_wait_until(m, detail::internal_platform_clock::now() + d);
+#endif
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::system_time const& abs_time, predicate_type pred)
{
+#if defined BOOST_THREAD_WAIT_BUG
+ const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
+#else
+ const detail::real_platform_timepoint ts(abs_time);
+#endif
while (!pred())
{
- if(!timed_wait(m, abs_time))
- return pred();
+#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+ // 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.
+ 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);
+#else
+ if (!do_wait_until(m, ts)) break; // timeout occurred
+#endif
}
- return true;
+ return pred();
}
template<typename lock_type,typename predicate_type>
@@ -247,24 +317,52 @@ namespace boost
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 timed_wait(m,get_system_time()+wait_duration,pred);
+ if (wait_duration.is_pos_infinity())
+ {
+ while (!pred())
+ {
+ wait(m);
+ }
+ return true;
+ }
+ if (wait_duration.is_special())
+ {
+ return pred();
+ }
+ detail::platform_duration d(wait_duration);
+#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
+ // 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::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
+ while (!pred())
+ {
+ 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);
+ d = ts - detail::mono_platform_clock::now();
+ }
+#else
+ const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
+ while (!pred())
+ {
+ if (!do_wait_until(m, ts)) break; // timeout occurred
+ }
+#endif
+ return pred();
}
#endif
-#ifndef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
#ifdef BOOST_THREAD_USES_CHRONO
template <class lock_type,class Duration>
cv_status
wait_until(
lock_type& lock,
- const chrono::time_point<chrono::system_clock, Duration>& t)
+ const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
{
- using namespace chrono;
- typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
- wait_until(lock,
- nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
- return system_clock::now() < t ? cv_status::no_timeout :
- cv_status::timeout;
+ const boost::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>
@@ -273,11 +371,18 @@ namespace boost
lock_type& lock,
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();
- wait_until(lock, s_now + ceil<nanoseconds>(t - c_now));
- 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>
@@ -286,86 +391,24 @@ namespace boost
lock_type& lock,
const chrono::duration<Rep, Period>& d)
{
- using namespace chrono;
- system_clock::time_point s_now = system_clock::now();
- steady_clock::time_point c_now = steady_clock::now();
- wait_until(lock, s_now + ceil<nanoseconds>(d));
- return steady_clock::now() - c_now < d ? cv_status::no_timeout :
- cv_status::timeout;
-
- }
-
- template <class lock_type>
- cv_status wait_until(
- lock_type& lk,
- chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp)
- {
- using namespace chrono;
- nanoseconds d = tp.time_since_epoch();
- timespec ts = boost::detail::to_timespec(d);
- if (do_wait_until(lk, ts)) return cv_status::no_timeout;
- else return cv_status::timeout;
+ return wait_until(lock, chrono::steady_clock::now() + d);
}
-#endif
-#else // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
-#ifdef BOOST_THREAD_USES_CHRONO
- template <class lock_type, class Duration>
- cv_status
- wait_until(
- lock_type& lock,
- const chrono::time_point<chrono::steady_clock, Duration>& t)
- {
- using namespace chrono;
- typedef time_point<steady_clock, nanoseconds> nano_sys_tmpt;
- wait_until(lock,
- nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
- return steady_clock::now() < t ? cv_status::no_timeout :
- cv_status::timeout;
- }
-
- template <class lock_type, class Clock, class Duration>
- cv_status
+ template <class lock_type, class Duration, class Predicate>
+ bool
wait_until(
- lock_type& lock,
- const chrono::time_point<Clock, Duration>& t)
- {
- using namespace chrono;
- steady_clock::time_point s_now = steady_clock::now();
- typename Clock::time_point c_now = Clock::now();
- wait_until(lock, s_now + ceil<nanoseconds>(t - c_now));
- return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout;
- }
-
- template <class lock_type, class Rep, class Period>
- cv_status
- wait_for(
- lock_type& lock,
- const chrono::duration<Rep, Period>& d)
- {
- using namespace chrono;
- steady_clock::time_point c_now = steady_clock::now();
- wait_until(lock, c_now + ceil<nanoseconds>(d));
- return steady_clock::now() - c_now < d ? cv_status::no_timeout :
- cv_status::timeout;
- }
-
- template <class lock_type>
- inline cv_status wait_until(
- lock_type& lock,
- chrono::time_point<chrono::steady_clock, chrono::nanoseconds> tp)
+ lock_type& lock,
+ const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
+ Predicate pred)
{
- using namespace chrono;
- nanoseconds d = tp.time_since_epoch();
- timespec ts = boost::detail::to_timespec(d);
- if (do_wait_until(lock, ts)) return cv_status::no_timeout;
- else return cv_status::timeout;
+ const detail::internal_platform_timepoint ts(t);
+ while (!pred())
+ {
+ if (!do_wait_until(lock, ts)) break; // timeout occurred
+ }
+ return pred();
}
-#endif
-#endif // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
-
-#ifdef BOOST_THREAD_USES_CHRONO
template <class lock_type, class Clock, class Duration, class Predicate>
bool
wait_until(
@@ -373,12 +416,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>
@@ -388,7 +437,7 @@ namespace boost
const chrono::duration<Rep, Period>& d,
Predicate pred)
{
- return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
+ return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
}
#endif
@@ -403,12 +452,21 @@ namespace boost
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
}
- private: // used by boost::thread::try_join_until
-
+ private:
+
+ // 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 <class lock_type>
bool do_wait_until(
lock_type& m,
- struct timespec const &timeout)
+ detail::internal_platform_timepoint const &timeout)
{
int res=0;
{
@@ -419,7 +477,7 @@ namespace boost
boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
#endif
guard.activate(m);
- res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
+ res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout.getTs());
check_for_interruption.unlock_if_locked();
guard.deactivate();
}
@@ -437,7 +495,6 @@ namespace boost
return true;
}
};
-
}
#include <boost/config/abi_suffix.hpp>
diff --git a/boost/thread/pthread/condition_variable_fwd.hpp b/boost/thread/pthread/condition_variable_fwd.hpp
index 0ea34e238d..dc471d56a0 100644
--- a/boost/thread/pthread/condition_variable_fwd.hpp
+++ b/boost/thread/pthread/condition_variable_fwd.hpp
@@ -13,7 +13,9 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_types.hpp>
#include <boost/thread/thread_time.hpp>
-#include <boost/thread/pthread/timespec.hpp>
+#include <boost/thread/detail/platform_time.hpp>
+#include <boost/thread/pthread/pthread_helpers.hpp>
+
#if defined BOOST_THREAD_USES_DATETIME
#include <boost/thread/xtime.hpp>
#endif
@@ -25,31 +27,12 @@
#include <boost/thread/detail/delete.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
+#include <algorithm>
+
#include <boost/config/abi_prefix.hpp>
namespace boost
{
- namespace detail {
- inline int monotonic_pthread_cond_init(pthread_cond_t& cond) {
-
-#ifdef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
- pthread_condattr_t attr;
- int res = pthread_condattr_init(&attr);
- if (res)
- {
- return res;
- }
- pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
- res=pthread_cond_init(&cond,&attr);
- pthread_condattr_destroy(&attr);
- return res;
-#else
- return pthread_cond_init(&cond,NULL);
-#endif
-
- }
- }
-
class condition_variable
{
private:
@@ -61,21 +44,9 @@ namespace boost
public:
//private: // used by boost::thread::try_join_until
- inline bool do_wait_until(
+ bool do_wait_until(
unique_lock<mutex>& lock,
- struct timespec const &timeout);
-
- bool do_wait_for(
- unique_lock<mutex>& lock,
- struct timespec const &timeout)
- {
-#if defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
- return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now_monotonic()));
-#else
- // old behavior was fine for monotonic
- return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now_realtime()));
-#endif
- }
+ detail::internal_platform_timepoint const &timeout);
public:
BOOST_THREAD_NO_COPYABLE(condition_variable)
@@ -93,14 +64,14 @@ namespace boost
boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread_mutex_init"));
}
//#endif
- res = detail::monotonic_pthread_cond_init(cond);
+ res = pthread::cond_init(cond);
if (res)
{
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
// ditto
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
//#endif
- boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in detail::monotonic_pthread_cond_init"));
+ boost::throw_exception(thread_resource_error(res, "boost::condition_variable::condition_variable() constructor failed in pthread::cond_init"));
}
}
~condition_variable()
@@ -124,20 +95,35 @@ namespace boost
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
- inline bool timed_wait(
+ bool timed_wait(
unique_lock<mutex>& m,
boost::system_time const& abs_time)
{
#if defined BOOST_THREAD_WAIT_BUG
- struct timespec const timeout=detail::to_timespec(abs_time + BOOST_THREAD_WAIT_BUG);
- return do_wait_until(m, timeout);
+ const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
+#else
+ const detail::real_platform_timepoint ts(abs_time);
+#endif
+#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+ // 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::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();
#else
- struct timespec const timeout=detail::to_timespec(abs_time);
- return do_wait_until(m, timeout);
+ return do_wait_until(m, ts);
#endif
}
bool timed_wait(
@@ -154,14 +140,28 @@ namespace boost
{
if (wait_duration.is_pos_infinity())
{
- wait(m); // or do_wait(m,detail::timeout::sentinel());
+ wait(m);
return true;
}
if (wait_duration.is_special())
{
return true;
}
- return timed_wait(m,get_system_time()+wait_duration);
+ detail::platform_duration d(wait_duration);
+#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
+ // 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::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
+ do_wait_until(m, detail::internal_platform_clock::now() + d);
+ return ts > detail::mono_platform_clock::now();
+#else
+ return do_wait_until(m, detail::internal_platform_clock::now() + d);
+#endif
}
template<typename predicate_type>
@@ -169,12 +169,26 @@ namespace boost
unique_lock<mutex>& m,
boost::system_time const& abs_time,predicate_type pred)
{
+#if defined BOOST_THREAD_WAIT_BUG
+ const detail::real_platform_timepoint ts(abs_time + BOOST_THREAD_WAIT_BUG);
+#else
+ const detail::real_platform_timepoint ts(abs_time);
+#endif
while (!pred())
{
- if(!timed_wait(m, abs_time))
- return pred();
+#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+ // 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.
+ 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);
+#else
+ if (!do_wait_until(m, ts)) break; // timeout occurred
+#endif
}
- return true;
+ return pred();
}
template<typename predicate_type>
@@ -194,7 +208,7 @@ namespace boost
{
while (!pred())
{
- wait(m); // or do_wait(m,detail::timeout::sentinel());
+ wait(m);
}
return true;
}
@@ -202,26 +216,41 @@ namespace boost
{
return pred();
}
- return timed_wait(m,get_system_time()+wait_duration,pred);
+ detail::platform_duration d(wait_duration);
+#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
+ // 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::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
+ while (!pred())
+ {
+ 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);
+ d = ts - detail::mono_platform_clock::now();
+ }
+#else
+ const detail::internal_platform_timepoint ts(detail::internal_platform_clock::now() + d);
+ while (!pred())
+ {
+ if (!do_wait_until(m, ts)) break; // timeout occurred
+ }
+#endif
+ return pred();
}
#endif
-#ifndef BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
-
#ifdef BOOST_THREAD_USES_CHRONO
template <class Duration>
cv_status
wait_until(
unique_lock<mutex>& lock,
- const chrono::time_point<chrono::system_clock, Duration>& t)
+ const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
{
- using namespace chrono;
- typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
- wait_until(lock,
- nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
- return system_clock::now() < t ? cv_status::no_timeout :
- cv_status::timeout;
+ 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>
@@ -230,100 +259,44 @@ namespace boost
unique_lock<mutex>& lock,
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();
- wait_until(lock, s_now + ceil<nanoseconds>(t - c_now));
- 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>
cv_status
wait_for(
unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& d)
{
- using namespace chrono;
- system_clock::time_point s_now = system_clock::now();
- steady_clock::time_point c_now = steady_clock::now();
- wait_until(lock, s_now + ceil<nanoseconds>(d));
- return steady_clock::now() - c_now < d ? cv_status::no_timeout :
- cv_status::timeout;
-
- }
-
- inline cv_status wait_until(
- unique_lock<mutex>& lk,
- chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp)
- {
- using namespace chrono;
- nanoseconds d = tp.time_since_epoch();
- timespec ts = boost::detail::to_timespec(d);
- if (do_wait_until(lk, ts)) return cv_status::no_timeout;
- else return cv_status::timeout;
+ return wait_until(lock, chrono::steady_clock::now() + d);
}
-#endif
-#else // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
-#ifdef BOOST_THREAD_USES_CHRONO
-
- template <class Duration>
- cv_status
- wait_until(
- unique_lock<mutex>& lock,
- const chrono::time_point<chrono::steady_clock, Duration>& t)
- {
- using namespace chrono;
- typedef time_point<steady_clock, nanoseconds> nano_sys_tmpt;
- wait_until(lock,
- nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
- return steady_clock::now() < t ? cv_status::no_timeout :
- cv_status::timeout;
- }
-
- template <class Clock, class Duration>
- cv_status
+ template <class Duration, class Predicate>
+ bool
wait_until(
- unique_lock<mutex>& lock,
- const chrono::time_point<Clock, Duration>& t)
- {
- using namespace chrono;
- steady_clock::time_point s_now = steady_clock::now();
- typename Clock::time_point c_now = Clock::now();
- wait_until(lock, s_now + ceil<nanoseconds>(t - c_now));
- return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout;
- }
-
- template <class Rep, class Period>
- cv_status
- wait_for(
- unique_lock<mutex>& lock,
- const chrono::duration<Rep, Period>& d)
- {
- using namespace chrono;
- steady_clock::time_point c_now = steady_clock::now();
- wait_until(lock, c_now + ceil<nanoseconds>(d));
- return steady_clock::now() - c_now < d ? cv_status::no_timeout :
- cv_status::timeout;
- }
-
- inline cv_status wait_until(
- unique_lock<mutex>& lk,
- chrono::time_point<chrono::steady_clock, chrono::nanoseconds> tp)
+ unique_lock<mutex>& lock,
+ const chrono::time_point<detail::internal_chrono_clock, Duration>& t,
+ Predicate pred)
{
- using namespace chrono;
- nanoseconds d = tp.time_since_epoch();
- timespec ts = boost::detail::to_timespec(d);
- if (do_wait_until(lk, ts)) return cv_status::no_timeout;
- else return cv_status::timeout;
+ const detail::internal_platform_timepoint ts(t);
+ while (!pred())
+ {
+ if (!do_wait_until(lock, ts)) break; // timeout occurred
+ }
+ return pred();
}
-#endif
-
-#endif // defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
-#ifdef BOOST_THREAD_USES_CHRONO
template <class Clock, class Duration, class Predicate>
bool
wait_until(
@@ -331,12 +304,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 Rep, class Period, class Predicate>
@@ -346,7 +325,7 @@ namespace boost
const chrono::duration<Rep, Period>& d,
Predicate pred)
{
- return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
+ return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
}
#endif
@@ -359,15 +338,11 @@ namespace boost
void notify_one() BOOST_NOEXCEPT;
void notify_all() BOOST_NOEXCEPT;
-
-
};
BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
-
}
-
#include <boost/config/abi_suffix.hpp>
#endif
diff --git a/boost/thread/pthread/mutex.hpp b/boost/thread/pthread/mutex.hpp
index 9ac808b6f4..6180ac5ebd 100644
--- a/boost/thread/pthread/mutex.hpp
+++ b/boost/thread/pthread/mutex.hpp
@@ -16,24 +16,20 @@
#include <boost/thread/lock_types.hpp>
#endif
#include <boost/thread/thread_time.hpp>
+#if defined BOOST_THREAD_USES_DATETIME
#include <boost/thread/xtime.hpp>
+#endif
#include <boost/assert.hpp>
#include <errno.h>
-#include <boost/thread/pthread/timespec.hpp>
+#include <boost/thread/detail/platform_time.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
+#include <boost/thread/pthread/pthread_helpers.hpp>
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
#endif
#include <boost/thread/detail/delete.hpp>
-#if (defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS-0)>=200112L) \
- || (defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
-#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
-#define BOOST_PTHREAD_HAS_TIMEDLOCK
-#endif
-#endif
-
#include <boost/config/abi_prefix.hpp>
@@ -165,7 +161,7 @@ namespace boost
{
private:
pthread_mutex_t m;
-#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
+#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
pthread_cond_t cond;
bool is_locked;
#endif
@@ -178,13 +174,12 @@ namespace boost
{
boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init"));
}
-#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
- int const res2=pthread_cond_init(&cond,NULL);
+#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
+ int const res2=pthread::cond_init(cond);
if(res2)
{
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
- //BOOST_VERIFY(!pthread_mutex_destroy(&m));
- boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init"));
+ boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread::cond_init"));
}
is_locked=false;
#endif
@@ -192,7 +187,7 @@ namespace boost
~timed_mutex()
{
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
-#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
+#ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
BOOST_VERIFY(!pthread_cond_destroy(&cond));
#endif
}
@@ -201,14 +196,36 @@ namespace boost
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
- return timed_lock(get_system_time()+relative_time);
+ if (relative_time.is_pos_infinity())
+ {
+ lock();
+ return true;
+ }
+ if (relative_time.is_special())
+ {
+ return true;
+ }
+ detail::platform_duration d(relative_time);
+#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
+ const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
+ {
+ d = ts - detail::mono_platform_clock::now();
+ if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ }
+ return true;
+#else
+ return do_try_lock_until(detail::internal_platform_clock::now() + d);
+#endif
}
bool timed_lock(boost::xtime const & absolute_time)
{
return timed_lock(system_time(absolute_time));
}
#endif
-#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
+#ifdef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
void lock()
{
int res = posix::pthread_mutex_lock(&m);
@@ -246,9 +263,9 @@ namespace boost
private:
- bool do_try_lock_until(struct timespec const &timeout)
+ bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
{
- int const res=pthread_mutex_timedlock(&m,&timeout);
+ int const res=pthread_mutex_timedlock(&m,&timeout.getTs());
BOOST_ASSERT(!res || res==ETIMEDOUT);
return !res;
}
@@ -284,18 +301,22 @@ namespace boost
}
private:
- bool do_try_lock_until(struct timespec const &timeout)
+ bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
while(is_locked)
{
- int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
+ int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout.getTs());
if(cond_res==ETIMEDOUT)
{
- return false;
+ break;
}
BOOST_ASSERT(!cond_res);
}
+ if(is_locked)
+ {
+ return false;
+ }
is_locked=true;
return true;
}
@@ -305,8 +326,20 @@ namespace boost
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock(system_time const & abs_time)
{
- struct timespec const ts=boost::detail::to_timespec(abs_time);
+ const detail::real_platform_timepoint ts(abs_time);
+#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+ detail::platform_duration d(ts - detail::real_platform_clock::now());
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
+ {
+ d = ts - detail::real_platform_clock::now();
+ if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ }
+ return true;
+#else
return do_try_lock_until(ts);
+#endif
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
@@ -318,23 +351,21 @@ namespace boost
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<nanoseconds>(t - c_now));
+ typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
+ common_duration d(t - Clock::now());
+ d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
+ while ( ! try_lock_until(detail::internal_chrono_clock::now() + d))
+ {
+ d = t - Clock::now();
+ if ( d <= common_duration::zero() ) return false; // timeout occurred
+ d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
+ }
+ return true;
}
template <class Duration>
- bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
+ bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
{
- using namespace chrono;
- typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
- return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
- }
- bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
- {
- //using namespace chrono;
- chrono::nanoseconds d = tp.time_since_epoch();
- timespec ts = boost::detail::to_timespec(d);
+ detail::internal_platform_timepoint ts(t);
return do_try_lock_until(ts);
}
#endif
@@ -352,7 +383,6 @@ namespace boost
typedef scoped_timed_lock scoped_lock;
#endif
};
-
}
#include <boost/config/abi_suffix.hpp>
diff --git a/boost/thread/pthread/pthread_helpers.hpp b/boost/thread/pthread/pthread_helpers.hpp
new file mode 100644
index 0000000000..c1ff0f9239
--- /dev/null
+++ b/boost/thread/pthread/pthread_helpers.hpp
@@ -0,0 +1,42 @@
+#ifndef BOOST_THREAD_PTHREAD_PTHREAD_HELPERS_HPP
+#define BOOST_THREAD_PTHREAD_PTHREAD_HELPERS_HPP
+// Copyright (C) 2017
+// Vicente J. Botet Escriba
+//
+// Distributed under the Boost Software License, Version 1.0. (See
+// accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/thread/detail/config.hpp>
+#include <pthread.h>
+
+#include <boost/config/abi_prefix.hpp>
+
+namespace boost
+{
+ namespace pthread
+ {
+ inline int cond_init(pthread_cond_t& cond) {
+
+ #ifdef BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+ pthread_condattr_t attr;
+ int res = pthread_condattr_init(&attr);
+ if (res)
+ {
+ return res;
+ }
+ pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+ res=pthread_cond_init(&cond,&attr);
+ pthread_condattr_destroy(&attr);
+ return res;
+ #else
+ return pthread_cond_init(&cond,NULL);
+ #endif
+
+ }
+ }
+}
+
+#include <boost/config/abi_suffix.hpp>
+
+#endif
diff --git a/boost/thread/pthread/recursive_mutex.hpp b/boost/thread/pthread/recursive_mutex.hpp
index 4caae0b5df..ce9a8ce44b 100644
--- a/boost/thread/pthread/recursive_mutex.hpp
+++ b/boost/thread/pthread/recursive_mutex.hpp
@@ -19,27 +19,22 @@
#endif
#include <boost/date_time/posix_time/conversion.hpp>
#include <errno.h>
-#include <boost/thread/pthread/timespec.hpp>
+#include <boost/thread/detail/platform_time.hpp>
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
+#include <boost/thread/pthread/pthread_helpers.hpp>
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
#endif
#include <boost/thread/detail/delete.hpp>
-#if (defined _POSIX_TIMEOUTS && (_POSIX_TIMEOUTS-0)>=200112L) \
- || (defined __ANDROID__ && defined __ANDROID_API__ && __ANDROID_API__ >= 21)
-#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
-#define BOOST_PTHREAD_HAS_TIMEDLOCK
-#endif
-#endif
#if defined BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE \
|| defined __ANDROID__
#define BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE
#endif
-#if defined BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE && defined BOOST_PTHREAD_HAS_TIMEDLOCK
+#if defined BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE && defined BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
#define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
#endif
@@ -89,11 +84,11 @@ namespace boost
{
boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init"));
}
- int const res2=pthread_cond_init(&cond,NULL);
+ int const res2=pthread::cond_init(cond);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
- boost::throw_exception(thread_resource_error(res2, "boost:: recursive_mutex constructor failed in pthread_cond_init"));
+ boost::throw_exception(thread_resource_error(res2, "boost:: recursive_mutex constructor failed in pthread::cond_init"));
}
is_locked=false;
count=0;
@@ -224,11 +219,11 @@ namespace boost
{
boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init"));
}
- int const res2=pthread_cond_init(&cond,NULL);
+ int const res2=pthread::cond_init(cond);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
- boost::throw_exception(thread_resource_error(res2, "boost:: recursive_timed_mutex constructor failed in pthread_cond_init"));
+ boost::throw_exception(thread_resource_error(res2, "boost:: recursive_timed_mutex constructor failed in pthread::cond_init"));
}
is_locked=false;
count=0;
@@ -246,7 +241,29 @@ namespace boost
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
- return timed_lock(get_system_time()+relative_time);
+ if (relative_time.is_pos_infinity())
+ {
+ lock();
+ return true;
+ }
+ if (relative_time.is_special())
+ {
+ return true;
+ }
+ detail::platform_duration d(relative_time);
+#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
+ const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
+ {
+ d = ts - detail::mono_platform_clock::now();
+ if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ }
+ return true;
+#else
+ return do_try_lock_until(detail::internal_platform_clock::now() + d);
+#endif
}
#endif
@@ -268,9 +285,9 @@ namespace boost
return !res;
}
private:
- bool do_try_lock_until(struct timespec const &timeout)
+ bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
{
- int const res=pthread_mutex_timedlock(&m,&timeout);
+ int const res=pthread_mutex_timedlock(&m,&timeout.getTs());
BOOST_ASSERT(!res || res==ETIMEDOUT);
return !res;
}
@@ -320,7 +337,7 @@ namespace boost
}
private:
- bool do_try_lock_until(struct timespec const &timeout)
+ bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
if(is_locked && pthread_equal(owner,pthread_self()))
@@ -330,13 +347,17 @@ namespace boost
}
while(is_locked)
{
- int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
+ int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout.getTs());
if(cond_res==ETIMEDOUT)
{
- return false;
+ break;
}
BOOST_ASSERT(!cond_res);
}
+ if(is_locked)
+ {
+ return false;
+ }
is_locked=true;
++count;
owner=pthread_self();
@@ -349,8 +370,20 @@ namespace boost
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock(system_time const & abs_time)
{
- struct timespec const ts=detail::to_timespec(abs_time);
+ const detail::real_platform_timepoint ts(abs_time);
+#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
+ detail::platform_duration d(ts - detail::real_platform_clock::now());
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
+ {
+ d = ts - detail::real_platform_clock::now();
+ if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
+ d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
+ }
+ return true;
+#else
return do_try_lock_until(ts);
+#endif
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
@@ -362,23 +395,22 @@ namespace boost
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<nanoseconds>(t - c_now));
+ typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
+ common_duration d(t - Clock::now());
+ d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
+ while ( ! try_lock_until(detail::internal_chrono_clock::now() + d))
+ {
+ d = t - Clock::now();
+ if ( d <= common_duration::zero() ) return false; // timeout occurred
+ d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
+ }
+ return true;
+
}
template <class Duration>
- bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
- {
- using namespace chrono;
- typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
- return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
- }
- bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
+ bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
{
- //using namespace chrono;
- chrono::nanoseconds d = tp.time_since_epoch();
- timespec ts = boost::detail::to_timespec(d);
+ detail::internal_platform_timepoint ts(t);
return do_try_lock_until(ts);
}
#endif
diff --git a/boost/thread/pthread/shared_mutex.hpp b/boost/thread/pthread/shared_mutex.hpp
index e4ec24fe3f..ed9a296f2e 100644
--- a/boost/thread/pthread/shared_mutex.hpp
+++ b/boost/thread/pthread/shared_mutex.hpp
@@ -9,6 +9,7 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/assert.hpp>
+#include <boost/bind.hpp>
#include <boost/static_assert.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
@@ -78,11 +79,6 @@ namespace boost
return ! (shared_count || exclusive);
}
- void exclusive_blocked (bool blocked)
- {
- exclusive_waiting_blocked = blocked;
- }
-
void lock ()
{
exclusive = true;
@@ -99,17 +95,19 @@ namespace boost
return ! (exclusive || exclusive_waiting_blocked);
}
- bool more_shared () const
+ bool no_shared () const
{
- return shared_count > 0 ;
+ return shared_count==0;
}
- unsigned get_shared_count () const
+
+ bool one_shared () const
{
- return shared_count ;
+ return shared_count==1;
}
- unsigned lock_shared ()
+
+ void lock_shared ()
{
- return ++shared_count;
+ ++shared_count;
}
@@ -118,18 +116,6 @@ namespace boost
--shared_count;
}
- bool unlock_shared_downgrades()
- {
- if (upgrade) {
- upgrade=false;
- exclusive=true;
- return true;
- } else {
- exclusive_waiting_blocked=false;
- return false;
- }
- }
-
void lock_upgrade ()
{
++shared_count;
@@ -185,10 +171,7 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
- while(!state.can_lock_shared())
- {
- shared_cond.wait(lk);
- }
+ shared_cond.wait(lk, boost::bind(&state_data::can_lock_shared, boost::ref(state)));
state.lock_shared();
}
@@ -211,13 +194,9 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
-
- while(!state.can_lock_shared())
+ if(!shared_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock_shared, boost::ref(state))))
{
- if(!shared_cond.timed_wait(lk,timeout))
- {
- return false;
- }
+ return false;
}
state.lock_shared();
return true;
@@ -226,7 +205,16 @@ namespace boost
template<typename TimeDuration>
bool timed_lock_shared(TimeDuration const & relative_time)
{
- return timed_lock_shared(get_system_time()+relative_time);
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ boost::this_thread::disable_interruption do_not_disturb;
+#endif
+ boost::unique_lock<boost::mutex> lk(state_change);
+ if(!shared_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock_shared, boost::ref(state))))
+ {
+ return false;
+ }
+ state.lock_shared();
+ return true;
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
@@ -242,14 +230,9 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
-
- while(!state.can_lock_shared())
- //while(state.exclusive || state.exclusive_waiting_blocked)
+ if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_shared, boost::ref(state))))
{
- if(cv_status::timeout==shared_cond.wait_until(lk,abs_time))
- {
- return false;
- }
+ return false;
}
state.lock_shared();
return true;
@@ -260,11 +243,11 @@ namespace boost
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
state.unlock_shared();
- if (! state.more_shared())
+ if (state.no_shared())
{
if (state.upgrade)
{
- // As there is a thread doing a unlock_upgrade_and_lock that is waiting for ! state.more_shared()
+ // As there is a thread doing a unlock_upgrade_and_lock that is waiting for state.no_shared()
// avoid other threads to lock, lock_upgrade or lock_shared, so only this thread is notified.
state.upgrade=false;
state.exclusive=true;
@@ -286,12 +269,8 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
-
- while (state.shared_count || state.exclusive)
- {
- state.exclusive_waiting_blocked=true;
- exclusive_cond.wait(lk);
- }
+ state.exclusive_waiting_blocked=true;
+ exclusive_cond.wait(lk, boost::bind(&state_data::can_lock, boost::ref(state)));
state.exclusive=true;
}
@@ -302,20 +281,12 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
-
- while(state.shared_count || state.exclusive)
+ state.exclusive_waiting_blocked=true;
+ if(!exclusive_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock, boost::ref(state))))
{
- state.exclusive_waiting_blocked=true;
- if(!exclusive_cond.timed_wait(lk,timeout))
- {
- if(state.shared_count || state.exclusive)
- {
- state.exclusive_waiting_blocked=false;
- release_waiters();
- return false;
- }
- break;
- }
+ state.exclusive_waiting_blocked=false;
+ release_waiters();
+ return false;
}
state.exclusive=true;
return true;
@@ -324,7 +295,19 @@ namespace boost
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
- return timed_lock(get_system_time()+relative_time);
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ boost::this_thread::disable_interruption do_not_disturb;
+#endif
+ boost::unique_lock<boost::mutex> lk(state_change);
+ state.exclusive_waiting_blocked=true;
+ if(!exclusive_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock, boost::ref(state))))
+ {
+ state.exclusive_waiting_blocked=false;
+ release_waiters();
+ return false;
+ }
+ state.exclusive=true;
+ return true;
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
@@ -340,20 +323,12 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
-
- while(state.shared_count || state.exclusive)
+ state.exclusive_waiting_blocked=true;
+ if(!exclusive_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock, boost::ref(state))))
{
- state.exclusive_waiting_blocked=true;
- if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time))
- {
- if(state.shared_count || state.exclusive)
- {
- state.exclusive_waiting_blocked=false;
- release_waiters();
- return false;
- }
- break;
- }
+ state.exclusive_waiting_blocked=false;
+ release_waiters();
+ return false;
}
state.exclusive=true;
return true;
@@ -363,17 +338,12 @@ namespace boost
bool try_lock()
{
boost::unique_lock<boost::mutex> lk(state_change);
-
- if(state.shared_count || state.exclusive)
+ if(!state.can_lock())
{
return false;
}
- else
- {
- state.exclusive=true;
- return true;
- }
-
+ state.exclusive=true;
+ return true;
}
void unlock()
@@ -392,10 +362,7 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
- while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
- {
- shared_cond.wait(lk);
- }
+ shared_cond.wait(lk, boost::bind(&state_data::can_lock_upgrade, boost::ref(state)));
state.lock_shared();
state.upgrade=true;
}
@@ -407,16 +374,9 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
- while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
+ if(!shared_cond.timed_wait(lk, timeout, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
{
- if(!shared_cond.timed_wait(lk,timeout))
- {
- if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
- {
- return false;
- }
- break;
- }
+ return false;
}
state.lock_shared();
state.upgrade=true;
@@ -426,7 +386,17 @@ namespace boost
template<typename TimeDuration>
bool timed_lock_upgrade(TimeDuration const & relative_time)
{
- return timed_lock_upgrade(get_system_time()+relative_time);
+#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
+ boost::this_thread::disable_interruption do_not_disturb;
+#endif
+ boost::unique_lock<boost::mutex> lk(state_change);
+ if(!shared_cond.timed_wait(lk, relative_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
+ {
+ return false;
+ }
+ state.lock_shared();
+ state.upgrade=true;
+ return true;
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
@@ -442,16 +412,9 @@ namespace boost
boost::this_thread::disable_interruption do_not_disturb;
#endif
boost::unique_lock<boost::mutex> lk(state_change);
- while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
+ if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
{
- if(cv_status::timeout == shared_cond.wait_until(lk,abs_time))
- {
- if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
- {
- return false;
- }
- break;
- }
+ return false;
}
state.lock_shared();
state.upgrade=true;
@@ -461,17 +424,14 @@ namespace boost
bool try_lock_upgrade()
{
boost::unique_lock<boost::mutex> lk(state_change);
- if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
+ if(!state.can_lock_upgrade())
{
return false;
}
- else
- {
- state.lock_shared();
- state.upgrade=true;
- state.assert_lock_upgraded();
- return true;
- }
+ state.lock_shared();
+ state.upgrade=true;
+ state.assert_lock_upgraded();
+ return true;
}
void unlock_upgrade()
@@ -479,7 +439,7 @@ namespace boost
boost::unique_lock<boost::mutex> lk(state_change);
//state.upgrade=false;
state.unlock_upgrade();
- if(! state.more_shared() )
+ if(state.no_shared())
{
state.exclusive_waiting_blocked=false;
release_waiters();
@@ -497,10 +457,7 @@ namespace boost
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
state.unlock_shared();
- while (state.more_shared())
- {
- upgrade_cond.wait(lk);
- }
+ upgrade_cond.wait(lk, boost::bind(&state_data::no_shared, boost::ref(state)));
state.upgrade=false;
state.exclusive=true;
state.assert_locked();
@@ -554,16 +511,9 @@ namespace boost
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_upgraded();
- if (state.shared_count != 1)
+ if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::one_shared, boost::ref(state))))
{
- for (;;)
- {
- cv_status status = shared_cond.wait_until(lk,abs_time);
- if (state.shared_count == 1)
- break;
- if(status == cv_status::timeout)
- return false;
- }
+ return false;
}
state.upgrade=false;
state.exclusive=true;
@@ -619,16 +569,9 @@ namespace boost
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
- if (state.shared_count != 1)
+ if(!shared_cond.wait_until(lk, abs_time, boost::bind(&state_data::one_shared, boost::ref(state))))
{
- for (;;)
- {
- cv_status status = shared_cond.wait_until(lk,abs_time);
- if (state.shared_count == 1)
- break;
- if(status == cv_status::timeout)
- return false;
- }
+ return false;
}
state.upgrade=false;
state.exclusive=true;
@@ -654,10 +597,7 @@ namespace boost
{
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
- if( !state.exclusive
- && !state.exclusive_waiting_blocked
- && !state.upgrade
- )
+ if(state.can_lock_upgrade())
{
state.upgrade=true;
return true;
@@ -683,22 +623,9 @@ namespace boost
#endif
boost::unique_lock<boost::mutex> lk(state_change);
state.assert_lock_shared();
- if( state.exclusive
- || state.exclusive_waiting_blocked
- || state.upgrade
- )
+ if(!exclusive_cond.wait_until(lk, abs_time, boost::bind(&state_data::can_lock_upgrade, boost::ref(state))))
{
- for (;;)
- {
- cv_status status = exclusive_cond.wait_until(lk,abs_time);
- if( ! state.exclusive
- && ! state.exclusive_waiting_blocked
- && ! state.upgrade
- )
- break;
- if(status == cv_status::timeout)
- return false;
- }
+ return false;
}
state.upgrade=true;
return true;
diff --git a/boost/thread/pthread/shared_mutex_assert.hpp b/boost/thread/pthread/shared_mutex_assert.hpp
deleted file mode 100644
index 186ab7984b..0000000000
--- a/boost/thread/pthread/shared_mutex_assert.hpp
+++ /dev/null
@@ -1,724 +0,0 @@
-#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
-#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
-
-// (C) Copyright 2006-8 Anthony Williams
-// (C) Copyright 2012 Vicente J. Botet Escriba
-//
-// Distributed under the Boost Software License, Version 1.0. (See
-// accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-#include <boost/assert.hpp>
-#include <boost/static_assert.hpp>
-#include <boost/thread/mutex.hpp>
-#include <boost/thread/condition_variable.hpp>
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
-#include <boost/thread/detail/thread_interruption.hpp>
-#endif
-#ifdef BOOST_THREAD_USES_CHRONO
-#include <boost/chrono/system_clocks.hpp>
-#include <boost/chrono/ceil.hpp>
-#endif
-#include <boost/thread/detail/delete.hpp>
-#include <boost/assert.hpp>
-
-#include <boost/config/abi_prefix.hpp>
-
-namespace boost
-{
- class shared_mutex
- {
- private:
- class state_data
- {
- public:
- state_data () :
- shared_count(0),
- exclusive(false),
- upgrade(false),
- exclusive_waiting_blocked(false)
- {}
-
- void assert_free() const
- {
- BOOST_ASSERT( ! exclusive );
- BOOST_ASSERT( ! upgrade );
- BOOST_ASSERT( shared_count==0 );
- }
-
- void assert_locked() const
- {
- BOOST_ASSERT( exclusive );
- BOOST_ASSERT( shared_count==0 );
- BOOST_ASSERT( ! upgrade );
- }
-
- void assert_lock_shared () const
- {
- BOOST_ASSERT( ! exclusive );
- BOOST_ASSERT( shared_count>0 );
- //BOOST_ASSERT( (! upgrade) || (shared_count>1));
- // if upgraded there are at least 2 threads sharing the mutex,
- // except when unlock_upgrade_and_lock has decreased the number of readers but has not taken yet exclusive ownership.
- }
-
- void assert_lock_upgraded () const
- {
- BOOST_ASSERT( ! exclusive );
- BOOST_ASSERT( upgrade );
- BOOST_ASSERT( shared_count>0 );
- }
-
- void assert_lock_not_upgraded () const
- {
- BOOST_ASSERT( ! upgrade );
- }
-
- bool can_lock () const
- {
- return ! (shared_count || exclusive);
- }
-
- void exclusive_blocked (bool blocked)
- {
- exclusive_waiting_blocked = blocked;
- }
-
- void lock ()
- {
- exclusive = true;
- }
-
- void unlock ()
- {
- exclusive = false;
- exclusive_waiting_blocked = false;
- }
-
- bool can_lock_shared () const
- {
- return ! (exclusive || exclusive_waiting_blocked);
- }
-
- bool is_last_shared () const
- {
- return !shared_count ;
- }
- unsigned get_shared_count () const
- {
- return shared_count ;
- }
- unsigned lock_shared ()
- {
- return ++shared_count;
- }
-
-
- void unlock_shared ()
- {
- --shared_count;
- }
-
- bool unlock_shared_downgrades()
- {
- if (upgrade) {
- upgrade=false;
- exclusive=true;
- return true;
- } else {
- exclusive_waiting_blocked=false;
- return false;
- }
- }
-
- void lock_upgrade ()
- {
- lock_shared ();
- upgrade=true;
- }
- bool can_lock_upgrade () const
- {
- return ! (exclusive || exclusive_waiting_blocked || upgrade);
- }
-
- void unlock_upgrade ()
- {
- upgrade=false;
- unlock_shared();
- }
-
- //private:
- unsigned shared_count;
- bool exclusive;
- bool upgrade;
- bool exclusive_waiting_blocked;
- };
-
-
-
- state_data state;
- boost::mutex state_change;
- boost::condition_variable shared_cond;
- boost::condition_variable exclusive_cond;
- boost::condition_variable upgrade_cond;
-
- void release_waiters()
- {
- exclusive_cond.notify_one();
- shared_cond.notify_all();
- }
-
- public:
- BOOST_THREAD_NO_COPYABLE(shared_mutex)
-
- shared_mutex()
- {
- }
-
- ~shared_mutex()
- {
- }
-
- void lock_shared()
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
-
- while(!state.can_lock_shared())
- {
- shared_cond.wait(lk);
- }
- state.lock_shared();
- }
-
- bool try_lock_shared()
- {
- boost::unique_lock<boost::mutex> lk(state_change);
- if(!state.can_lock_shared())
- {
- return false;
- }
- else
- {
- state.lock_shared();
- return true;
- }
- }
-
-#if defined BOOST_THREAD_USES_DATETIME
- bool timed_lock_shared(system_time const& timeout)
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
-
- while(!state.can_lock_shared())
- {
- if(!shared_cond.timed_wait(lk,timeout))
- {
- return false;
- }
- }
- state.lock_shared();
- return true;
- }
-
- template<typename TimeDuration>
- bool timed_lock_shared(TimeDuration const & relative_time)
- {
- return timed_lock_shared(get_system_time()+relative_time);
- }
-#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>& abs_time)
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
-
- while(!state.can_lock_shared())
- {
- if(cv_status::timeout==shared_cond.wait_until(lk,abs_time))
- {
- return false;
- }
- }
- state.lock_shared();
- return true;
- }
-#endif
- void unlock_shared()
- {
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_lock_shared();
- state.unlock_shared();
- if (state.get_shared_count () == 0)
- {
- if (state.unlock_shared_downgrades())
- {
- lk.unlock();
- upgrade_cond.notify_one();
- } else {
- lk.unlock();
- }
- release_waiters();
- }
- }
-
- void lock()
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
-
- while(!state.can_lock())
- {
- state.exclusive_blocked(true);
- exclusive_cond.wait(lk);
- }
- state.lock();
- }
-
-#if defined BOOST_THREAD_USES_DATETIME
- bool timed_lock(system_time const& timeout)
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
-
- while(!state.can_lock())
- {
- state.exclusive_blocked(true);
- if(!exclusive_cond.timed_wait(lk,timeout))
- {
- if(!state.can_lock())
- {
- state.exclusive_blocked(false);
- release_waiters();
- return false;
- }
- break;
- }
- }
- state.exclusive=true;
- //state.lock();
- return true;
- }
-
- template<typename TimeDuration>
- bool timed_lock(TimeDuration const & relative_time)
- {
- return timed_lock(get_system_time()+relative_time);
- }
-#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>& abs_time)
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
-
- while(!state.can_lock())
- {
- state.exclusive_blocked(true);
- if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time))
- {
- if(!state.can_lock())
- {
- state.exclusive_blocked(false);
- release_waiters();
- return false;
- }
- break;
- }
- }
- state.exclusive=true;
- //state.lock();
- return true;
- }
-#endif
-
- bool try_lock()
- {
- boost::unique_lock<boost::mutex> lk(state_change);
-
- if(!state.can_lock())
- {
- return false;
- }
- else
- {
- state.lock();
- return true;
- }
-
- }
-
- void unlock()
- {
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_locked();
- state.unlock();
- state.assert_free();
- release_waiters();
- }
-
- void lock_upgrade()
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
- while(!state.can_lock_upgrade())
- {
- shared_cond.wait(lk);
- }
- state.lock_upgrade();
- }
-
-#if defined BOOST_THREAD_USES_DATETIME
- bool timed_lock_upgrade(system_time const& timeout)
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
- while(!state.can_lock_upgrade())
- {
- if(!shared_cond.timed_wait(lk,timeout))
- {
- if(!state.can_lock_upgrade())
- {
- return false;
- }
- break;
- }
- }
- state.lock_upgrade();
- return true;
- }
-
- template<typename TimeDuration>
- bool timed_lock_upgrade(TimeDuration const & relative_time)
- {
- return timed_lock_upgrade(get_system_time()+relative_time);
- }
-#endif
-#ifdef BOOST_THREAD_USES_CHRONO
- template <class Rep, class Period>
- bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time)
- {
- return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
- }
- template <class Clock, class Duration>
- bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time)
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
- while(!state.can_lock_upgrade())
- {
- if(cv_status::timeout == shared_cond.wait_until(lk,abs_time))
- {
- if(!state.can_lock_upgrade())
- {
- return false;
- }
- break;
- }
- }
- state.lock_upgrade();
- return true;
- }
-#endif
- bool try_lock_upgrade()
- {
- boost::unique_lock<boost::mutex> lk(state_change);
- if(!state.can_lock_upgrade())
- {
- return false;
- }
- else
- {
- state.lock_upgrade();
- state.assert_lock_upgraded();
- return true;
- }
- }
-
- void unlock_upgrade()
- {
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_lock_upgraded();
- state.unlock_upgrade();
- state.assert_lock_not_upgraded ();
- if(state.get_shared_count () == 0)
- {
- state.exclusive_blocked(false);
- lk.unlock();
- release_waiters();
- } else {
- lk.unlock();
- shared_cond.notify_all();
- }
- }
-
- // Upgrade <-> Exclusive
- void unlock_upgrade_and_lock()
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_lock_upgraded();
- // assert state.get_shared_count() >=1
- while(
- //! state.exclusive_waiting_blocked // Fixme: is this needed?
- //&&
- state.get_shared_count()!=1)
- {
- upgrade_cond.wait(lk);
- }
- state.unlock_upgrade();
- state.lock();
- state.assert_locked();
- }
-
- void unlock_and_lock_upgrade()
- {
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_locked();
- state.unlock();
- state.lock_upgrade();
- state.assert_lock_upgraded();
- release_waiters();
- }
-
- bool try_unlock_upgrade_and_lock()
- {
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_lock_upgraded();
- if( //!state.exclusive // this should be removed once the assertion work
- ! state.exclusive_waiting_blocked // Fixme: why this is needed?
- //&& state.upgrade // this should be removed once the assertion work
- && state.get_shared_count()==1)
- {
- state.unlock_upgrade();
- state.lock();
- state.assert_locked();
- return true;
- }
- 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)
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_lock_upgraded();
- if (//state.exclusive // this should be removed once the assertion work
- state.exclusive_waiting_blocked // Fixme: is this needed?
- //|| ! state.upgrade // this should be removed once the assertion work
- || state.get_shared_count() != 1)
- {
- for (;;)
- {
- //cv_status status = shared_cond.wait_until(lk,abs_time);
- cv_status status = upgrade_cond.wait_until(lk,abs_time);
- if (//!state.exclusive // this should be removed once the assertion work
- ! state.exclusive_waiting_blocked // Fixme: is this needed?
- //&& ! state.upgrade // this should be removed once the assertion work
- && state.get_shared_count() == 1)
- break;
- if(status == cv_status::timeout)
- return false;
- }
- }
- state.unlock_upgrade();
- state.lock();
- return true;
- }
-#endif
-
- // Shared <-> Exclusive
- void unlock_and_lock_shared()
- {
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_locked();
- state.unlock();
- state.lock_shared();
- release_waiters();
- }
-
-#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
- bool try_unlock_shared_and_lock()
- {
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_lock_shared();
- if( //!state.exclusive // this should be removed once the assertion work
- ! state.exclusive_waiting_blocked // Fixme: why this is needed?
- //&& ! state.upgrade // Fixme: why this is needed if state.get_shared_count()==1?
- && state.get_shared_count()==1)
- {
- state.unlock_shared();
- state.lock();
- return true;
- }
- return false;
- }
-#ifdef BOOST_THREAD_USES_CHRONO
- template <class Rep, class Period>
- bool
- try_unlock_shared_and_lock_for(
- const chrono::duration<Rep, Period>& rel_time)
- {
- return try_unlock_shared_and_lock_until(
- chrono::steady_clock::now() + rel_time);
- }
- template <class Clock, class Duration>
- bool
- try_unlock_shared_and_lock_until(
- const chrono::time_point<Clock, Duration>& abs_time)
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_lock_shared();
- if ( // !state.exclusive // this should be removed once the assertion work
- state.exclusive_waiting_blocked // Fixme: is this needed?
- //|| state.upgrade // Fixme: why this is needed if state.get_shared_count()==1?
- || state.get_shared_count() != 1)
- {
- for (;;)
- {
- cv_status status = shared_cond.wait_until(lk,abs_time);
- if ( //! state.exclusive // this should be removed once the assertion work
- ! state.exclusive_waiting_blocked // Fixme: is this needed?
- //&& ! state.upgrade
- && state.get_shared_count() == 1)
- break;
- if(status == cv_status::timeout)
- return false;
- }
- }
- state.unlock_shared();
- state.lock();
- state.upgrade=false; // Is this absolutely needed?
- state.exclusive_waiting_blocked=false; // Is this absolutely needed?
- return true;
- }
-#endif
-#endif
-
- // Shared <-> Upgrade
- void unlock_upgrade_and_lock_shared()
- {
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_lock_upgraded();
- //state.unlock_upgrade();
- //state.lock_shared(); // less efficient
- state.upgrade=false;
- state.exclusive_waiting_blocked=false; // Is this absolutely needed?
- release_waiters();
- }
-
-#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
- bool try_unlock_shared_and_lock_upgrade()
- {
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_lock_shared();
- if( //! state.exclusive // this should be removed once the assertion work
- ! state.exclusive_waiting_blocked // Fixme: is this needed?
- && ! state.upgrade
- )
- {
- state.upgrade=true;
- return true;
- }
- return false;
- }
-#ifdef BOOST_THREAD_USES_CHRONO
- template <class Rep, class Period>
- bool
- try_unlock_shared_and_lock_upgrade_for(
- const chrono::duration<Rep, Period>& rel_time)
- {
- return try_unlock_shared_and_lock_upgrade_until(
- chrono::steady_clock::now() + rel_time);
- }
- template <class Clock, class Duration>
- bool
- try_unlock_shared_and_lock_upgrade_until(
- const chrono::time_point<Clock, Duration>& abs_time)
- {
-#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
- boost::this_thread::disable_interruption do_not_disturb;
-#endif
- boost::unique_lock<boost::mutex> lk(state_change);
- state.assert_lock_shared();
- if( //state.exclusive // this should be removed once the assertion work
- state.exclusive_waiting_blocked // Fixme: is this needed?
- || state.upgrade
- )
- {
- for (;;)
- {
- cv_status status = exclusive_cond.wait_until(lk,abs_time);
- if( //! state.exclusive // this should be removed once the assertion work
- ! state.exclusive_waiting_blocked // Fixme: is this needed?
- && ! state.upgrade
- )
- break;
- if(status == cv_status::timeout)
- return false;
- }
- }
- //state.unlock_shared();
- //state.lock_upgrade(); // less efficient
- state.upgrade=true;
- return true;
- }
-#endif
-#endif
- };
-
- typedef shared_mutex upgrade_mutex;
-}
-
-#include <boost/config/abi_suffix.hpp>
-
-#endif
diff --git a/boost/thread/pthread/thread_data.hpp b/boost/thread/pthread/thread_data.hpp
index f6575f1c22..859ccfbd2a 100644
--- a/boost/thread/pthread/thread_data.hpp
+++ b/boost/thread/pthread/thread_data.hpp
@@ -16,6 +16,7 @@
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/assert.hpp>
+#include <boost/thread/detail/platform_time.hpp>
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#endif
@@ -111,8 +112,6 @@ namespace boost
pthread_t thread_handle;
boost::mutex data_mutex;
boost::condition_variable done_condition;
- boost::mutex sleep_mutex;
- boost::condition_variable sleep_condition;
bool done;
bool join_started;
bool joined;
@@ -241,66 +240,158 @@ namespace boost
namespace this_thread
{
+ void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT;
+
namespace hidden
{
- void BOOST_THREAD_DECL sleep_for(const timespec& ts);
- void BOOST_THREAD_DECL sleep_until_realtime(const timespec& ts);
+ inline bool always_false()
+ {
+ return false;
+ }
+ }
+
+#if defined BOOST_THREAD_USES_DATETIME
+#ifdef __DECXXX
+ /// Workaround of DECCXX issue of incorrect template substitution
+ template<>
+#endif
+ inline void sleep(system_time const& abs_time)
+ {
+ mutex mx;
+ unique_lock<mutex> lock(mx);
+ condition_variable cond;
+ cond.timed_wait(lock, abs_time, hidden::always_false);
}
+ template<typename TimeDuration>
+ void sleep(TimeDuration const& rel_time)
+ {
+ mutex mx;
+ unique_lock<mutex> lock(mx);
+ condition_variable cond;
+ cond.timed_wait(lock, rel_time, hidden::always_false);
+ }
+#endif
+
#ifdef BOOST_THREAD_USES_CHRONO
- template <class Rep, class Period>
- void sleep_for(const chrono::duration<Rep, Period>& d);
-#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
+ template <class Clock, class Duration>
+ void sleep_until(const chrono::time_point<Clock, Duration>& t)
+ {
+ mutex mut;
+ unique_lock<mutex> lk(mut);
+ condition_variable cv;
+ cv.wait_until(lk, t, hidden::always_false);
+ }
- inline
- void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
+ template <class Rep, class Period>
+ void sleep_for(const chrono::duration<Rep, Period>& d)
{
- return boost::this_thread::hidden::sleep_for(boost::detail::to_timespec(ns));
+ mutex mut;
+ unique_lock<mutex> lk(mut);
+ condition_variable cv;
+ cv.wait_for(lk, d, hidden::always_false);
}
#endif
-#endif // BOOST_THREAD_USES_CHRONO
namespace no_interruption_point
{
+#if defined BOOST_THREAD_SLEEP_FOR_IS_STEADY
+// Use pthread_delay_np or nanosleep when available
+// because they do not provide an interruption point.
+
namespace hidden
{
- void BOOST_THREAD_DECL sleep_for(const timespec& ts);
- void BOOST_THREAD_DECL sleep_until_realtime(const timespec& ts);
+ void BOOST_THREAD_DECL sleep_for_internal(const detail::platform_duration& ts);
}
- #ifdef BOOST_THREAD_USES_CHRONO
+#if defined BOOST_THREAD_USES_DATETIME
+#ifdef __DECXXX
+ /// Workaround of DECCXX issue of incorrect template substitution
+ template<>
+#endif
+ inline void sleep(system_time const& 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));
+ hidden::sleep_for_internal(d);
+ d = ts - detail::real_platform_clock::now();
+ }
+ }
+
+ template<typename TimeDuration>
+ void sleep(TimeDuration const& rel_time)
+ {
+ hidden::sleep_for_internal(detail::platform_duration(rel_time));
+ }
+#endif
+
+#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
- void sleep_for(const chrono::duration<Rep, Period>& d);
- #ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
+ void sleep_for(const chrono::duration<Rep, Period>& d)
+ {
+ hidden::sleep_for_internal(detail::platform_duration(d));
+ }
- inline
- void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
+ template <class Duration>
+ void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
{
- return boost::this_thread::no_interruption_point::hidden::sleep_for(boost::detail::to_timespec(ns));
+ sleep_for(t - chrono::steady_clock::now());
}
- #endif
- #endif // BOOST_THREAD_USES_CHRONO
- } // no_interruption_point
+ 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)));
+ hidden::sleep_for_internal(detail::platform_duration(d));
+ d = t - Clock::now();
+ }
+ }
+#endif
- void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT;
+#else // BOOST_THREAD_SLEEP_FOR_IS_STEADY
+// When pthread_delay_np and nanosleep are not available,
+// fall back to using the interruptible sleep functions.
#if defined BOOST_THREAD_USES_DATETIME
#ifdef __DECXXX
- /// Workaround of DECCXX issue of incorrect template substitution
- template<>
+ /// Workaround of DECCXX issue of incorrect template substitution
+ template<>
#endif
- inline void sleep(system_time const& abs_time)
- {
- return boost::this_thread::hidden::sleep_until_realtime(boost::detail::to_timespec(abs_time));
- }
+ inline void sleep(system_time const& abs_time)
+ {
+ this_thread::sleep(abs_time);
+ }
- template<typename TimeDuration>
- inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
- {
- this_thread::sleep(get_system_time()+rel_time);
- }
-#endif // BOOST_THREAD_USES_DATETIME
+ template<typename TimeDuration>
+ void sleep(TimeDuration const& rel_time)
+ {
+ this_thread::sleep(rel_time);
+ }
+#endif
+
+#ifdef BOOST_THREAD_USES_CHRONO
+ template <class Clock, class Duration>
+ void sleep_until(const chrono::time_point<Clock, Duration>& t)
+ {
+ this_thread::sleep_until(t);
+ }
+
+ template <class Rep, class Period>
+ void sleep_for(const chrono::duration<Rep, Period>& d)
+ {
+ this_thread::sleep_for(d);
+ }
+#endif
+
+#endif // BOOST_THREAD_SLEEP_FOR_IS_STEADY
+ } // no_interruption_point
} // this_thread
}
diff --git a/boost/thread/pthread/timespec.hpp b/boost/thread/pthread/timespec.hpp
deleted file mode 100644
index 1fb8de94c8..0000000000
--- a/boost/thread/pthread/timespec.hpp
+++ /dev/null
@@ -1,138 +0,0 @@
-#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP
-#define BOOST_THREAD_PTHREAD_TIMESPEC_HPP
-// (C) Copyright 2007-8 Anthony Williams
-// (C) Copyright 2012 Vicente J. Botet Escriba
-//
-// Distributed under the Boost Software License, Version 1.0. (See
-// accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-
-#include <boost/thread/detail/config.hpp>
-#include <boost/thread/thread_time.hpp>
-#if defined BOOST_THREAD_USES_DATETIME
-#include <boost/date_time/posix_time/conversion.hpp>
-#endif
-#include <pthread.h>
-#ifndef _WIN32
-#include <unistd.h>
-#endif
-#ifdef BOOST_THREAD_USES_CHRONO
-#include <boost/chrono/duration.hpp>
-#endif
-
-#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
-# define BOOST_THREAD_TIMESPEC_MAC_API
-#include <sys/time.h> //for gettimeofday and timeval
-#else
-#include <time.h> // for clock_gettime
-#endif
-
-#include <boost/config/abi_prefix.hpp>
-
-namespace boost
-{
- namespace detail
- {
-#if defined BOOST_THREAD_USES_DATETIME
- inline struct timespec to_timespec(boost::system_time const& abs_time)
- {
- struct timespec timeout = { 0,0};
- boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
-
- timeout.tv_sec=time_since_epoch.total_seconds();
- timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second()));
- return timeout;
- }
-#endif
-#if defined BOOST_THREAD_USES_CHRONO
- inline timespec to_timespec(chrono::nanoseconds const& ns)
- {
- struct timespec ts;
- ts.tv_sec = static_cast<long>(chrono::duration_cast<chrono::seconds>(ns).count());
- ts.tv_nsec = static_cast<long>((ns - chrono::duration_cast<chrono::seconds>(ns)).count());
- return ts;
- }
-
-#endif
-
- inline timespec to_timespec(boost::intmax_t const& ns)
- {
- boost::intmax_t s = ns / 1000000000l;
- struct timespec ts;
- ts.tv_sec = static_cast<long> (s);
- ts.tv_nsec = static_cast<long> (ns - s * 1000000000l);
- return ts;
- }
- inline boost::intmax_t to_nanoseconds_int_max(timespec const& ts)
- {
- return static_cast<boost::intmax_t>(ts.tv_sec) * 1000000000l + ts.tv_nsec;
- }
- inline bool timespec_ge_zero(timespec const& ts)
- {
- return (ts.tv_sec >= 0) || (ts.tv_nsec >= 0);
- }
-#if defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
-
- inline timespec timespec_now_monotonic()
- {
- timespec ts;
-
- if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) )
- {
- ts.tv_sec = 0;
- ts.tv_nsec = 0;
- BOOST_ASSERT(0 && "Boost::Thread - Internal Error");
- }
- return ts;
- }
-#endif
-
- inline timespec timespec_now_realtime()
- {
- timespec ts;
-
-#if defined(BOOST_THREAD_TIMESPEC_MAC_API)
- timeval tv;
- ::gettimeofday(&tv, 0);
- ts.tv_sec = tv.tv_sec;
- ts.tv_nsec = tv.tv_usec * 1000;
-#else
- if ( ::clock_gettime( CLOCK_REALTIME, &ts ) )
- {
- ts.tv_sec = 0;
- ts.tv_nsec = 0;
- BOOST_ASSERT(0 && "Boost::Thread - Internal Error");
- }
-#endif
- return ts;
- }
- inline timespec timespec_zero()
- {
- timespec ts;
- ts.tv_sec = 0;
- ts.tv_nsec = 0;
- return ts;
- }
- inline timespec timespec_plus(timespec const& lhs, timespec const& rhs)
- {
- return to_timespec(to_nanoseconds_int_max(lhs) + to_nanoseconds_int_max(rhs));
- }
- inline timespec timespec_minus(timespec const& lhs, timespec const& rhs)
- {
- return to_timespec(to_nanoseconds_int_max(lhs) - to_nanoseconds_int_max(rhs));
- }
- inline bool timespec_gt(timespec const& lhs, timespec const& rhs)
- {
- return to_nanoseconds_int_max(lhs) > to_nanoseconds_int_max(rhs);
- }
- inline bool timespec_ge(timespec const& lhs, timespec const& rhs)
- {
- return to_nanoseconds_int_max(lhs) >= to_nanoseconds_int_max(rhs);
- }
-
- }
-}
-
-#include <boost/config/abi_suffix.hpp>
-
-#endif
diff --git a/boost/thread/shared_mutex.hpp b/boost/thread/shared_mutex.hpp
index ce5d6d1bfb..20a95d8c51 100644
--- a/boost/thread/shared_mutex.hpp
+++ b/boost/thread/shared_mutex.hpp
@@ -13,13 +13,20 @@
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#if defined(BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN)
+#if defined(BOOST_THREAD_V2_SHARED_MUTEX)
+#include <boost/thread/v2/shared_mutex.hpp>
+#else
#include <boost/thread/pthread/shared_mutex.hpp>
+#endif
#else
#include <boost/thread/win32/shared_mutex.hpp>
#endif
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
-//#include <boost/thread/v2/shared_mutex.hpp>
+#if defined(BOOST_THREAD_V2_SHARED_MUTEX)
+#include <boost/thread/v2/shared_mutex.hpp>
+#else
#include <boost/thread/pthread/shared_mutex.hpp>
+#endif
#else
#error "Boost threads unavailable on this platform"
#endif
diff --git a/boost/thread/thread_only.hpp b/boost/thread/thread_only.hpp
index 0d0c07061f..d408344eef 100644
--- a/boost/thread/thread_only.hpp
+++ b/boost/thread/thread_only.hpp
@@ -23,7 +23,7 @@
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
#include <boost/thread/detail/thread_interruption.hpp>
#endif
-#include <boost/thread/v2/thread.hpp>
+#include <boost/thread/condition_variable.hpp>
#endif
diff --git a/boost/thread/v2/shared_mutex.hpp b/boost/thread/v2/shared_mutex.hpp
index 5e8b24f70a..e30a59e413 100644
--- a/boost/thread/v2/shared_mutex.hpp
+++ b/boost/thread/v2/shared_mutex.hpp
@@ -153,222 +153,292 @@ public:
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
+#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono.hpp>
+#endif
#include <climits>
#include <boost/system/system_error.hpp>
-#define BOOST_THREAD_INLINE inline
+#include <boost/bind.hpp>
namespace boost {
namespace thread_v2 {
class shared_mutex
{
- typedef ::boost::mutex mutex_t;
- typedef ::boost::condition_variable cond_t;
- typedef unsigned count_t;
+ typedef boost::mutex mutex_t;
+ typedef boost::condition_variable cond_t;
+ typedef unsigned count_t;
mutex_t mut_;
cond_t gate1_;
+ // the gate2_ condition variable is only used by functions that
+ // have taken write_entered_ but are waiting for no_readers()
cond_t gate2_;
count_t state_;
static const count_t write_entered_ = 1U << (sizeof(count_t)*CHAR_BIT - 1);
static const count_t n_readers_ = ~write_entered_;
- public:
- BOOST_THREAD_INLINE shared_mutex();
- BOOST_THREAD_INLINE ~shared_mutex();
-
-#ifndef BOOST_NO_CXX11_DELETED_FUNCTIONS
- shared_mutex(shared_mutex const&) = delete;
- shared_mutex& operator=(shared_mutex const&) = delete;
-#else // BOOST_NO_CXX11_DELETED_FUNCTIONS
- private:
+ bool no_writer() const
+ {
+ return (state_ & write_entered_) == 0;
+ }
+
+ bool one_writer() const
+ {
+ return (state_ & write_entered_) != 0;
+ }
+
+ bool no_writer_no_readers() const
+ {
+ //return (state_ & write_entered_) == 0 &&
+ // (state_ & n_readers_) == 0;
+ return state_ == 0;
+ }
+
+ bool no_writer_no_max_readers() const
+ {
+ return (state_ & write_entered_) == 0 &&
+ (state_ & n_readers_) != n_readers_;
+ }
+
+ bool no_readers() const
+ {
+ return (state_ & n_readers_) == 0;
+ }
+
+ bool one_or_more_readers() const
+ {
+ return (state_ & n_readers_) > 0;
+ }
+
shared_mutex(shared_mutex const&);
shared_mutex& operator=(shared_mutex const&);
+
public:
-#endif // BOOST_NO_CXX11_DELETED_FUNCTIONS
+ shared_mutex();
+ ~shared_mutex();
// Exclusive ownership
- BOOST_THREAD_INLINE void lock();
- BOOST_THREAD_INLINE bool try_lock();
+ void lock();
+ bool try_lock();
+#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time)
{
- return try_lock_until(boost::chrono::steady_clock::now() + rel_time);
+ return try_lock_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
- bool
- try_lock_until(
+ bool try_lock_until(
const boost::chrono::time_point<Clock, Duration>& abs_time);
- BOOST_THREAD_INLINE void unlock();
-
+#endif
+#if defined BOOST_THREAD_USES_DATETIME
+ template<typename T>
+ bool timed_lock(T const & abs_or_rel_time);
+#endif
+ void unlock();
// Shared ownership
- BOOST_THREAD_INLINE void lock_shared();
- BOOST_THREAD_INLINE bool try_lock_shared();
+ void lock_shared();
+ bool try_lock_shared();
+#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
- bool
- try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time)
+ bool try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time)
{
- return try_lock_shared_until(boost::chrono::steady_clock::now() +
- rel_time);
+ return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
- bool
- try_lock_shared_until(
+ bool try_lock_shared_until(
const boost::chrono::time_point<Clock, Duration>& abs_time);
- BOOST_THREAD_INLINE void unlock_shared();
-
+#endif
#if defined BOOST_THREAD_USES_DATETIME
- bool timed_lock(system_time const& timeout);
- template<typename TimeDuration>
- bool timed_lock(TimeDuration const & relative_time)
+ template<typename T>
+ bool timed_lock_shared(T const & abs_or_rel_time);
+#endif
+ void unlock_shared();
+ };
+
+ inline shared_mutex::shared_mutex()
+ : state_(0)
+ {
+ }
+
+ inline shared_mutex::~shared_mutex()
+ {
+ boost::lock_guard<mutex_t> _(mut_);
+ }
+
+ // Exclusive ownership
+
+ inline void shared_mutex::lock()
+ {
+ boost::unique_lock<mutex_t> lk(mut_);
+ gate1_.wait(lk, boost::bind(&shared_mutex::no_writer, boost::ref(*this)));
+ state_ |= write_entered_;
+ gate2_.wait(lk, boost::bind(&shared_mutex::no_readers, boost::ref(*this)));
+ }
+
+ inline bool shared_mutex::try_lock()
+ {
+ boost::unique_lock<mutex_t> lk(mut_);
+ if (!no_writer_no_readers())
+ {
+ return false;
+ }
+ state_ = write_entered_;
+ return true;
+ }
+
+#ifdef BOOST_THREAD_USES_CHRONO
+ template <class Clock, class Duration>
+ bool shared_mutex::try_lock_until(
+ const boost::chrono::time_point<Clock, Duration>& abs_time)
+ {
+ boost::unique_lock<mutex_t> lk(mut_);
+ if (!gate1_.wait_until(lk, abs_time, boost::bind(
+ &shared_mutex::no_writer, boost::ref(*this))))
{
- return timed_lock(get_system_time()+relative_time);
+ return false;
}
- bool timed_lock_shared(system_time const& timeout);
- template<typename TimeDuration>
- bool timed_lock_shared(TimeDuration const & relative_time)
+ state_ |= write_entered_;
+ if (!gate2_.wait_until(lk, abs_time, boost::bind(
+ &shared_mutex::no_readers, boost::ref(*this))))
{
- return timed_lock_shared(get_system_time()+relative_time);
+ state_ &= ~write_entered_;
+ return false;
}
+ return true;
+ }
#endif
- };
- template <class Clock, class Duration>
- bool
- shared_mutex::try_lock_until(
- const boost::chrono::time_point<Clock, Duration>& abs_time)
+#if defined BOOST_THREAD_USES_DATETIME
+ template<typename T>
+ bool shared_mutex::timed_lock(T const & abs_or_rel_time)
{
boost::unique_lock<mutex_t> lk(mut_);
- if (state_ & write_entered_)
+ if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind(
+ &shared_mutex::no_writer, boost::ref(*this))))
{
- for (;;)
- {
- boost::cv_status status = gate1_.wait_until(lk, abs_time);
- if ((state_ & write_entered_) == 0)
- break;
- if (status == boost::cv_status::timeout)
- return false;
- }
+ return false;
}
state_ |= write_entered_;
- if (state_ & n_readers_)
+ if (!gate2_.timed_wait(lk, abs_or_rel_time, boost::bind(
+ &shared_mutex::no_readers, boost::ref(*this))))
+ {
+ state_ &= ~write_entered_;
+ return false;
+ }
+ return true;
+ }
+#endif
+
+ inline void shared_mutex::unlock()
+ {
+ boost::lock_guard<mutex_t> _(mut_);
+ BOOST_ASSERT(one_writer());
+ BOOST_ASSERT(no_readers());
+ state_ = 0;
+ // notify all since multiple *lock_shared*() calls may be able
+ // to proceed in response to this notification
+ gate1_.notify_all();
+ }
+
+ // Shared ownership
+
+ inline void shared_mutex::lock_shared()
+ {
+ boost::unique_lock<mutex_t> lk(mut_);
+ gate1_.wait(lk, boost::bind(&shared_mutex::no_writer_no_max_readers, boost::ref(*this)));
+ count_t num_readers = (state_ & n_readers_) + 1;
+ state_ &= ~n_readers_;
+ state_ |= num_readers;
+ }
+
+ inline bool shared_mutex::try_lock_shared()
+ {
+ boost::unique_lock<mutex_t> lk(mut_);
+ if (!no_writer_no_max_readers())
{
- for (;;)
- {
- boost::cv_status status = gate2_.wait_until(lk, abs_time);
- if ((state_ & n_readers_) == 0)
- break;
- if (status == boost::cv_status::timeout)
- {
- state_ &= ~write_entered_;
- return false;
- }
- }
+ return false;
}
+ count_t num_readers = (state_ & n_readers_) + 1;
+ state_ &= ~n_readers_;
+ state_ |= num_readers;
return true;
}
+#ifdef BOOST_THREAD_USES_CHRONO
template <class Clock, class Duration>
- bool
- shared_mutex::try_lock_shared_until(
+ bool shared_mutex::try_lock_shared_until(
const boost::chrono::time_point<Clock, Duration>& abs_time)
{
boost::unique_lock<mutex_t> lk(mut_);
- if ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_)
+ if (!gate1_.wait_until(lk, abs_time, boost::bind(
+ &shared_mutex::no_writer_no_max_readers, boost::ref(*this))))
{
- for (;;)
- {
- boost::cv_status status = gate1_.wait_until(lk, abs_time);
- if ((state_ & write_entered_) == 0 &&
- (state_ & n_readers_) < n_readers_)
- break;
- if (status == boost::cv_status::timeout)
- return false;
- }
+ return false;
}
count_t num_readers = (state_ & n_readers_) + 1;
state_ &= ~n_readers_;
state_ |= num_readers;
return true;
}
+#endif
#if defined BOOST_THREAD_USES_DATETIME
- bool shared_mutex::timed_lock(system_time const& abs_time)
+ template<typename T>
+ bool shared_mutex::timed_lock_shared(T const & abs_or_rel_time)
{
boost::unique_lock<mutex_t> lk(mut_);
- if (state_ & write_entered_)
- {
- for (;;)
- {
- bool status = gate1_.timed_wait(lk, abs_time);
- if ((state_ & write_entered_) == 0)
- break;
- if (!status)
- return false;
- }
- }
- state_ |= write_entered_;
- if (state_ & n_readers_)
+ if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind(
+ &shared_mutex::no_writer_no_max_readers, boost::ref(*this))))
{
- for (;;)
- {
- bool status = gate2_.timed_wait(lk, abs_time);
- if ((state_ & n_readers_) == 0)
- break;
- if (!status)
- {
- state_ &= ~write_entered_;
- return false;
- }
- }
+ return false;
}
+ count_t num_readers = (state_ & n_readers_) + 1;
+ state_ &= ~n_readers_;
+ state_ |= num_readers;
return true;
}
- bool shared_mutex::timed_lock_shared(system_time const& abs_time)
+#endif
+
+ inline void shared_mutex::unlock_shared()
+ {
+ boost::lock_guard<mutex_t> _(mut_);
+ BOOST_ASSERT(one_or_more_readers());
+ count_t num_readers = (state_ & n_readers_) - 1;
+ state_ &= ~n_readers_;
+ state_ |= num_readers;
+ if (no_writer())
{
- boost::unique_lock<mutex_t> lk(mut_);
- if (state_ & write_entered_)
- {
- for (;;)
- {
- bool status = gate1_.timed_wait(lk, abs_time);
- if ((state_ & write_entered_) == 0)
- break;
- if (!status )
- return false;
- }
- }
- state_ |= write_entered_;
- if (state_ & n_readers_)
- {
- for (;;)
- {
- bool status = gate2_.timed_wait(lk, abs_time);
- if ((state_ & n_readers_) == 0)
- break;
- if (!status)
- {
- state_ &= ~write_entered_;
- return false;
- }
- }
- }
- return true;
+ if (num_readers == n_readers_ - 1)
+ gate1_.notify_one();
}
-#endif
+ else
+ {
+ if (num_readers == 0)
+ gate2_.notify_one();
+ }
+ }
+
+ } // thread_v2
+} // boost
+
+namespace boost {
+ namespace thread_v2 {
+
class upgrade_mutex
{
typedef boost::mutex mutex_t;
typedef boost::condition_variable cond_t;
- typedef unsigned count_t;
+ typedef unsigned count_t;
mutex_t mut_;
cond_t gate1_;
+ // the gate2_ condition variable is only used by functions that
+ // have taken write_entered_ but are waiting for no_readers()
cond_t gate2_;
count_t state_;
@@ -376,677 +446,597 @@ namespace boost {
static const unsigned upgradable_entered_ = write_entered_ >> 1;
static const unsigned n_readers_ = ~(write_entered_ | upgradable_entered_);
- public:
+ bool no_writer() const
+ {
+ return (state_ & write_entered_) == 0;
+ }
+
+ bool one_writer() const
+ {
+ return (state_ & write_entered_) != 0;
+ }
+
+ bool no_writer_no_max_readers() const
+ {
+ return (state_ & write_entered_) == 0 &&
+ (state_ & n_readers_) != n_readers_;
+ }
+
+ bool no_writer_no_upgrader() const
+ {
+ return (state_ & (write_entered_ | upgradable_entered_)) == 0;
+ }
+
+ bool no_writer_no_upgrader_no_readers() const
+ {
+ //return (state_ & (write_entered_ | upgradable_entered_)) == 0 &&
+ // (state_ & n_readers_) == 0;
+ return state_ == 0;
+ }
+
+ bool no_writer_no_upgrader_one_reader() const
+ {
+ //return (state_ & (write_entered_ | upgradable_entered_)) == 0 &&
+ // (state_ & n_readers_) == 1;
+ return state_ == 1;
+ }
+
+ bool no_writer_no_upgrader_no_max_readers() const
+ {
+ return (state_ & (write_entered_ | upgradable_entered_)) == 0 &&
+ (state_ & n_readers_) != n_readers_;
+ }
+
+ bool no_upgrader() const
+ {
+ return (state_ & upgradable_entered_) == 0;
+ }
+
+ bool one_upgrader() const
+ {
+ return (state_ & upgradable_entered_) != 0;
+ }
+
+ bool no_readers() const
+ {
+ return (state_ & n_readers_) == 0;
+ }
- BOOST_THREAD_INLINE upgrade_mutex();
- BOOST_THREAD_INLINE ~upgrade_mutex();
+ bool one_reader() const
+ {
+ return (state_ & n_readers_) == 1;
+ }
+
+ bool one_or_more_readers() const
+ {
+ return (state_ & n_readers_) > 0;
+ }
-#ifndef BOOST_CXX11_NO_DELETED_FUNCTIONS
- upgrade_mutex(const upgrade_mutex&) = delete;
- upgrade_mutex& operator=(const upgrade_mutex&) = delete;
-#else // BOOST_CXX11_NO_DELETED_FUNCTIONS
- private:
upgrade_mutex(const upgrade_mutex&);
upgrade_mutex& operator=(const upgrade_mutex&);
+
public:
-#endif // BOOST_CXX11_NO_DELETED_FUNCTIONS
+ upgrade_mutex();
+ ~upgrade_mutex();
// Exclusive ownership
- BOOST_THREAD_INLINE void lock();
- BOOST_THREAD_INLINE bool try_lock();
+ void lock();
+ bool try_lock();
+#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_for(const boost::chrono::duration<Rep, Period>& rel_time)
{
- return try_lock_until(boost::chrono::steady_clock::now() + rel_time);
+ return try_lock_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
- bool
- try_lock_until(
+ bool try_lock_until(
const boost::chrono::time_point<Clock, Duration>& abs_time);
- BOOST_THREAD_INLINE void unlock();
+#endif
+#if defined BOOST_THREAD_USES_DATETIME
+ template<typename T>
+ bool timed_lock(T const & abs_or_rel_time);
+#endif
+ void unlock();
// Shared ownership
- BOOST_THREAD_INLINE void lock_shared();
- BOOST_THREAD_INLINE bool try_lock_shared();
+ void lock_shared();
+ bool try_lock_shared();
+#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
- bool
- try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time)
+ bool try_lock_shared_for(const boost::chrono::duration<Rep, Period>& rel_time)
{
- return try_lock_shared_until(boost::chrono::steady_clock::now() +
- rel_time);
+ return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
- bool
- try_lock_shared_until(
+ bool try_lock_shared_until(
const boost::chrono::time_point<Clock, Duration>& abs_time);
- BOOST_THREAD_INLINE void unlock_shared();
+#endif
+#if defined BOOST_THREAD_USES_DATETIME
+ template<typename T>
+ bool timed_lock_shared(T const & abs_or_rel_time);
+#endif
+ void unlock_shared();
// Upgrade ownership
- BOOST_THREAD_INLINE void lock_upgrade();
- BOOST_THREAD_INLINE bool try_lock_upgrade();
+ void lock_upgrade();
+ bool try_lock_upgrade();
+#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
- bool
- try_lock_upgrade_for(
+ bool try_lock_upgrade_for(
const boost::chrono::duration<Rep, Period>& rel_time)
{
- return try_lock_upgrade_until(boost::chrono::steady_clock::now() +
- rel_time);
+ return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
- bool
- try_lock_upgrade_until(
+ bool try_lock_upgrade_until(
const boost::chrono::time_point<Clock, Duration>& abs_time);
- BOOST_THREAD_INLINE void unlock_upgrade();
+#endif
+#if defined BOOST_THREAD_USES_DATETIME
+ template<typename T>
+ bool timed_lock_upgrade(T const & abs_or_rel_time);
+#endif
+ void unlock_upgrade();
// Shared <-> Exclusive
- BOOST_THREAD_INLINE bool try_unlock_shared_and_lock();
+#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
+ //bool unlock_shared_and_lock(); // can cause a deadlock if used
+ bool try_unlock_shared_and_lock();
+#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
- bool
- try_unlock_shared_and_lock_for(
+ bool try_unlock_shared_and_lock_for(
const boost::chrono::duration<Rep, Period>& rel_time)
{
- return try_unlock_shared_and_lock_until(
- boost::chrono::steady_clock::now() + rel_time);
+ return try_unlock_shared_and_lock_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
- bool
- try_unlock_shared_and_lock_until(
+ bool try_unlock_shared_and_lock_until(
const boost::chrono::time_point<Clock, Duration>& abs_time);
- BOOST_THREAD_INLINE void unlock_and_lock_shared();
+#endif
+#endif
+ void unlock_and_lock_shared();
// Shared <-> Upgrade
- BOOST_THREAD_INLINE bool try_unlock_shared_and_lock_upgrade();
+#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
+ //bool unlock_shared_and_lock_upgrade(); // can cause a deadlock if used
+ bool try_unlock_shared_and_lock_upgrade();
+#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
- bool
- try_unlock_shared_and_lock_upgrade_for(
+ bool try_unlock_shared_and_lock_upgrade_for(
const boost::chrono::duration<Rep, Period>& rel_time)
{
- return try_unlock_shared_and_lock_upgrade_until(
- boost::chrono::steady_clock::now() + rel_time);
+ return try_unlock_shared_and_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
}
template <class Clock, class Duration>
- bool
- try_unlock_shared_and_lock_upgrade_until(
+ bool try_unlock_shared_and_lock_upgrade_until(
const boost::chrono::time_point<Clock, Duration>& abs_time);
- BOOST_THREAD_INLINE void unlock_upgrade_and_lock_shared();
+#endif
+#endif
+ void unlock_upgrade_and_lock_shared();
// Upgrade <-> Exclusive
- BOOST_THREAD_INLINE void unlock_upgrade_and_lock();
- BOOST_THREAD_INLINE bool try_unlock_upgrade_and_lock();
+ void unlock_upgrade_and_lock();
+ bool try_unlock_upgrade_and_lock();
+#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
- bool
- try_unlock_upgrade_and_lock_for(
+ bool try_unlock_upgrade_and_lock_for(
const boost::chrono::duration<Rep, Period>& rel_time)
{
- return try_unlock_upgrade_and_lock_until(
- boost::chrono::steady_clock::now() + 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(
+ bool try_unlock_upgrade_and_lock_until(
const boost::chrono::time_point<Clock, Duration>& abs_time);
- BOOST_THREAD_INLINE void unlock_and_lock_upgrade();
-
-#if defined BOOST_THREAD_USES_DATETIME
- inline bool timed_lock(system_time const& abs_time);
- template<typename TimeDuration>
- bool timed_lock(TimeDuration const & relative_time)
- {
- return timed_lock(get_system_time()+relative_time);
- }
- inline bool timed_lock_shared(system_time const& abs_time);
- template<typename TimeDuration>
- bool timed_lock_shared(TimeDuration const & relative_time)
- {
- return timed_lock_shared(get_system_time()+relative_time);
- }
- inline bool timed_lock_upgrade(system_time const& abs_time);
- template<typename TimeDuration>
- bool timed_lock_upgrade(TimeDuration const & relative_time)
- {
- return timed_lock_upgrade(get_system_time()+relative_time);
- }
#endif
-
+ void unlock_and_lock_upgrade();
};
- template <class Clock, class Duration>
- bool
- upgrade_mutex::try_lock_until(
- const boost::chrono::time_point<Clock, Duration>& abs_time)
+ inline upgrade_mutex::upgrade_mutex()
+ : gate1_(),
+ gate2_(),
+ state_(0)
{
- boost::unique_lock<mutex_t> lk(mut_);
- if (state_ & (write_entered_ | upgradable_entered_))
- {
- for (;;)
- {
- boost::cv_status status = gate1_.wait_until(lk, abs_time);
- if ((state_ & (write_entered_ | upgradable_entered_)) == 0)
- break;
- if (status == boost::cv_status::timeout)
- return false;
- }
- }
- state_ |= write_entered_;
- if (state_ & n_readers_)
- {
- for (;;)
- {
- boost::cv_status status = gate2_.wait_until(lk, abs_time);
- if ((state_ & n_readers_) == 0)
- break;
- if (status == boost::cv_status::timeout)
- {
- state_ &= ~write_entered_;
- return false;
- }
- }
- }
- return true;
}
- template <class Clock, class Duration>
- bool
- upgrade_mutex::try_lock_shared_until(
- const boost::chrono::time_point<Clock, Duration>& abs_time)
+ inline upgrade_mutex::~upgrade_mutex()
{
- boost::unique_lock<mutex_t> lk(mut_);
- if ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_)
- {
- for (;;)
- {
- boost::cv_status status = gate1_.wait_until(lk, abs_time);
- if ((state_ & write_entered_) == 0 &&
- (state_ & n_readers_) < n_readers_)
- break;
- if (status == boost::cv_status::timeout)
- return false;
- }
- }
- count_t num_readers = (state_ & n_readers_) + 1;
- state_ &= ~n_readers_;
- state_ |= num_readers;
- return true;
+ boost::lock_guard<mutex_t> _(mut_);
}
- template <class Clock, class Duration>
- bool
- upgrade_mutex::try_lock_upgrade_until(
- const boost::chrono::time_point<Clock, Duration>& abs_time)
+ // Exclusive ownership
+
+ inline void upgrade_mutex::lock()
{
boost::unique_lock<mutex_t> lk(mut_);
- if ((state_ & (write_entered_ | upgradable_entered_)) ||
- (state_ & n_readers_) == n_readers_)
- {
- for (;;)
- {
- boost::cv_status status = gate1_.wait_until(lk, abs_time);
- if ((state_ & (write_entered_ | upgradable_entered_)) == 0 &&
- (state_ & n_readers_) < n_readers_)
- break;
- if (status == boost::cv_status::timeout)
- return false;
- }
- }
- count_t num_readers = (state_ & n_readers_) + 1;
- state_ &= ~n_readers_;
- state_ |= upgradable_entered_ | num_readers;
- return true;
+ gate1_.wait(lk, boost::bind(&upgrade_mutex::no_writer_no_upgrader, boost::ref(*this)));
+ state_ |= write_entered_;
+ gate2_.wait(lk, boost::bind(&upgrade_mutex::no_readers, boost::ref(*this)));
}
-#if defined BOOST_THREAD_USES_DATETIME
- bool upgrade_mutex::timed_lock(system_time const& abs_time)
- {
- boost::unique_lock<mutex_t> lk(mut_);
- if (state_ & (write_entered_ | upgradable_entered_))
- {
- for (;;)
- {
- bool status = gate1_.timed_wait(lk, abs_time);
- if ((state_ & (write_entered_ | upgradable_entered_)) == 0)
- break;
- if (!status)
- return false;
- }
- }
- state_ |= write_entered_;
- if (state_ & n_readers_)
- {
- for (;;)
- {
- bool status = gate2_.timed_wait(lk, abs_time);
- if ((state_ & n_readers_) == 0)
- break;
- if (!status)
- {
- state_ &= ~write_entered_;
- return false;
- }
- }
- }
- return true;
- }
- bool upgrade_mutex::timed_lock_shared(system_time const& abs_time)
- {
- boost::unique_lock<mutex_t> lk(mut_);
- if ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_)
- {
- for (;;)
- {
- bool status = gate1_.timed_wait(lk, abs_time);
- if ((state_ & write_entered_) == 0 &&
- (state_ & n_readers_) < n_readers_)
- break;
- if (!status)
- return false;
- }
- }
- count_t num_readers = (state_ & n_readers_) + 1;
- state_ &= ~n_readers_;
- state_ |= num_readers;
- return true;
- }
- bool upgrade_mutex::timed_lock_upgrade(system_time const& abs_time)
- {
- boost::unique_lock<mutex_t> lk(mut_);
- if ((state_ & (write_entered_ | upgradable_entered_)) ||
- (state_ & n_readers_) == n_readers_)
- {
- for (;;)
- {
- bool status = gate1_.timed_wait(lk, abs_time);
- if ((state_ & (write_entered_ | upgradable_entered_)) == 0 &&
- (state_ & n_readers_) < n_readers_)
- break;
- if (!status)
- return false;
- }
- }
- count_t num_readers = (state_ & n_readers_) + 1;
- state_ &= ~n_readers_;
- state_ |= upgradable_entered_ | num_readers;
- return true;
- }
-
-#endif
- template <class Clock, class Duration>
- bool
- upgrade_mutex::try_unlock_shared_and_lock_until(
- const boost::chrono::time_point<Clock, Duration>& abs_time)
+ inline bool upgrade_mutex::try_lock()
{
boost::unique_lock<mutex_t> lk(mut_);
- if (state_ != 1)
+ if (!no_writer_no_upgrader_no_readers())
{
- for (;;)
- {
- boost::cv_status status = gate2_.wait_until(lk, abs_time);
- if (state_ == 1)
- break;
- if (status == boost::cv_status::timeout)
- return false;
- }
+ return false;
}
state_ = write_entered_;
return true;
}
+#ifdef BOOST_THREAD_USES_CHRONO
template <class Clock, class Duration>
- bool
- upgrade_mutex::try_unlock_shared_and_lock_upgrade_until(
+ bool upgrade_mutex::try_lock_until(
const boost::chrono::time_point<Clock, Duration>& abs_time)
{
boost::unique_lock<mutex_t> lk(mut_);
- if ((state_ & (write_entered_ | upgradable_entered_)) != 0)
+ if (!gate1_.wait_until(lk, abs_time, boost::bind(
+ &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this))))
{
- for (;;)
- {
- boost::cv_status status = gate2_.wait_until(lk, abs_time);
- if ((state_ & (write_entered_ | upgradable_entered_)) == 0)
- break;
- if (status == boost::cv_status::timeout)
- return false;
- }
+ return false;
+ }
+ state_ |= write_entered_;
+ if (!gate2_.wait_until(lk, abs_time, boost::bind(
+ &upgrade_mutex::no_readers, boost::ref(*this))))
+ {
+ state_ &= ~write_entered_;
+ return false;
}
- state_ |= upgradable_entered_;
return true;
}
+#endif
- template <class Clock, class Duration>
- bool
- upgrade_mutex::try_unlock_upgrade_and_lock_until(
- const boost::chrono::time_point<Clock, Duration>& abs_time)
+#if defined BOOST_THREAD_USES_DATETIME
+ template<typename T>
+ bool upgrade_mutex::timed_lock(T const & abs_or_rel_time)
{
boost::unique_lock<mutex_t> lk(mut_);
- if ((state_ & n_readers_) != 1)
+ if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind(
+ &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this))))
{
- for (;;)
- {
- boost::cv_status status = gate2_.wait_until(lk, abs_time);
- if ((state_ & n_readers_) == 1)
- break;
- if (status == boost::cv_status::timeout)
- return false;
- }
+ return false;
+ }
+ state_ |= write_entered_;
+ if (!gate2_.timed_wait(lk, abs_or_rel_time, boost::bind(
+ &upgrade_mutex::no_readers, boost::ref(*this))))
+ {
+ state_ &= ~write_entered_;
+ return false;
}
- state_ = write_entered_;
return true;
}
+#endif
- //////
- // shared_mutex
-
- shared_mutex::shared_mutex()
- : state_(0)
- {
- }
-
- shared_mutex::~shared_mutex()
+ inline void upgrade_mutex::unlock()
{
boost::lock_guard<mutex_t> _(mut_);
+ BOOST_ASSERT(one_writer());
+ BOOST_ASSERT(no_upgrader());
+ BOOST_ASSERT(no_readers());
+ state_ = 0;
+ // notify all since multiple *lock_shared*() calls and a *lock_upgrade*()
+ // call may be able to proceed in response to this notification
+ gate1_.notify_all();
}
- // Exclusive ownership
+ // Shared ownership
- void
- shared_mutex::lock()
+ inline void upgrade_mutex::lock_shared()
{
boost::unique_lock<mutex_t> lk(mut_);
- while (state_ & write_entered_)
- gate1_.wait(lk);
- state_ |= write_entered_;
- while (state_ & n_readers_)
- gate2_.wait(lk);
+ gate1_.wait(lk, boost::bind(&upgrade_mutex::no_writer_no_max_readers, boost::ref(*this)));
+ count_t num_readers = (state_ & n_readers_) + 1;
+ state_ &= ~n_readers_;
+ state_ |= num_readers;
}
- bool
- shared_mutex::try_lock()
+ inline bool upgrade_mutex::try_lock_shared()
{
boost::unique_lock<mutex_t> lk(mut_);
- if (state_ == 0)
+ if (!no_writer_no_max_readers())
{
- state_ = write_entered_;
- return true;
+ return false;
}
- return false;
- }
-
- void
- shared_mutex::unlock()
- {
- boost::lock_guard<mutex_t> _(mut_);
- state_ = 0;
- gate1_.notify_all();
+ count_t num_readers = (state_ & n_readers_) + 1;
+ state_ &= ~n_readers_;
+ state_ |= num_readers;
+ return true;
}
- // Shared ownership
-
- void
- shared_mutex::lock_shared()
+#ifdef BOOST_THREAD_USES_CHRONO
+ template <class Clock, class Duration>
+ bool upgrade_mutex::try_lock_shared_until(
+ const boost::chrono::time_point<Clock, Duration>& abs_time)
{
boost::unique_lock<mutex_t> lk(mut_);
- while ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_)
- gate1_.wait(lk);
+ if (!gate1_.wait_until(lk, abs_time, boost::bind(
+ &upgrade_mutex::no_writer_no_max_readers, boost::ref(*this))))
+ {
+ return false;
+ }
count_t num_readers = (state_ & n_readers_) + 1;
state_ &= ~n_readers_;
state_ |= num_readers;
+ return true;
}
+#endif
- bool
- shared_mutex::try_lock_shared()
+#if defined BOOST_THREAD_USES_DATETIME
+ template<typename T>
+ bool upgrade_mutex::timed_lock_shared(T const & abs_or_rel_time)
{
boost::unique_lock<mutex_t> lk(mut_);
- count_t num_readers = state_ & n_readers_;
- if (!(state_ & write_entered_) && num_readers != n_readers_)
+ if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind(
+ &upgrade_mutex::no_writer_no_max_readers, boost::ref(*this))))
{
- ++num_readers;
- state_ &= ~n_readers_;
- state_ |= num_readers;
- return true;
+ return false;
}
- return false;
+ count_t num_readers = (state_ & n_readers_) + 1;
+ state_ &= ~n_readers_;
+ state_ |= num_readers;
+ return true;
}
+#endif
- void
- shared_mutex::unlock_shared()
+ inline void upgrade_mutex::unlock_shared()
{
boost::lock_guard<mutex_t> _(mut_);
+ BOOST_ASSERT(one_or_more_readers());
count_t num_readers = (state_ & n_readers_) - 1;
state_ &= ~n_readers_;
state_ |= num_readers;
- if (state_ & write_entered_)
+ if (no_writer())
{
- if (num_readers == 0)
- gate2_.notify_one();
+ if (num_readers == n_readers_ - 1)
+ gate1_.notify_one();
}
else
{
- if (num_readers == n_readers_ - 1)
- gate1_.notify_one();
+ if (num_readers == 0)
+ gate2_.notify_one();
}
}
- // upgrade_mutex
-
- upgrade_mutex::upgrade_mutex()
- : gate1_(),
- gate2_(),
- state_(0)
- {
- }
-
- upgrade_mutex::~upgrade_mutex()
- {
- boost::lock_guard<mutex_t> _(mut_);
- }
-
- // Exclusive ownership
+ // Upgrade ownership
- void
- upgrade_mutex::lock()
+ inline void upgrade_mutex::lock_upgrade()
{
boost::unique_lock<mutex_t> lk(mut_);
- while (state_ & (write_entered_ | upgradable_entered_))
- gate1_.wait(lk);
- state_ |= write_entered_;
- while (state_ & n_readers_)
- gate2_.wait(lk);
+ gate1_.wait(lk, boost::bind(&upgrade_mutex::no_writer_no_upgrader_no_max_readers, boost::ref(*this)));
+ count_t num_readers = (state_ & n_readers_) + 1;
+ state_ &= ~n_readers_;
+ state_ |= upgradable_entered_ | num_readers;
}
- bool
- upgrade_mutex::try_lock()
+ inline bool upgrade_mutex::try_lock_upgrade()
{
boost::unique_lock<mutex_t> lk(mut_);
- if (state_ == 0)
+ if (!no_writer_no_upgrader_no_max_readers())
{
- state_ = write_entered_;
- return true;
+ return false;
}
- return false;
- }
-
- void
- upgrade_mutex::unlock()
- {
- boost::lock_guard<mutex_t> _(mut_);
- state_ = 0;
- gate1_.notify_all();
+ count_t num_readers = (state_ & n_readers_) + 1;
+ state_ &= ~n_readers_;
+ state_ |= upgradable_entered_ | num_readers;
+ return true;
}
- // Shared ownership
-
- void
- upgrade_mutex::lock_shared()
+#ifdef BOOST_THREAD_USES_CHRONO
+ template <class Clock, class Duration>
+ bool upgrade_mutex::try_lock_upgrade_until(
+ const boost::chrono::time_point<Clock, Duration>& abs_time)
{
boost::unique_lock<mutex_t> lk(mut_);
- while ((state_ & write_entered_) || (state_ & n_readers_) == n_readers_)
- gate1_.wait(lk);
+ if (!gate1_.wait_until(lk, abs_time, boost::bind(
+ &upgrade_mutex::no_writer_no_upgrader_no_max_readers, boost::ref(*this))))
+ {
+ return false;
+ }
count_t num_readers = (state_ & n_readers_) + 1;
state_ &= ~n_readers_;
- state_ |= num_readers;
+ state_ |= upgradable_entered_ | num_readers;
+ return true;
}
+#endif
- bool
- upgrade_mutex::try_lock_shared()
+#if defined BOOST_THREAD_USES_DATETIME
+ template<typename T>
+ bool upgrade_mutex::timed_lock_upgrade(T const & abs_or_rel_time)
{
boost::unique_lock<mutex_t> lk(mut_);
- count_t num_readers = state_ & n_readers_;
- if (!(state_ & write_entered_) && num_readers != n_readers_)
+ if (!gate1_.timed_wait(lk, abs_or_rel_time, boost::bind(
+ &upgrade_mutex::no_writer_no_upgrader_no_max_readers, boost::ref(*this))))
{
- ++num_readers;
- state_ &= ~n_readers_;
- state_ |= num_readers;
- return true;
+ return false;
}
- return false;
+ count_t num_readers = (state_ & n_readers_) + 1;
+ state_ &= ~n_readers_;
+ state_ |= upgradable_entered_ | num_readers;
+ return true;
}
+#endif
- void
- upgrade_mutex::unlock_shared()
+ inline void upgrade_mutex::unlock_upgrade()
{
boost::lock_guard<mutex_t> _(mut_);
+ BOOST_ASSERT(no_writer());
+ BOOST_ASSERT(one_upgrader());
+ BOOST_ASSERT(one_or_more_readers());
count_t num_readers = (state_ & n_readers_) - 1;
- state_ &= ~n_readers_;
+ state_ &= ~(upgradable_entered_ | n_readers_);
state_ |= num_readers;
- if (state_ & write_entered_)
- {
- if (num_readers == 0)
- gate2_.notify_one();
- }
- else
- {
- if (num_readers == n_readers_ - 1)
- gate1_.notify_one();
- }
+ // notify all since both a *lock*() and a *lock_shared*() call
+ // may be able to proceed in response to this notification
+ gate1_.notify_all();
}
- // Upgrade ownership
+ // Shared <-> Exclusive
- void
- upgrade_mutex::lock_upgrade()
+#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
+ inline bool upgrade_mutex::try_unlock_shared_and_lock()
{
boost::unique_lock<mutex_t> lk(mut_);
- while ((state_ & (write_entered_ | upgradable_entered_)) ||
- (state_ & n_readers_) == n_readers_)
- gate1_.wait(lk);
- count_t num_readers = (state_ & n_readers_) + 1;
- state_ &= ~n_readers_;
- state_ |= upgradable_entered_ | num_readers;
+ BOOST_ASSERT(one_or_more_readers());
+ if (!no_writer_no_upgrader_one_reader())
+ {
+ return false;
+ }
+ state_ = write_entered_;
+ return true;
}
- bool
- upgrade_mutex::try_lock_upgrade()
+#ifdef BOOST_THREAD_USES_CHRONO
+ template <class Clock, class Duration>
+ bool upgrade_mutex::try_unlock_shared_and_lock_until(
+ const boost::chrono::time_point<Clock, Duration>& abs_time)
{
boost::unique_lock<mutex_t> lk(mut_);
- count_t num_readers = state_ & n_readers_;
- if (!(state_ & (write_entered_ | upgradable_entered_))
- && num_readers != n_readers_)
+ BOOST_ASSERT(one_or_more_readers());
+ if (!gate1_.wait_until(lk, abs_time, boost::bind(
+ &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this))))
+ {
+ return false;
+ }
+ count_t num_readers = (state_ & n_readers_) - 1;
+ state_ &= ~n_readers_;
+ state_ |= (write_entered_ | num_readers);
+ if (!gate2_.wait_until(lk, abs_time, boost::bind(
+ &upgrade_mutex::no_readers, boost::ref(*this))))
{
++num_readers;
- state_ &= ~n_readers_;
- state_ |= upgradable_entered_ | num_readers;
- return true;
+ state_ &= ~(write_entered_ | n_readers_);
+ state_ |= num_readers;
+ return false;
}
- return false;
+ return true;
}
+#endif
+#endif
- void
- upgrade_mutex::unlock_upgrade()
+ inline void upgrade_mutex::unlock_and_lock_shared()
{
- {
- boost::lock_guard<mutex_t> _(mut_);
- count_t num_readers = (state_ & n_readers_) - 1;
- state_ &= ~(upgradable_entered_ | n_readers_);
- state_ |= num_readers;
- }
+ boost::lock_guard<mutex_t> _(mut_);
+ BOOST_ASSERT(one_writer());
+ BOOST_ASSERT(no_upgrader());
+ BOOST_ASSERT(no_readers());
+ state_ = 1;
+ // notify all since multiple *lock_shared*() calls and a *lock_upgrade*()
+ // call may be able to proceed in response to this notification
gate1_.notify_all();
}
- // Shared <-> Exclusive
+ // Shared <-> Upgrade
- bool
- upgrade_mutex::try_unlock_shared_and_lock()
+#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
+ inline bool upgrade_mutex::try_unlock_shared_and_lock_upgrade()
{
boost::unique_lock<mutex_t> lk(mut_);
- if (state_ == 1)
- {
- state_ = write_entered_;
- return true;
- }
- return false;
- }
-
- void
- upgrade_mutex::unlock_and_lock_shared()
- {
+ BOOST_ASSERT(one_or_more_readers());
+ if (!no_writer_no_upgrader())
{
- boost::lock_guard<mutex_t> _(mut_);
- state_ = 1;
+ return false;
}
- gate1_.notify_all();
+ state_ |= upgradable_entered_;
+ return true;
}
- // Shared <-> Upgrade
-
- bool
- upgrade_mutex::try_unlock_shared_and_lock_upgrade()
+#ifdef BOOST_THREAD_USES_CHRONO
+ template <class Clock, class Duration>
+ bool upgrade_mutex::try_unlock_shared_and_lock_upgrade_until(
+ const boost::chrono::time_point<Clock, Duration>& abs_time)
{
boost::unique_lock<mutex_t> lk(mut_);
- if (!(state_ & (write_entered_ | upgradable_entered_)))
+ BOOST_ASSERT(one_or_more_readers());
+ if (!gate1_.wait_until(lk, abs_time, boost::bind(
+ &upgrade_mutex::no_writer_no_upgrader, boost::ref(*this))))
{
- state_ |= upgradable_entered_;
- return true;
+ return false;
}
- return false;
+ state_ |= upgradable_entered_;
+ return true;
}
+#endif
+#endif
- void
- upgrade_mutex::unlock_upgrade_and_lock_shared()
+ inline void upgrade_mutex::unlock_upgrade_and_lock_shared()
{
- {
- boost::lock_guard<mutex_t> _(mut_);
- state_ &= ~upgradable_entered_;
- }
+ boost::lock_guard<mutex_t> _(mut_);
+ BOOST_ASSERT(no_writer());
+ BOOST_ASSERT(one_upgrader());
+ BOOST_ASSERT(one_or_more_readers());
+ state_ &= ~upgradable_entered_;
+ // notify all since only one *lock*() or *lock_upgrade*() call can win and
+ // proceed in response to this notification, but a *lock_shared*() call may
+ // also be waiting and could steal the notification
gate1_.notify_all();
}
// Upgrade <-> Exclusive
- void
- upgrade_mutex::unlock_upgrade_and_lock()
+ inline void upgrade_mutex::unlock_upgrade_and_lock()
{
boost::unique_lock<mutex_t> lk(mut_);
+ BOOST_ASSERT(no_writer());
+ BOOST_ASSERT(one_upgrader());
+ BOOST_ASSERT(one_or_more_readers());
count_t num_readers = (state_ & n_readers_) - 1;
state_ &= ~(upgradable_entered_ | n_readers_);
state_ |= write_entered_ | num_readers;
- while (state_ & n_readers_)
- gate2_.wait(lk);
+ gate2_.wait(lk, boost::bind(&upgrade_mutex::no_readers, boost::ref(*this)));
}
- bool
- upgrade_mutex::try_unlock_upgrade_and_lock()
+ inline bool upgrade_mutex::try_unlock_upgrade_and_lock()
{
boost::unique_lock<mutex_t> lk(mut_);
- if (state_ == (upgradable_entered_ | 1))
+ BOOST_ASSERT(no_writer());
+ BOOST_ASSERT(one_upgrader());
+ BOOST_ASSERT(one_or_more_readers());
+ if (!one_reader())
{
- state_ = write_entered_;
- return true;
+ return false;
}
- return false;
+ state_ = write_entered_;
+ return true;
}
- void
- upgrade_mutex::unlock_and_lock_upgrade()
+#ifdef BOOST_THREAD_USES_CHRONO
+ template <class Clock, class Duration>
+ bool upgrade_mutex::try_unlock_upgrade_and_lock_until(
+ const boost::chrono::time_point<Clock, Duration>& abs_time)
{
+ boost::unique_lock<mutex_t> lk(mut_);
+ BOOST_ASSERT(no_writer());
+ BOOST_ASSERT(one_upgrader());
+ BOOST_ASSERT(one_or_more_readers());
+ count_t num_readers = (state_ & n_readers_) - 1;
+ state_ &= ~(upgradable_entered_ | n_readers_);
+ state_ |= (write_entered_ | num_readers);
+ if (!gate2_.wait_until(lk, abs_time, boost::bind(
+ &upgrade_mutex::no_readers, boost::ref(*this))))
{
- boost::lock_guard<mutex_t> _(mut_);
- state_ = upgradable_entered_ | 1;
+ ++num_readers;
+ state_ &= ~(write_entered_ | n_readers_);
+ state_ |= (upgradable_entered_ | num_readers);
+ return false;
}
+ return true;
+ }
+#endif
+
+ inline void upgrade_mutex::unlock_and_lock_upgrade()
+ {
+ boost::lock_guard<mutex_t> _(mut_);
+ BOOST_ASSERT(one_writer());
+ BOOST_ASSERT(no_upgrader());
+ BOOST_ASSERT(no_readers());
+ state_ = upgradable_entered_ | 1;
+ // notify all since multiple *lock_shared*() calls may be able
+ // to proceed in response to this notification
gate1_.notify_all();
}
diff --git a/boost/thread/v2/thread.hpp b/boost/thread/v2/thread.hpp
deleted file mode 100644
index 53560610e2..0000000000
--- a/boost/thread/v2/thread.hpp
+++ /dev/null
@@ -1,155 +0,0 @@
-// Distributed under the Boost Software License, Version 1.0. (See
-// accompanying file LICENSE_1_0.txt or copy at
-// http://www.boost.org/LICENSE_1_0.txt)
-// (C) Copyright 2011 Vicente J. Botet Escriba
-
-#ifndef BOOST_THREAD_V2_THREAD_HPP
-#define BOOST_THREAD_V2_THREAD_HPP
-
-#include <boost/thread/detail/config.hpp>
-#ifdef BOOST_THREAD_USES_CHRONO
-#include <boost/chrono/system_clocks.hpp>
-#include <boost/chrono/ceil.hpp>
-#endif
-#include <boost/thread/condition_variable.hpp>
-#include <boost/thread/lock_types.hpp>
-
-namespace boost
-{
- namespace this_thread
- {
- namespace no_interruption_point
- {
-#ifdef BOOST_THREAD_USES_CHRONO
-
- template <class Clock, class Duration>
- void sleep_until(const chrono::time_point<Clock, Duration>& t)
- {
- using namespace chrono;
- mutex mut;
- condition_variable cv;
- unique_lock<mutex> lk(mut);
- while (Clock::now() < t)
- cv.wait_until(lk, t);
- }
-
-#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
-
- template <class Rep, class Period>
- void sleep_for(const chrono::duration<Rep, Period>& d)
- {
- using namespace chrono;
- if (d > duration<Rep, Period>::zero())
- {
- duration<long double> Max = nanoseconds::max BOOST_PREVENT_MACRO_SUBSTITUTION ();
- nanoseconds ns;
- if (d < Max)
- {
- ns = duration_cast<nanoseconds>(d);
- if (ns < d)
- ++ns;
- }
- else
- ns = nanoseconds:: max BOOST_PREVENT_MACRO_SUBSTITUTION ();
- sleep_for(ns);
- }
- }
-
- template <class Duration>
- inline BOOST_SYMBOL_VISIBLE
- void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
- {
- using namespace chrono;
- sleep_for(t - steady_clock::now());
- }
-#else
- template <class Rep, class Period>
- void sleep_for(const chrono::duration<Rep, Period>& d)
- {
- using namespace chrono;
- if (d > duration<Rep, Period>::zero())
- {
- steady_clock::time_point c_timeout = steady_clock::now() + ceil<nanoseconds>(d);
- sleep_until(c_timeout);
- }
- }
-
-#endif
-
-#endif
- }
-#ifdef BOOST_THREAD_USES_CHRONO
-
- template <class Clock, class Duration>
- void sleep_until(const chrono::time_point<Clock, Duration>& t)
- {
- using namespace chrono;
- mutex mut;
- condition_variable cv;
- unique_lock<mutex> lk(mut);
- while (Clock::now() < t)
- cv.wait_until(lk, t);
- }
-
-#if defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC && defined BOOST_CHRONO_HAS_CLOCK_STEADY
- template <class Rep, class Period>
- void sleep_for(const chrono::duration<Rep, Period>& d)
- {
- using namespace chrono;
- if (d > duration<Rep, Period>::zero())
- {
- steady_clock::time_point c_timeout = steady_clock::now() + ceil<nanoseconds>(d);
- sleep_until(c_timeout);
- }
- }
-
-#elif defined BOOST_THREAD_SLEEP_FOR_IS_STEADY
-
- template <class Rep, class Period>
- void sleep_for(const chrono::duration<Rep, Period>& d)
- {
- using namespace chrono;
- if (d > duration<Rep, Period>::zero())
- {
- duration<long double> Max = nanoseconds::max BOOST_PREVENT_MACRO_SUBSTITUTION ();
- nanoseconds ns;
- if (d < Max)
- {
- ns = duration_cast<nanoseconds>(d);
- if (ns < d)
- ++ns;
- }
- else
- ns = nanoseconds:: max BOOST_PREVENT_MACRO_SUBSTITUTION ();
- sleep_for(ns);
- }
- }
-
- template <class Duration>
- inline BOOST_SYMBOL_VISIBLE
- void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
- {
- using namespace chrono;
- sleep_for(t - steady_clock::now());
- }
-#else
- template <class Rep, class Period>
- void sleep_for(const chrono::duration<Rep, Period>& d)
- {
- using namespace chrono;
- if (d > duration<Rep, Period>::zero())
- {
- //system_clock::time_point c_timeout = time_point_cast<system_clock::duration>(system_clock::now() + ceil<nanoseconds>(d));
- system_clock::time_point c_timeout = system_clock::now() + ceil<system_clock::duration>(d);
- sleep_until(c_timeout);
- }
- }
-
-#endif
-
-#endif
- }
-}
-
-
-#endif
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));
}
}