Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r86352 - in trunk/boost/sync/detail: . events
From: andrey.semashev_at_[hidden]
Date: 2013-10-18 10:31:29


Author: andysem
Date: 2013-10-18 10:31:29 EDT (Fri, 18 Oct 2013)
New Revision: 86352
URL: http://svn.boost.org/trac/boost/changeset/86352

Log:
Changed futex API adapters so that it is more obvious that the timeout is relative. Fixed timeouts handling in auto-reset futex event.

Text files modified:
   trunk/boost/sync/detail/events/auto_reset_event_futex.hpp | 85 ++++++++++++++++++++++++++++++++++++---
   trunk/boost/sync/detail/events/manual_reset_event_futex.hpp | 10 ---
   trunk/boost/sync/detail/futex.hpp | 9 ++-
   3 files changed, 86 insertions(+), 18 deletions(-)

Modified: trunk/boost/sync/detail/events/auto_reset_event_futex.hpp
==============================================================================
--- trunk/boost/sync/detail/events/auto_reset_event_futex.hpp Fri Oct 18 10:00:03 2013 (r86351)
+++ trunk/boost/sync/detail/events/auto_reset_event_futex.hpp 2013-10-18 10:31:29 EDT (Fri, 18 Oct 2013) (r86352)
@@ -155,7 +155,7 @@
     }
 
 private:
- bool priv_timed_wait(sync::detail::system_time_point const& timeout)
+ bool priv_timed_wait(sync::detail::system_time_point const& abs_timeout)
     {
         // Try the fast path first
         if (this->try_wait())
@@ -169,7 +169,83 @@
             if (posts == 0)
             {
             again:
- const int status = sync::detail::linux_::futex_timedwait(reinterpret_cast< int* >(&m_state), old_state, &timeout.get());
+ sync::detail::system_duration::native_type time_left = (abs_timeout - sync::detail::system_time_point::now()).get();
+ if (time_left <= 0)
+ goto timeout;
+ const int status = sync::detail::linux_::futex_timedwait(reinterpret_cast< int* >(&m_state), old_state, time_left);
+ if (status != 0)
+ {
+ const int err = errno;
+ switch (err)
+ {
+ case ETIMEDOUT:
+ old_state = m_state.load(detail::atomic_ns::memory_order_acquire);
+ goto timeout;
+
+ case EINTR: // signal received
+ goto again;
+
+ case EWOULDBLOCK: // another thread changed the state
+ break;
+
+ default:
+ BOOST_ASSERT(false);
+ }
+ }
+
+ old_state = m_state.load(detail::atomic_ns::memory_order_acquire);
+ posts = old_state >> post_count_lowest_bit;
+ if (posts == 0)
+ goto again;
+ }
+
+ // Remove one post and one waiter from the counters
+ if (m_state.compare_exchange_strong(old_state, old_state - (post_count_one + 1u), detail::atomic_ns::memory_order_acquire, detail::atomic_ns::memory_order_release))
+ break;
+ }
+
+ return true;
+
+ timeout:
+ while (true)
+ {
+ const unsigned int posts = old_state >> post_count_lowest_bit;
+ if (posts == 0)
+ {
+ // Remove one waiter
+ if (m_state.compare_exchange_weak(old_state, old_state - 1u, detail::atomic_ns::memory_order_acquire, detail::atomic_ns::memory_order_release))
+ return false;
+ }
+ else
+ {
+ // Remove one post and one waiter from the counters
+ if (m_state.compare_exchange_weak(old_state, old_state - (post_count_one + 1u), detail::atomic_ns::memory_order_acquire, detail::atomic_ns::memory_order_release))
+ return true;
+ }
+
+ detail::pause();
+ }
+ }
+
+ bool priv_timed_wait(sync::detail::system_duration dur)
+ {
+ // Try the fast path first
+ if (this->try_wait())
+ return true;
+
+ sync::detail::system_duration::native_type time_left = dur.get();
+ if (time_left <= 0)
+ return false;
+
+ // Add one waiter
+ unsigned int old_state = m_state.fetch_add(1, detail::atomic_ns::memory_order_acq_rel);
+ while (true)
+ {
+ unsigned int posts = old_state >> post_count_lowest_bit;
+ if (posts == 0)
+ {
+ again:
+ const int status = sync::detail::linux_::futex_timedwait(reinterpret_cast< int* >(&m_state), old_state, time_left);
                 if (status != 0)
                 {
                     const int err = errno;
@@ -222,11 +298,6 @@
         return true;
     }
 
- bool priv_timed_wait(sync::detail::system_duration dur)
- {
- return priv_timed_wait(sync::detail::system_time_point::now() + dur);
- }
-
     template< typename TimePoint >
     bool priv_timed_wait(sync::detail::chrono_time_point< TimePoint > const& t)
     {

Modified: trunk/boost/sync/detail/events/manual_reset_event_futex.hpp
==============================================================================
--- trunk/boost/sync/detail/events/manual_reset_event_futex.hpp Fri Oct 18 10:00:03 2013 (r86351)
+++ trunk/boost/sync/detail/events/manual_reset_event_futex.hpp 2013-10-18 10:31:29 EDT (Fri, 18 Oct 2013) (r86352)
@@ -108,14 +108,11 @@
             if (time_left <= 0)
                 return false;
 
- struct ::timespec timeout;
             // Check that system time resolution is nanoseconds
             BOOST_STATIC_ASSERT(sync::detail::system_duration::subsecond_fraction == 1000000000u);
- timeout.tv_sec = time_left / sync::detail::system_duration::subsecond_fraction;
- timeout.tv_nsec = time_left % sync::detail::system_duration::subsecond_fraction;
 
             // Note that futex timeout must be relative
- const int status = sync::detail::linux_::futex_timedwait(reinterpret_cast< int* >(&m_state), 0, &timeout);
+ const int status = sync::detail::linux_::futex_timedwait(reinterpret_cast< int* >(&m_state), 0, time_left);
             if (status == 0)
                 break;
 
@@ -144,15 +141,12 @@
             if (time_left <= 0)
                 return false;
 
- struct ::timespec timeout;
             // Check that system time resolution is nanoseconds
             BOOST_STATIC_ASSERT(sync::detail::system_duration::subsecond_fraction == 1000000000u);
- timeout.tv_sec = time_left / sync::detail::system_duration::subsecond_fraction;
- timeout.tv_nsec = time_left % sync::detail::system_duration::subsecond_fraction;
             do
             {
                 // Note that futex timeout must be relative
- const int status = sync::detail::linux_::futex_timedwait(reinterpret_cast< int* >(&m_state), 0, &timeout);
+ const int status = sync::detail::linux_::futex_timedwait(reinterpret_cast< int* >(&m_state), 0, time_left);
                 if (status == 0)
                     break;
 

Modified: trunk/boost/sync/detail/futex.hpp
==============================================================================
--- trunk/boost/sync/detail/futex.hpp Fri Oct 18 10:00:03 2013 (r86351)
+++ trunk/boost/sync/detail/futex.hpp 2013-10-18 10:31:29 EDT (Fri, 18 Oct 2013) (r86352)
@@ -60,9 +60,12 @@
     );
 }
 
-//! Checks that the value \c pval is \c expected and blocks until \c timeout
-BOOST_FORCEINLINE int futex_timedwait(int* pval, int expected, const struct ::timespec* timeout) BOOST_NOEXCEPT
+//! Checks that the value \c pval is \c expected and blocks until \c timeout_nsec expires
+BOOST_FORCEINLINE int futex_timedwait(int* pval, int expected, uint64_t timeout_nsec) BOOST_NOEXCEPT
 {
+ struct ::timespec timeout;
+ timeout.tv_sec = timeout_nsec / 1000000000u;
+ timeout.tv_nsec = timeout_nsec % 1000000000u;
     return futex_invoke
     (
         pval,
@@ -72,7 +75,7 @@
         FUTEX_WAIT,
 #endif
         expected,
- timeout
+ &timeout
     );
 }
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk