1 // semaphore.hpp, osx/ios dispatch 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_SEMAPHORE_SEMAPHORE_DISPATCH_HPP_INCLUDED_ 11 #define BOOST_SYNC_DETAIL_SEMAPHORE_SEMAPHORE_DISPATCH_HPP_INCLUDED_ 12 13 #include <time.h> 14 #include <cstddef> 15 #include <dispatch/dispatch.h> 16 17 #include <boost/cstdint.hpp> 18 #include <boost/utility/enable_if.hpp> 19 #include <boost/sync/detail/config.hpp> 20 #include <boost/sync/detail/time_traits.hpp> 21 #include <boost/sync/detail/time_units.hpp> 22 #include <boost/sync/detail/throw_exception.hpp> 23 #include <boost/sync/detail/system_error.hpp> 24 #include <boost/sync/exceptions/resource_error.hpp> 25 #include <boost/sync/detail/header.hpp> 26 27 #ifdef BOOST_HAS_PRAGMA_ONCE 28 #pragma once 29 #endif 30 31 namespace boost { 32 33 namespace sync { 34 35 BOOST_SYNC_DETAIL_OPEN_ABI_NAMESPACE { 36 37 class semaphore 38 { 39 BOOST_DELETED_FUNCTION(semaphore(semaphore const&)) 40 BOOST_DELETED_FUNCTION(semaphore& operator=(semaphore const&)) 41 42 public: 43 explicit semaphore(unsigned int i = 0) 44 { 45 // Note that dispatch_release requires the semaphore counter to be equal to the one specified for dispatch_semaphore_create. 46 // Otherwise dispatch_release just crashes. This is probably a bug in libdispatch, but in order to work around it, we have to 47 // set the counter manually in a loop, after creating the semaphore. 48 m_sem = dispatch_semaphore_create(0); 49 if (m_sem == NULL) 50 BOOST_SYNC_DETAIL_THROW(resource_error, (sync::detail::system_ns::errc::not_enough_memory)("semaphore constructor failed in dispatch_semaphore_create")); 51 52 for (; i > 0; --i) 53 dispatch_semaphore_signal(m_sem); 54 } 55 56 ~semaphore() 57 { 58 dispatch_release(m_sem); 59 } 60 61 void post() 62 { 63 dispatch_semaphore_signal(m_sem); 64 } 65 66 void wait() 67 { 68 dispatch_semaphore_wait(m_sem, DISPATCH_TIME_FOREVER); 69 } 70 71 bool try_wait() 72 { 73 return dispatch_semaphore_wait(m_sem, DISPATCH_TIME_NOW) == 0; 74 } 75 76 template< typename Time > 77 typename enable_if_c< sync::detail::time_traits< Time >::is_specialized, bool >::type timed_wait(Time const& t) 78 { 79 return priv_timed_wait(sync::detail::time_traits< Time >::to_sync_unit(t)); 80 } 81 82 template< typename Duration > 83 typename enable_if< detail::is_time_tag_of< Duration, detail::time_duration_tag >, bool >::type wait_for(Duration const& duration) 84 { 85 return priv_timed_wait(sync::detail::time_traits< Duration >::to_sync_unit(duration)); 86 } 87 88 template< typename TimePoint > 89 typename enable_if< detail::is_time_tag_of< TimePoint, detail::time_point_tag >, bool >::type wait_until(TimePoint const& abs_time) 90 { 91 return priv_timed_wait(sync::detail::time_traits< TimePoint >::to_sync_unit(abs_time)); 92 } 93 94 private: 95 bool priv_timed_wait(sync::detail::system_duration dur) 96 { 97 dispatch_time_t timeout = DISPATCH_TIME_NOW; 98 99 sync::detail::system_duration::native_type time_left = dur.get(); 100 if (time_left > 0) 101 { 102 enum 103 { 104 nanoseconds_fraction = 1000000000u, 105 conversion_ratio = static_cast< uint64_t >(nanoseconds_fraction) >= sync::detail::system_duration::subsecond_fraction ? 106 nanoseconds_fraction / sync::detail::system_duration::subsecond_fraction : 107 sync::detail::system_duration::subsecond_fraction / nanoseconds_fraction 108 }; 109 110 const int64_t nanoseconds_left = static_cast< uint64_t >(nanoseconds_fraction) >= sync::detail::system_duration::subsecond_fraction ? 111 time_left / conversion_ratio : time_left * conversion_ratio; 112 113 timeout = dispatch_time(DISPATCH_TIME_NOW, nanoseconds_left); 114 } 115 116 return dispatch_semaphore_wait(m_sem, timeout) == 0; 117 } 118 119 bool priv_timed_wait(sync::detail::system_time_point const& t) 120 { 121 struct timespec timespec_timeout = t.get(); 122 dispatch_time_t timeout = dispatch_walltime( ×pec_timeout, 0 ); 123 return dispatch_semaphore_wait(m_sem, timeout) == 0; 124 } 125 126 template< typename TimePoint > 127 bool priv_timed_wait(sync::detail::chrono_time_point< TimePoint > const& t) 128 { 129 typedef TimePoint time_point; 130 typedef typename time_point::clock clock; 131 typedef typename time_point::duration duration; 132 time_point now = clock::now(); 133 while (now < t.get()) 134 { 135 if (priv_timed_wait(sync::detail::time_traits< duration >::to_sync_unit(t.get() - now))) 136 return true; 137 now = clock::now(); 138 } 139 return false; 140 } 141 142 private: 143 dispatch_semaphore_t m_sem; 144 }; 145 146 } // namespace posix 147 148 } // namespace sync 149 150 } // namespace boost 151 152 #include <boost/sync/detail/footer.hpp> 153 154 #endif // BOOST_SYNC_DETAIL_SEMAPHORE_SEMAPHORE_DISPATCH_HPP_INCLUDED_ 155