$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r85773 - in trunk: boost/sync boost/sync/detail/event libs/sync/test
From: tim_at_[hidden]
Date: 2013-09-18 07:38:52
Author: timblechmann
Date: 2013-09-18 07:38:52 EDT (Wed, 18 Sep 2013)
New Revision: 85773
URL: http://svn.boost.org/trac/boost/changeset/85773
Log:
sync: event - implement event with mach semaphores
Added:
   trunk/boost/sync/detail/event/event_mach.hpp   (contents, props changed)
Text files modified: 
   trunk/boost/sync/detail/event/event_emulation.hpp |    11 +-                                      
   trunk/boost/sync/detail/event/event_mach.hpp      |   156 ++++++++++++++++++++++++++++++++++++++++
   trunk/boost/sync/event.hpp                        |    22 ++++-                                   
   trunk/libs/sync/test/event_test.cpp               |     2                                         
   4 files changed, 180 insertions(+), 11 deletions(-)
Modified: trunk/boost/sync/detail/event/event_emulation.hpp
==============================================================================
--- trunk/boost/sync/detail/event/event_emulation.hpp	Wed Sep 18 06:58:46 2013	(r85772)
+++ trunk/boost/sync/detail/event/event_emulation.hpp	2013-09-18 07:38:52 EDT (Wed, 18 Sep 2013)	(r85773)
@@ -32,16 +32,17 @@
 public:
     explicit event(bool auto_reset = false) :
         m_auto_reset(auto_reset), m_is_set(false)
-    {
-    }
+    {}
 
     void post()
     {
         unique_lock<mutex> lock(m_mutex);
+        bool already_signaled = m_is_set;
         m_is_set = true;
-        if (m_auto_reset)
-            m_cond.notify_one();
-        else
+        if (m_auto_reset) {
+            if (!already_signaled)
+                m_cond.notify_one();
+        } else
             m_cond.notify_all();
     }
 
Added: trunk/boost/sync/detail/event/event_mach.hpp
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ trunk/boost/sync/detail/event/event_mach.hpp	2013-09-18 07:38:52 EDT (Wed, 18 Sep 2013)	(r85773)
@@ -0,0 +1,156 @@
+// event.hpp, mach events
+//
+// Copyright (C) 2013 Tim Blechmann
+//
+// 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)
+
+#ifndef BOOST_SYNC_EVENT_DETAIL_DARWIN_EVENT_MACH_HPP
+#define BOOST_SYNC_EVENT_DETAIL_DARWIN_EVENT_MACH_HPP
+
+#include <cstddef>
+#include <boost/assert.hpp>
+
+#include <boost/sync/detail/config.hpp>
+#include <boost/sync/exceptions/resource_error.hpp>
+#include <boost/sync/detail/header.hpp>
+
+#include <mach/task.h>
+#include <mach/semaphore.h>
+#include <mach/mach_traps.h>
+#include <mach/mach_init.h>
+
+#include <boost/atomic.hpp>
+
+namespace boost {
+
+namespace sync {
+
+BOOST_SYNC_DETAIL_OPEN_ABI_NAMESPACE {
+
+class event
+{
+    BOOST_DELETED_FUNCTION(event(event const&))
+    BOOST_DELETED_FUNCTION(event& operator=(event const&));
+
+public:
+    explicit event(bool auto_reset = false):
+        m_auto_reset(auto_reset), m_signaled(0)
+    {
+        kern_return_t result = semaphore_create(mach_task_self(), &m_sem, SYNC_POLICY_FIFO, 0);
+        BOOST_VERIFY(result == KERN_SUCCESS);
+    }
+
+    ~event()
+    {
+        kern_return_t result = semaphore_destroy(mach_task_self(), m_sem);
+        BOOST_VERIFY(result == KERN_SUCCESS);
+    }
+
+    void post()
+    {
+        if (m_auto_reset) {
+            bool already_signaled = m_signaled.exchange(true);
+            if (!already_signaled)
+                semaphore_signal( m_sem ); // wake one thread!
+        } else {
+            m_signaled = true;
+            semaphore_signal_all( m_sem ); // wake all threads!& reset semaphore count
+        }
+    }
+
+    void reset()
+    {
+        m_signaled = false;
+    }
+
+    void wait()
+    {
+        if (m_auto_reset) {
+            // the first waiter succeeds and resets the signalled state
+
+        try_again:
+            kern_return_t result = semaphore_wait( m_sem );
+
+            if (result == KERN_SUCCESS) {
+                bool isTrue = true;
+                bool firstWaiter = m_signaled.compare_exchange_strong(isTrue, false);
+
+                if (firstWaiter) // only the first waiter succeeds
+                    return;
+            }
+
+            goto try_again;
+        } else {
+            if (m_signaled.load() == true)
+                return;
+
+            kern_return_t result = semaphore_wait( m_sem );
+            BOOST_VERIFY (result == KERN_SUCCESS);
+        }
+    }
+
+    bool try_wait()
+    {
+        const mach_timespec_t immediate = {0, 0};
+        return do_try_wait_until(immediate);
+    }
+
+    template <class Rep, class Period>
+    bool try_wait_for(const chrono::duration<Rep, Period> & duration)
+    {
+        BOOST_AUTO ( seconds, chrono::duration_cast<chrono::seconds>(duration) );
+        BOOST_AUTO ( nanoseconds, chrono::duration_cast<chrono::nanoseconds>(duration) - seconds );
+
+        const mach_timespec_t mach_duration = { seconds.count(), nanoseconds.count() };
+        return do_try_wait_until( mach_duration );
+    }
+
+    template <class Clock, class Duration>
+    bool try_wait_until(const chrono::time_point<Clock, Duration> & timeout )
+    {
+        return try_wait_for( timeout - Clock::now() );
+    }
+
+private:
+    bool do_try_wait_until (const mach_timespec_t & timeout)
+    {
+        if (m_auto_reset) {
+            // the first waiter succeeds and resets the signaled state
+
+            kern_return_t result = semaphore_timedwait( m_sem, timeout );
+
+            if (result == KERN_SUCCESS) {
+                bool isTrue = true;
+                bool firstWaiter = m_signaled.compare_exchange_strong(isTrue, false);
+
+                if (firstWaiter) // only the first waiter succeeds
+                    return true;
+            }
+            return false;
+
+        } else {
+            if (m_signaled.load() == true)
+                return true;
+
+            kern_return_t result = semaphore_timedwait( m_sem, timeout );
+            if (result == KERN_SUCCESS)
+                return true;
+            else
+                return false;
+        }
+    }
+
+    const bool m_auto_reset;
+    semaphore_t m_sem;
+    atomic_bool m_signaled;
+};
+
+}
+}
+}
+
+#include <boost/sync/detail/footer.hpp>
+
+#endif // BOOST_SYNC_EVENT_DETAIL_DARWIN_EVENT_MACH_HPP
Modified: trunk/boost/sync/event.hpp
==============================================================================
--- trunk/boost/sync/event.hpp	Wed Sep 18 06:58:46 2013	(r85772)
+++ trunk/boost/sync/event.hpp	2013-09-18 07:38:52 EDT (Wed, 18 Sep 2013)	(r85773)
@@ -97,14 +97,26 @@
 #pragma once
 #endif
 
+#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+#include <Availability.h>
+
+// OSX
+#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
+
+// Check: do other mach-based platforms support mach semaphores?
+
+#if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_7
+#define BOOST_SYNC_DETAIL_PLATFORM_MACH
+#endif
+
+#endif // __MAC_OS_X_VERSION_MIN_REQUIRED
+#endif // apple stuff
+
 #if defined(BOOST_SYNC_DETAIL_PLATFORM_WINAPI)
 #include <boost/sync/detail/event/event_windows.hpp>
 
-//#elif defined(BOOST_SYNC_POSIX_SEMAPHORES)
-//#include <boost/sync/semaphore/semaphore_posix.hpp>
-
-//#elif defined(BOOST_SYNC_DISPATCH_SEMAPHORES)
-//#include <boost/sync/semaphore/semaphore_dispatch.hpp>
+#elif defined(BOOST_SYNC_DETAIL_PLATFORM_MACH)
+#include <boost/sync/detail/event/event_mach.hpp>
 
 #else
 
Modified: trunk/libs/sync/test/event_test.cpp
==============================================================================
--- trunk/libs/sync/test/event_test.cpp	Wed Sep 18 06:58:46 2013	(r85772)
+++ trunk/libs/sync/test/event_test.cpp	2013-09-18 07:38:52 EDT (Wed, 18 Sep 2013)	(r85773)
@@ -41,7 +41,7 @@
     boost::sync::event ev(true);
 
     ev.post();
-    ev.wait();
+    BOOST_REQUIRE( ev.try_wait() == true );
     BOOST_REQUIRE( ev.try_wait() == false );
 }