1 /* 2 * Distributed under the Boost Software License, Version 1.0. 3 * (See accompanying file LICENSE_1_0.txt or copy at 4 * http://www.boost.org/LICENSE_1_0.txt) 5 * 6 * (C) Copyright 2007-2008 Anthony Williams 7 * (C) Copyright 2011-2012 Vicente J. Botet Escriba 8 * (C) Copyright 2013 Andrey Semashev 9 */ 10 /*! 11 * \file detail/condition_variables/condition_variable_posix.hpp 12 * 13 * \brief This header is the Boost.Sync library implementation, see the library documentation 14 * at http://www.boost.org/doc/libs/release/libs/sync/doc/html/index.html. 15 */ 16 17 #ifndef BOOST_SYNC_DETAIL_CONDITION_VARIABLES_CONDITION_VARIABLE_POSIX_HPP_INCLUDED_ 18 #define BOOST_SYNC_DETAIL_CONDITION_VARIABLES_CONDITION_VARIABLE_POSIX_HPP_INCLUDED_ 19 20 #include <cstddef> 21 #include <boost/assert.hpp> 22 #include <boost/utility/enable_if.hpp> 23 #include <boost/mpl/and.hpp> 24 #include <boost/sync/detail/config.hpp> 25 #include <boost/sync/locks/unique_lock_fwd.hpp> 26 #include <boost/sync/exceptions/wait_error.hpp> 27 #include <boost/sync/exceptions/resource_error.hpp> 28 #include <boost/sync/traits/is_condition_variable_compatible.hpp> 29 #include <boost/sync/detail/pthread.hpp> 30 #include <boost/sync/detail/time_traits.hpp> 31 #include <boost/sync/detail/time_units.hpp> 32 #include <boost/sync/detail/throw_exception.hpp> 33 #include <boost/sync/condition_variables/cv_status.hpp> 34 #include <boost/sync/detail/header.hpp> 35 36 #ifdef BOOST_HAS_PRAGMA_ONCE 37 #pragma once 38 #endif 39 40 #define BOOST_SYNC_DEFINES_CONDITION_VARIABLE_NATIVE_HANDLE 41 42 namespace boost { 43 44 namespace sync { 45 46 BOOST_SYNC_DETAIL_OPEN_ABI_NAMESPACE { 47 48 class condition_variable 49 { 50 public: 51 typedef pthread_cond_t* native_handle_type; 52 53 private: 54 pthread_cond_t m_cond; 55 56 public: 57 #if defined(PTHREAD_COND_INITIALIZER) 58 #if !defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) 59 #if !defined(BOOST_NO_CXX11_CONSTEXPR) 60 #define BOOST_SYNC_DEFINES_CONDITION_VARIABLE_CONSTEXPR_CONSTRUCTOR 61 #endif 62 63 BOOST_CONSTEXPR condition_variable() BOOST_NOEXCEPT : m_cond(PTHREAD_COND_INITIALIZER) 64 { 65 } 66 #else 67 condition_variable() BOOST_NOEXCEPT 68 { 69 BOOST_CONSTEXPR_OR_CONST pthread_cond_t temp = PTHREAD_COND_INITIALIZER; 70 m_cond = temp; 71 } 72 #endif 73 #else // defined(PTHREAD_COND_INITIALIZER) 74 condition_variable() 75 { 76 int const res = pthread_cond_init(&m_cond, NULL); 77 if (res) 78 BOOST_SYNC_DETAIL_THROW(resource_error, (res)("condition_variable constructor failed in pthread_cond_init")); 79 } 80 #endif // defined(PTHREAD_COND_INITIALIZER) 81 82 ~condition_variable() 83 { 84 BOOST_VERIFY(sync::detail::posix::pthread_cond_destroy(&m_cond) == 0); 85 } 86 87 void notify_one() BOOST_NOEXCEPT 88 { 89 BOOST_VERIFY(::pthread_cond_signal(&m_cond) == 0); 90 } 91 92 void notify_all() BOOST_NOEXCEPT 93 { 94 BOOST_VERIFY(::pthread_cond_broadcast(&m_cond) == 0); 95 } 96 97 template< typename Mutex > 98 typename enable_if< is_condition_variable_compatible< Mutex >, void >::type wait(unique_lock< Mutex >& lock) 99 { 100 BOOST_ASSERT(lock.owns_lock()); 101 this->priv_wait(lock.mutex()->native_handle()); 102 } 103 104 template< typename Mutex, typename Predicate > 105 typename enable_if< is_condition_variable_compatible< Mutex >, void >::type wait(unique_lock< Mutex >& lock, Predicate pred) 106 { 107 BOOST_ASSERT(lock.owns_lock()); 108 pthread_mutex_t* const mtx = lock.mutex()->native_handle(); 109 while (!pred()) 110 this->priv_wait(mtx); 111 } 112 113 template< typename Mutex, typename Time > 114 typename enable_if_c< sync::detail::time_traits< Time >::is_specialized && is_condition_variable_compatible< Mutex >::value, bool >::type 115 timed_wait(unique_lock< Mutex >& lock, Time const& t) 116 { 117 BOOST_ASSERT(lock.owns_lock()); 118 return priv_timed_wait(lock, sync::detail::time_traits< Time >::to_sync_unit(t)) == sync::cv_status::no_timeout; 119 } 120 121 template< typename Mutex, typename TimePoint, typename Predicate > 122 typename enable_if< mpl::and_< detail::is_time_tag_of< TimePoint, detail::time_point_tag >, is_condition_variable_compatible< Mutex > >, bool >::type 123 timed_wait(unique_lock< Mutex >& lock, TimePoint const& t, Predicate pred) 124 { 125 BOOST_ASSERT(lock.owns_lock()); 126 typedef typename sync::detail::time_traits< TimePoint >::unit_type unit_type; 127 unit_type abs_timeout = sync::detail::time_traits< TimePoint >::to_sync_unit(t); 128 while (!pred()) 129 { 130 if (this->priv_timed_wait(lock, abs_timeout) != sync::cv_status::no_timeout) 131 return pred(); 132 } 133 return true; 134 } 135 136 template< typename Mutex, typename Duration, typename Predicate > 137 typename enable_if< mpl::and_< detail::is_time_tag_of< Duration, detail::time_duration_tag >, is_condition_variable_compatible< Mutex > >, bool >::type 138 timed_wait(unique_lock< Mutex >& lock, Duration const& t, Predicate pred) 139 { 140 BOOST_ASSERT(lock.owns_lock()); 141 sync::detail::system_time_point abs_timeout = sync::detail::system_time_point::now() + sync::detail::time_traits< Duration >::to_sync_unit(t); 142 while (!pred()) 143 { 144 if (this->priv_timed_wait(lock, abs_timeout) != sync::cv_status::no_timeout) 145 return pred(); 146 } 147 return true; 148 } 149 150 template< typename Mutex, typename TimePoint > 151 typename enable_if< mpl::and_< detail::is_time_tag_of< TimePoint, detail::time_point_tag >, is_condition_variable_compatible< Mutex > >, sync::cv_status >::type 152 wait_until(unique_lock< Mutex >& lock, TimePoint const& abs_time) 153 { 154 BOOST_ASSERT(lock.owns_lock()); 155 return priv_timed_wait(lock, sync::detail::time_traits< TimePoint >::to_sync_unit(abs_time)); 156 } 157 158 template< typename Mutex, typename TimePoint, typename Predicate > 159 typename enable_if< mpl::and_< detail::is_time_tag_of< TimePoint, detail::time_point_tag >, is_condition_variable_compatible< Mutex > >, bool >::type 160 wait_until(unique_lock< Mutex >& lock, TimePoint const& abs_time, Predicate pred) 161 { 162 BOOST_ASSERT(lock.owns_lock()); 163 typedef typename sync::detail::time_traits< TimePoint >::unit_type unit_type; 164 unit_type abs_timeout = sync::detail::time_traits< TimePoint >::to_sync_unit(abs_time); 165 while (!pred()) 166 { 167 if (this->priv_timed_wait(lock, abs_timeout) != sync::cv_status::no_timeout) 168 return pred(); 169 } 170 return true; 171 } 172 173 template< typename Mutex, typename Duration > 174 typename enable_if< mpl::and_< detail::is_time_tag_of< Duration, detail::time_duration_tag >, is_condition_variable_compatible< Mutex > >, sync::cv_status >::type 175 wait_for(unique_lock< Mutex >& lock, Duration const& rel_time) 176 { 177 BOOST_ASSERT(lock.owns_lock()); 178 return priv_timed_wait(lock, sync::detail::time_traits< Duration >::to_sync_unit(rel_time)); 179 } 180 181 template< typename Mutex, typename Duration, typename Predicate > 182 typename enable_if< mpl::and_< detail::is_time_tag_of< Duration, detail::time_duration_tag >, is_condition_variable_compatible< Mutex > >, bool >::type 183 wait_for(unique_lock< Mutex >& lock, Duration const& rel_time, Predicate pred) 184 { 185 BOOST_ASSERT(lock.owns_lock()); 186 sync::detail::system_time_point abs_timeout = sync::detail::system_time_point::now() + sync::detail::time_traits< Duration >::to_sync_unit(rel_time); 187 while (!pred()) 188 { 189 if (this->priv_timed_wait(lock, abs_timeout) != sync::cv_status::no_timeout) 190 return pred(); 191 } 192 return true; 193 } 194 195 native_handle_type native_handle() BOOST_NOEXCEPT 196 { 197 return &m_cond; 198 } 199 200 BOOST_DELETED_FUNCTION(condition_variable(condition_variable const&)) 201 BOOST_DELETED_FUNCTION(condition_variable& operator= (condition_variable const&)) 202 203 private: 204 void priv_wait(pthread_mutex_t* mtx) 205 { 206 int const res = sync::detail::posix::pthread_cond_wait(&m_cond, mtx); 207 if (res != 0) 208 BOOST_SYNC_DETAIL_THROW(wait_error, (res)("condition_variable::wait failed in pthread_cond_wait")); 209 } 210 211 template< typename Mutex > 212 sync::cv_status priv_timed_wait(unique_lock< Mutex >& lock, sync::detail::system_duration dur) 213 { 214 return priv_timed_wait(lock, sync::detail::system_time_point::now() + dur); 215 } 216 217 template< typename Mutex > 218 sync::cv_status priv_timed_wait(unique_lock< Mutex >& lock, sync::detail::system_time_point const& t) 219 { 220 int const res = sync::detail::posix::pthread_cond_timedwait(&m_cond, lock.mutex()->native_handle(), &t.get()); 221 if (res == ETIMEDOUT) 222 return sync::cv_status::timeout; 223 else if (res != 0) 224 BOOST_SYNC_DETAIL_THROW(wait_error, (res)("condition_variable::timed_wait failed in pthread_cond_timedwait")); 225 return sync::cv_status::no_timeout; 226 } 227 228 template< typename Mutex, typename TimePoint > 229 sync::cv_status priv_timed_wait(unique_lock< Mutex >& lock, sync::detail::chrono_time_point< TimePoint > const& t) 230 { 231 typedef TimePoint time_point; 232 typedef typename time_point::clock clock; 233 typedef typename time_point::duration duration; 234 time_point now = clock::now(); 235 while (now < t.get()) 236 { 237 if (priv_timed_wait(lock, sync::detail::time_traits< duration >::to_sync_unit(t.get() - now)) == sync::cv_status::no_timeout) 238 return sync::cv_status::no_timeout; 239 now = clock::now(); 240 } 241 return sync::cv_status::timeout; 242 } 243 }; 244 245 } // namespace posix 246 247 } // namespace sync 248 249 } // namespace boost 250 251 #include <boost/sync/detail/footer.hpp> 252 253 #endif // BOOST_SYNC_DETAIL_CONDITION_VARIABLES_CONDITION_VARIABLE_POSIX_HPP_INCLUDED_ 254