$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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
     );
 }