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 2012-2013 Vicente J. Botet Escriba 8 * (C) Copyright 2013 Andrey Semashev 9 */ 10 /*! 11 * \file detail/mutexes/timed_mutex_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_MUTEXES_TIMED_MUTEX_POSIX_HPP_INCLUDED_ 18 #define BOOST_SYNC_DETAIL_MUTEXES_TIMED_MUTEX_POSIX_HPP_INCLUDED_ 19 20 #include <errno.h> 21 #include <cstddef> 22 #include <boost/assert.hpp> 23 #include <boost/utility/enable_if.hpp> 24 #include <boost/sync/exceptions/lock_error.hpp> 25 #include <boost/sync/exceptions/resource_error.hpp> 26 #include <boost/sync/detail/config.hpp> 27 #include <boost/sync/detail/pthread.hpp> 28 #include <boost/sync/detail/time_traits.hpp> 29 #include <boost/sync/detail/time_units.hpp> 30 #include <boost/sync/detail/throw_exception.hpp> 31 #if !defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 32 #include <boost/sync/detail/pthread_mutex_locks.hpp> 33 #endif 34 #include <boost/sync/detail/header.hpp> 35 36 #ifdef BOOST_HAS_PRAGMA_ONCE 37 #pragma once 38 #endif 39 40 #if defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 41 #define BOOST_SYNC_DEFINES_TIMED_MUTEX_NATIVE_HANDLE 42 #endif 43 44 namespace boost { 45 46 namespace sync { 47 48 BOOST_SYNC_DETAIL_OPEN_ABI_NAMESPACE { 49 50 class timed_mutex 51 { 52 public: 53 #if defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 54 typedef void _is_condition_variable_compatible; 55 #endif 56 #if defined(BOOST_SYNC_DEFINES_TIMED_MUTEX_NATIVE_HANDLE) 57 typedef pthread_mutex_t* native_handle_type; 58 #endif 59 60 private: 61 pthread_mutex_t m_mutex; 62 #if !defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 63 pthread_cond_t m_cond; 64 bool m_is_locked; 65 #endif 66 67 public: 68 #if defined(PTHREAD_MUTEX_INITIALIZER) && (defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) || defined(PTHREAD_COND_INITIALIZER)) 69 #if !defined(BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX) 70 #if !defined(BOOST_NO_CXX11_CONSTEXPR) 71 #define BOOST_SYNC_DEFINES_TIMED_MUTEX_CONSTEXPR_CONSTRUCTOR 72 #endif 73 74 BOOST_CONSTEXPR timed_mutex() BOOST_NOEXCEPT : 75 m_mutex(PTHREAD_MUTEX_INITIALIZER) 76 #if !defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 77 , m_cond(PTHREAD_COND_INITIALIZER), 78 m_is_locked(false) 79 #endif 80 { 81 } 82 #else 83 timed_mutex() BOOST_NOEXCEPT 84 { 85 BOOST_CONSTEXPR_OR_CONST pthread_mutex_t temp = PTHREAD_MUTEX_INITIALIZER; 86 m_mutex = temp; 87 88 #if !defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 89 BOOST_CONSTEXPR_OR_CONST pthread_cond_t temp2 = PTHREAD_COND_INITIALIZER; 90 m_cond = temp2; 91 m_is_locked = false; 92 #endif 93 } 94 #endif 95 #else // defined(PTHREAD_MUTEX_INITIALIZER) 96 timed_mutex() 97 { 98 int const res = pthread_mutex_init(&m_mutex, NULL); 99 if (res) 100 BOOST_SYNC_DETAIL_THROW(resource_error, (res)("timed_mutex constructor failed in pthread_mutex_init")); 101 102 #if !defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 103 int const res2 = pthread_cond_init(&m_cond, NULL); 104 if (res2) 105 BOOST_SYNC_DETAIL_THROW(resource_error, (res2)("timed_mutex constructor failed in pthread_cond_init")); 106 m_is_locked = false; 107 #endif 108 } 109 #endif // defined(PTHREAD_MUTEX_INITIALIZER) 110 111 ~timed_mutex() 112 { 113 BOOST_VERIFY(sync::detail::posix::pthread_mutex_destroy(&m_mutex) == 0); 114 #if !defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 115 BOOST_VERIFY(sync::detail::posix::pthread_cond_destroy(&m_cond) == 0); 116 #endif 117 } 118 119 #if defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 120 121 void lock() 122 { 123 int const res = sync::detail::posix::pthread_mutex_lock(&m_mutex); 124 if (res) 125 BOOST_SYNC_DETAIL_THROW(lock_error, (res)("timed_mutex lock failed in pthread_mutex_lock")); 126 } 127 128 void unlock() BOOST_NOEXCEPT 129 { 130 BOOST_VERIFY(sync::detail::posix::pthread_mutex_unlock(&m_mutex) == 0); 131 } 132 133 bool try_lock() 134 { 135 int const res = sync::detail::posix::pthread_mutex_trylock(&m_mutex); 136 137 if (res == 0) 138 return true; 139 else if (res != EBUSY) 140 BOOST_SYNC_DETAIL_THROW(lock_error, (res)("timed_mutex try_lock failed in pthread_mutex_trylock")); 141 return false; 142 } 143 144 #else // defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 145 146 void lock() 147 { 148 sync::detail::posix::pthread_mutex_lock_guard const local_lock(m_mutex); 149 while (m_is_locked) 150 { 151 BOOST_VERIFY(sync::detail::posix::pthread_cond_wait(&m_cond, &m_mutex) == 0); 152 } 153 m_is_locked = true; 154 } 155 156 void unlock() BOOST_NOEXCEPT 157 { 158 sync::detail::posix::pthread_mutex_lock_guard const local_lock(m_mutex); 159 m_is_locked = false; 160 BOOST_VERIFY(pthread_cond_signal(&m_cond) == 0); 161 } 162 163 bool try_lock() 164 { 165 sync::detail::posix::pthread_mutex_lock_guard const local_lock(m_mutex); 166 if (m_is_locked) 167 return false; 168 m_is_locked = true; 169 return true; 170 } 171 172 #endif // defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 173 174 template< typename Time > 175 typename enable_if_c< sync::detail::time_traits< Time >::is_specialized, bool >::type timed_lock(Time const& t) 176 { 177 return priv_timed_lock(sync::detail::time_traits< Time >::to_sync_unit(t)); 178 } 179 180 template< typename Duration > 181 typename detail::enable_if_tag< Duration, detail::time_duration_tag, bool >::type try_lock_for(Duration const& rel_time) 182 { 183 return priv_timed_lock(sync::detail::time_traits< Duration >::to_sync_unit(rel_time)); 184 } 185 186 template< typename TimePoint > 187 typename detail::enable_if_tag< TimePoint, detail::time_point_tag, bool >::type try_lock_until(TimePoint const& abs_time) 188 { 189 return priv_timed_lock(sync::detail::time_traits< TimePoint >::to_sync_unit(abs_time)); 190 } 191 192 #if defined(BOOST_SYNC_DEFINES_TIMED_MUTEX_NATIVE_HANDLE) 193 native_handle_type native_handle() BOOST_NOEXCEPT 194 { 195 return &m_mutex; 196 } 197 #endif 198 199 BOOST_DELETED_FUNCTION(timed_mutex(timed_mutex const&)) 200 BOOST_DELETED_FUNCTION(timed_mutex& operator= (timed_mutex const&)) 201 202 private: 203 bool priv_timed_lock(sync::detail::system_duration dur) 204 { 205 return priv_timed_lock(sync::detail::system_time_point::now() + dur); 206 } 207 208 bool priv_timed_lock(sync::detail::system_time_point const& t) 209 { 210 #if defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 211 212 int const res = sync::detail::posix::pthread_mutex_timedlock(&m_mutex, &t.get()); 213 214 if (res == 0) 215 return true; 216 else if (res != ETIMEDOUT) 217 BOOST_SYNC_DETAIL_THROW(lock_error, (res)("timed_mutex timed_lock failed in pthread_mutex_timedlock")); 218 return false; 219 220 #else // defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 221 222 sync::detail::posix::pthread_mutex_lock_guard const local_lock(m_mutex); 223 while (m_is_locked) 224 { 225 int const cond_res = sync::detail::posix::pthread_cond_timedwait(&m_cond, &m_mutex, &t.get()); 226 if (cond_res == ETIMEDOUT) 227 { 228 if (!m_is_locked) 229 break; 230 else 231 return false; 232 } 233 else if (cond_res != 0) 234 { 235 BOOST_SYNC_DETAIL_THROW(lock_error, (cond_res)("timed_mutex timed_lock failed in pthread_cond_timedwait")); 236 } 237 } 238 m_is_locked = true; 239 return true; 240 241 #endif // defined(BOOST_SYNC_DETAIL_PTHREAD_HAS_TIMEDLOCK) 242 } 243 244 template< typename TimePoint > 245 bool priv_timed_lock(sync::detail::chrono_time_point< TimePoint > const& t) 246 { 247 if (try_lock()) 248 return true; 249 250 typedef TimePoint time_point; 251 typedef typename time_point::clock clock; 252 typedef typename time_point::duration duration; 253 time_point now = clock::now(); 254 while (now < t.get()) 255 { 256 if (priv_timed_lock(sync::detail::time_traits< duration >::to_sync_unit(t.get() - now))) 257 return true; 258 now = clock::now(); 259 } 260 return false; 261 } 262 }; 263 264 } // namespace posix 265 266 } // namespace sync 267 268 } // namespace boost 269 270 #include <boost/sync/detail/footer.hpp> 271 272 #endif // BOOST_SYNC_DETAIL_MUTEXES_TIMED_MUTEX_POSIX_HPP_INCLUDED_ 273