1 // autoreset event for generic semaphores 2 // 3 // Copyright (C) 2013 Tim Blechmann 4 // Copyright (C) 2013 Andrey Semashev 5 // 6 // Distributed under the Boost Software License, Version 1.0. (See 7 // accompanying file LICENSE_1_0.txt or copy at 8 // http://www.boost.org/LICENSE_1_0.txt) 9 10 #ifndef BOOST_SYNC_DETAIL_EVENTS_AUTO_RESET_EVENT_SEMAPHORE_HPP_INCLUDED_ 11 #define BOOST_SYNC_DETAIL_EVENTS_AUTO_RESET_EVENT_SEMAPHORE_HPP_INCLUDED_ 12 13 #include <cstddef> 14 #include <boost/cstdint.hpp> 15 #include <boost/utility/enable_if.hpp> 16 #include <boost/sync/detail/config.hpp> 17 #include <boost/sync/detail/atomic.hpp> 18 #include <boost/sync/detail/pause.hpp> 19 #include <boost/sync/detail/time_traits.hpp> 20 #include <boost/sync/semaphore.hpp> 21 #include <boost/sync/detail/header.hpp> 22 23 #ifdef BOOST_HAS_PRAGMA_ONCE 24 #pragma once 25 #endif 26 27 namespace boost { 28 29 namespace sync { 30 31 BOOST_SYNC_DETAIL_OPEN_ABI_NAMESPACE { 32 33 class auto_reset_event 34 { 35 BOOST_DELETED_FUNCTION(auto_reset_event(auto_reset_event const&)) 36 BOOST_DELETED_FUNCTION(auto_reset_event& operator= (auto_reset_event const&)); 37 38 public: 39 auto_reset_event() : m_state(0) 40 { 41 } 42 43 void post() BOOST_NOEXCEPT 44 { 45 int32_t old_state = m_state.load(detail::atomic_ns::memory_order_acquire); 46 if (old_state >= 0) 47 { 48 for (;;) 49 { 50 if (m_state.compare_exchange_weak(old_state, old_state - 1, detail::atomic_ns::memory_order_release, detail::atomic_ns::memory_order_acquire)) 51 { 52 m_sem.post(); 53 return; // avoid unnecessary fence 54 } 55 56 if (old_state < 0) 57 break; // someone else has set the auto_reset_event with no waiters 58 59 detail::pause(); 60 } 61 } 62 63 detail::atomic_ns::atomic_thread_fence(detail::atomic_ns::memory_order_release); 64 } 65 66 void wait() 67 { 68 m_state.fetch_add(1, detail::atomic_ns::memory_order_acquire); 69 m_sem.wait(); 70 } 71 72 bool try_wait() 73 { 74 m_state.fetch_add(1, detail::atomic_ns::memory_order_acquire); 75 76 const bool wait_successful = m_sem.try_wait(); 77 if (wait_successful) 78 return true; 79 80 m_state.fetch_add(-1, detail::atomic_ns::memory_order_relaxed); 81 return false; 82 } 83 84 template< typename Time > 85 typename enable_if_c< sync::detail::time_traits< Time >::is_specialized, bool >::type timed_wait(Time const& timeout) 86 { 87 m_state.fetch_add(1, detail::atomic_ns::memory_order_acquire); 88 89 const bool wait_successful = m_sem.timed_wait(timeout); 90 if (wait_successful) 91 return true; 92 93 m_state.fetch_add(-1, detail::atomic_ns::memory_order_relaxed); 94 return false; 95 } 96 97 template< typename Duration > 98 typename enable_if< detail::is_time_tag_of< Duration, detail::time_duration_tag >, bool >::type wait_for(Duration const& duration) 99 { 100 return timed_wait(duration); 101 } 102 103 template< typename TimePoint > 104 typename enable_if< detail::is_time_tag_of< TimePoint, detail::time_point_tag >, bool >::type wait_until(TimePoint const& abs_time) 105 { 106 return timed_wait(abs_time); 107 } 108 109 private: 110 semaphore m_sem; 111 detail::atomic_ns::atomic< int32_t > m_state; 112 }; 113 114 } // namespace abi 115 116 } // namespace sync 117 118 } // namespace boost 119 120 #include <boost/sync/detail/footer.hpp> 121 122 #endif // BOOST_SYNC_DETAIL_EVENTS_AUTO_RESET_EVENT_SEMAPHORE_HPP_INCLUDED_ 123