1 #ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP 2 #define BOOST_THREAD_PTHREAD_MUTEX_HPP 3 // (C) Copyright 2007-8 Anthony Williams 4 // (C) Copyright 2011,2012,2015 Vicente J. Botet Escriba 5 // Distributed under the Boost Software License, Version 1.0. (See 6 // accompanying file LICENSE_1_0.txt or copy at 7 // http://www.boost.org/LICENSE_1_0.txt) 8 9 #include <boost/thread/detail/config.hpp> 10 #include <boost/assert.hpp> 11 #include <pthread.h> 12 #include <boost/throw_exception.hpp> 13 #include <boost/core/ignore_unused.hpp> 14 #include <boost/thread/exceptions.hpp> 15 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS 16 #include <boost/thread/lock_types.hpp> 17 #endif 18 #include <boost/thread/thread_time.hpp> 19 #if defined BOOST_THREAD_USES_DATETIME 20 #include <boost/thread/xtime.hpp> 21 #endif 22 #include <boost/assert.hpp> 23 #include <errno.h> 24 #include <boost/thread/detail/platform_time.hpp> 25 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> 26 #include <boost/thread/pthread/pthread_helpers.hpp> 27 #ifdef BOOST_THREAD_USES_CHRONO 28 #include <boost/chrono/system_clocks.hpp> 29 #include <boost/chrono/ceil.hpp> 30 #endif 31 #include <boost/thread/detail/delete.hpp> 32 33 34 #include <boost/config/abi_prefix.hpp> 35 36 namespace boost 37 { 38 39 class BOOST_THREAD_CAPABILITY("mutex") mutex 40 { 41 private: 42 pthread_mutex_t m; 43 public: 44 BOOST_THREAD_NO_COPYABLE(mutex) 45 mutex()46 mutex() 47 { 48 int const res=posix::pthread_mutex_init(&m); 49 if(res) 50 { 51 boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init")); 52 } 53 } ~mutex()54 ~mutex() 55 { 56 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); 57 } 58 lock()59 void lock() BOOST_THREAD_ACQUIRE() 60 { 61 int res = posix::pthread_mutex_lock(&m); 62 if (res) 63 { 64 boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); 65 } 66 } 67 unlock()68 void unlock() BOOST_THREAD_RELEASE() 69 { 70 BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); 71 } 72 try_lock()73 bool try_lock() BOOST_THREAD_TRY_ACQUIRE(true) 74 { 75 int res = posix::pthread_mutex_trylock(&m); 76 if (res==EBUSY) 77 { 78 return false; 79 } 80 81 return !res; 82 } 83 84 #define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE 85 typedef pthread_mutex_t* native_handle_type; native_handle()86 native_handle_type native_handle() 87 { 88 return &m; 89 } 90 91 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS 92 typedef unique_lock<mutex> scoped_lock; 93 typedef detail::try_lock_wrapper<mutex> scoped_try_lock; 94 #endif 95 }; 96 97 typedef mutex try_mutex; 98 99 class timed_mutex 100 { 101 private: 102 pthread_mutex_t m; 103 #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK 104 pthread_cond_t cond; 105 bool is_locked; 106 #endif 107 public: 108 BOOST_THREAD_NO_COPYABLE(timed_mutex) timed_mutex()109 timed_mutex() 110 { 111 int const res=posix::pthread_mutex_init(&m); 112 if(res) 113 { 114 boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init")); 115 } 116 #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK 117 int const res2=posix::pthread_cond_init(&cond); 118 if(res2) 119 { 120 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); 121 boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init")); 122 } 123 is_locked=false; 124 #endif 125 } ~timed_mutex()126 ~timed_mutex() 127 { 128 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); 129 #ifndef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK 130 BOOST_VERIFY(!posix::pthread_cond_destroy(&cond)); 131 #endif 132 } 133 134 #if defined BOOST_THREAD_USES_DATETIME 135 template<typename TimeDuration> timed_lock(TimeDuration const & relative_time)136 bool timed_lock(TimeDuration const & relative_time) 137 { 138 if (relative_time.is_pos_infinity()) 139 { 140 lock(); 141 return true; 142 } 143 if (relative_time.is_special()) 144 { 145 return true; 146 } 147 detail::platform_duration d(relative_time); 148 #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) 149 const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); 150 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 151 while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) 152 { 153 d = ts - detail::mono_platform_clock::now(); 154 if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred 155 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 156 } 157 return true; 158 #else 159 return do_try_lock_until(detail::internal_platform_clock::now() + d); 160 #endif 161 } timed_lock(boost::xtime const & absolute_time)162 bool timed_lock(boost::xtime const & absolute_time) 163 { 164 return timed_lock(system_time(absolute_time)); 165 } 166 #endif 167 #ifdef BOOST_THREAD_USES_PTHREAD_TIMEDLOCK lock()168 void lock() 169 { 170 int res = posix::pthread_mutex_lock(&m); 171 if (res) 172 { 173 boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); 174 } 175 } 176 unlock()177 void unlock() 178 { 179 BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); 180 } 181 try_lock()182 bool try_lock() 183 { 184 int res = posix::pthread_mutex_trylock(&m); 185 if (res==EBUSY) 186 { 187 return false; 188 } 189 190 return !res; 191 } 192 193 194 private: do_try_lock_until(detail::internal_platform_timepoint const & timeout)195 bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) 196 { 197 int const res=pthread_mutex_timedlock(&m,&timeout.getTs()); 198 BOOST_ASSERT(!res || res==ETIMEDOUT); 199 return !res; 200 } 201 public: 202 203 #else 204 void lock() 205 { 206 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 207 while(is_locked) 208 { 209 BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m)); 210 } 211 is_locked=true; 212 } 213 214 void unlock() 215 { 216 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 217 is_locked=false; 218 BOOST_VERIFY(!posix::pthread_cond_signal(&cond)); 219 } 220 221 bool try_lock() 222 { 223 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 224 if(is_locked) 225 { 226 return false; 227 } 228 is_locked=true; 229 return true; 230 } 231 232 private: 233 bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) 234 { 235 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 236 while(is_locked) 237 { 238 int const cond_res=posix::pthread_cond_timedwait(&cond,&m,&timeout.getTs()); 239 if(cond_res==ETIMEDOUT) 240 { 241 break; 242 } 243 BOOST_ASSERT(!cond_res); 244 } 245 if(is_locked) 246 { 247 return false; 248 } 249 is_locked=true; 250 return true; 251 } 252 public: 253 #endif 254 255 #if defined BOOST_THREAD_USES_DATETIME timed_lock(system_time const & abs_time)256 bool timed_lock(system_time const & abs_time) 257 { 258 const detail::real_platform_timepoint ts(abs_time); 259 #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO 260 detail::platform_duration d(ts - detail::real_platform_clock::now()); 261 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 262 while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) 263 { 264 d = ts - detail::real_platform_clock::now(); 265 if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred 266 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 267 } 268 return true; 269 #else 270 return do_try_lock_until(ts); 271 #endif 272 } 273 #endif 274 #ifdef BOOST_THREAD_USES_CHRONO 275 template <class Rep, class Period> try_lock_for(const chrono::duration<Rep,Period> & rel_time)276 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) 277 { 278 return try_lock_until(chrono::steady_clock::now() + rel_time); 279 } 280 template <class Clock, class Duration> try_lock_until(const chrono::time_point<Clock,Duration> & t)281 bool try_lock_until(const chrono::time_point<Clock, Duration>& t) 282 { 283 typedef typename common_type<Duration, typename Clock::duration>::type common_duration; 284 common_duration d(t - Clock::now()); 285 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); 286 while ( ! try_lock_until(detail::internal_chrono_clock::now() + d)) 287 { 288 d = t - Clock::now(); 289 if ( d <= common_duration::zero() ) return false; // timeout occurred 290 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); 291 } 292 return true; 293 } 294 template <class Duration> try_lock_until(const chrono::time_point<detail::internal_chrono_clock,Duration> & t)295 bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t) 296 { 297 detail::internal_platform_timepoint ts(t); 298 return do_try_lock_until(ts); 299 } 300 #endif 301 302 #define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE 303 typedef pthread_mutex_t* native_handle_type; native_handle()304 native_handle_type native_handle() 305 { 306 return &m; 307 } 308 309 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS 310 typedef unique_lock<timed_mutex> scoped_timed_lock; 311 typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock; 312 typedef scoped_timed_lock scoped_lock; 313 #endif 314 }; 315 } 316 317 #include <boost/config/abi_suffix.hpp> 318 319 320 #endif 321