1 #ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP 2 #define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP 3 // (C) Copyright 2007-8 Anthony Williams 4 // (C) Copyright 2011-2012 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 <pthread.h> 10 #include <boost/throw_exception.hpp> 11 #include <boost/thread/exceptions.hpp> 12 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS 13 #include <boost/thread/lock_types.hpp> 14 #endif 15 #include <boost/thread/thread_time.hpp> 16 #include <boost/assert.hpp> 17 #ifndef _WIN32 18 #include <unistd.h> 19 #endif 20 #include <boost/date_time/posix_time/conversion.hpp> 21 #include <errno.h> 22 #include <boost/thread/detail/platform_time.hpp> 23 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> 24 #include <boost/thread/pthread/pthread_helpers.hpp> 25 #ifdef BOOST_THREAD_USES_CHRONO 26 #include <boost/chrono/system_clocks.hpp> 27 #include <boost/chrono/ceil.hpp> 28 #endif 29 #include <boost/thread/detail/delete.hpp> 30 31 32 #if defined BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE \ 33 || defined __ANDROID__ 34 #define BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE 35 #endif 36 37 #if defined BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE && defined BOOST_THREAD_USES_PTHREAD_TIMEDLOCK 38 #define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK 39 #endif 40 41 #include <boost/config/abi_prefix.hpp> 42 43 namespace boost 44 { 45 class recursive_mutex 46 { 47 private: 48 pthread_mutex_t m; 49 #ifndef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE 50 pthread_cond_t cond; 51 bool is_locked; 52 pthread_t owner; 53 unsigned count; 54 #endif 55 public: 56 BOOST_THREAD_NO_COPYABLE(recursive_mutex) recursive_mutex()57 recursive_mutex() 58 { 59 #ifdef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE 60 pthread_mutexattr_t attr; 61 62 int const init_attr_res=pthread_mutexattr_init(&attr); 63 if(init_attr_res) 64 { 65 boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_init")); 66 } 67 int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); 68 if(set_attr_res) 69 { 70 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); 71 boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_settype")); 72 } 73 74 int const res=posix::pthread_mutex_init(&m,&attr); 75 if(res) 76 { 77 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); 78 boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init")); 79 } 80 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); 81 #else 82 int const res=posix::pthread_mutex_init(&m); 83 if(res) 84 { 85 boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init")); 86 } 87 int const res2=posix::pthread_cond_init(&cond); 88 if(res2) 89 { 90 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); 91 boost::throw_exception(thread_resource_error(res2, "boost:: recursive_mutex constructor failed in pthread_cond_init")); 92 } 93 is_locked=false; 94 count=0; 95 #endif 96 } ~recursive_mutex()97 ~recursive_mutex() 98 { 99 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); 100 #ifndef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE 101 BOOST_VERIFY(!posix::pthread_cond_destroy(&cond)); 102 #endif 103 } 104 105 #ifdef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE lock()106 void lock() 107 { 108 BOOST_VERIFY(!posix::pthread_mutex_lock(&m)); 109 } 110 unlock()111 void unlock() 112 { 113 BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); 114 } 115 try_lock()116 bool try_lock() BOOST_NOEXCEPT 117 { 118 int const res=posix::pthread_mutex_trylock(&m); 119 BOOST_ASSERT(!res || res==EBUSY); 120 return !res; 121 } 122 #define BOOST_THREAD_DEFINES_RECURSIVE_MUTEX_NATIVE_HANDLE 123 typedef pthread_mutex_t* native_handle_type; native_handle()124 native_handle_type native_handle() 125 { 126 return &m; 127 } 128 129 #else lock()130 void lock() 131 { 132 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 133 if(is_locked && pthread_equal(owner,pthread_self())) 134 { 135 ++count; 136 return; 137 } 138 139 while(is_locked) 140 { 141 BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m)); 142 } 143 is_locked=true; 144 ++count; 145 owner=pthread_self(); 146 } 147 unlock()148 void unlock() 149 { 150 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 151 if(!--count) 152 { 153 is_locked=false; 154 } 155 BOOST_VERIFY(!posix::pthread_cond_signal(&cond)); 156 } 157 try_lock()158 bool try_lock() 159 { 160 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 161 if(is_locked && !pthread_equal(owner,pthread_self())) 162 { 163 return false; 164 } 165 is_locked=true; 166 ++count; 167 owner=pthread_self(); 168 return true; 169 } 170 171 #endif 172 173 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS 174 typedef unique_lock<recursive_mutex> scoped_lock; 175 typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock; 176 #endif 177 }; 178 179 typedef recursive_mutex recursive_try_mutex; 180 181 class recursive_timed_mutex 182 { 183 private: 184 pthread_mutex_t m; 185 #ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK 186 pthread_cond_t cond; 187 bool is_locked; 188 pthread_t owner; 189 unsigned count; 190 #endif 191 public: 192 BOOST_THREAD_NO_COPYABLE(recursive_timed_mutex) recursive_timed_mutex()193 recursive_timed_mutex() 194 { 195 #ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK 196 pthread_mutexattr_t attr; 197 198 int const init_attr_res=pthread_mutexattr_init(&attr); 199 if(init_attr_res) 200 { 201 boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_init")); 202 } 203 int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); 204 if(set_attr_res) 205 { 206 boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_settype")); 207 } 208 209 int const res=posix::pthread_mutex_init(&m,&attr); 210 if(res) 211 { 212 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); 213 boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init")); 214 } 215 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); 216 #else 217 int const res=posix::pthread_mutex_init(&m); 218 if(res) 219 { 220 boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init")); 221 } 222 int const res2=posix::pthread_cond_init(&cond); 223 if(res2) 224 { 225 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); 226 boost::throw_exception(thread_resource_error(res2, "boost:: recursive_timed_mutex constructor failed in pthread_cond_init")); 227 } 228 is_locked=false; 229 count=0; 230 #endif 231 } ~recursive_timed_mutex()232 ~recursive_timed_mutex() 233 { 234 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); 235 #ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK 236 BOOST_VERIFY(!posix::pthread_cond_destroy(&cond)); 237 #endif 238 } 239 240 #if defined BOOST_THREAD_USES_DATETIME 241 template<typename TimeDuration> timed_lock(TimeDuration const & relative_time)242 bool timed_lock(TimeDuration const & relative_time) 243 { 244 if (relative_time.is_pos_infinity()) 245 { 246 lock(); 247 return true; 248 } 249 if (relative_time.is_special()) 250 { 251 return true; 252 } 253 detail::platform_duration d(relative_time); 254 #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO) 255 const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d); 256 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 257 while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) 258 { 259 d = ts - detail::mono_platform_clock::now(); 260 if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred 261 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 262 } 263 return true; 264 #else 265 return do_try_lock_until(detail::internal_platform_clock::now() + d); 266 #endif 267 } 268 #endif 269 270 #ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK lock()271 void lock() 272 { 273 BOOST_VERIFY(!posix::pthread_mutex_lock(&m)); 274 } 275 unlock()276 void unlock() 277 { 278 BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); 279 } 280 try_lock()281 bool try_lock() 282 { 283 int const res=posix::pthread_mutex_trylock(&m); 284 BOOST_ASSERT(!res || res==EBUSY); 285 return !res; 286 } 287 private: do_try_lock_until(detail::internal_platform_timepoint const & timeout)288 bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) 289 { 290 int const res=pthread_mutex_timedlock(&m,&timeout.getTs()); 291 BOOST_ASSERT(!res || res==ETIMEDOUT); 292 return !res; 293 } 294 295 public: 296 297 #else 298 void lock() 299 { 300 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 301 if(is_locked && pthread_equal(owner,pthread_self())) 302 { 303 ++count; 304 return; 305 } 306 307 while(is_locked) 308 { 309 BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m)); 310 } 311 is_locked=true; 312 ++count; 313 owner=pthread_self(); 314 } 315 316 void unlock() 317 { 318 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 319 if(!--count) 320 { 321 is_locked=false; 322 } 323 BOOST_VERIFY(!posix::pthread_cond_signal(&cond)); 324 } 325 326 bool try_lock() BOOST_NOEXCEPT 327 { 328 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 329 if(is_locked && !pthread_equal(owner,pthread_self())) 330 { 331 return false; 332 } 333 is_locked=true; 334 ++count; 335 owner=pthread_self(); 336 return true; 337 } 338 339 private: 340 bool do_try_lock_until(detail::internal_platform_timepoint const &timeout) 341 { 342 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 343 if(is_locked && pthread_equal(owner,pthread_self())) 344 { 345 ++count; 346 return true; 347 } 348 while(is_locked) 349 { 350 int const cond_res=posix::pthread_cond_timedwait(&cond,&m,&timeout.getTs()); 351 if(cond_res==ETIMEDOUT) 352 { 353 break; 354 } 355 BOOST_ASSERT(!cond_res); 356 } 357 if(is_locked) 358 { 359 return false; 360 } 361 is_locked=true; 362 ++count; 363 owner=pthread_self(); 364 return true; 365 } 366 public: 367 368 #endif 369 370 #if defined BOOST_THREAD_USES_DATETIME timed_lock(system_time const & abs_time)371 bool timed_lock(system_time const & abs_time) 372 { 373 const detail::real_platform_timepoint ts(abs_time); 374 #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO 375 detail::platform_duration d(ts - detail::real_platform_clock::now()); 376 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 377 while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) ) 378 { 379 d = ts - detail::real_platform_clock::now(); 380 if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred 381 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)); 382 } 383 return true; 384 #else 385 return do_try_lock_until(ts); 386 #endif 387 } 388 #endif 389 #ifdef BOOST_THREAD_USES_CHRONO 390 template <class Rep, class Period> try_lock_for(const chrono::duration<Rep,Period> & rel_time)391 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) 392 { 393 return try_lock_until(chrono::steady_clock::now() + rel_time); 394 } 395 template <class Clock, class Duration> try_lock_until(const chrono::time_point<Clock,Duration> & t)396 bool try_lock_until(const chrono::time_point<Clock, Duration>& t) 397 { 398 typedef typename common_type<Duration, typename Clock::duration>::type common_duration; 399 common_duration d(t - Clock::now()); 400 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); 401 while ( ! try_lock_until(detail::internal_chrono_clock::now() + d)) 402 { 403 d = t - Clock::now(); 404 if ( d <= common_duration::zero() ) return false; // timeout occurred 405 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS))); 406 } 407 return true; 408 409 } 410 template <class Duration> try_lock_until(const chrono::time_point<detail::internal_chrono_clock,Duration> & t)411 bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t) 412 { 413 detail::internal_platform_timepoint ts(t); 414 return do_try_lock_until(ts); 415 } 416 #endif 417 418 #define BOOST_THREAD_DEFINES_RECURSIVE_TIMED_MUTEX_NATIVE_HANDLE 419 typedef pthread_mutex_t* native_handle_type; native_handle()420 native_handle_type native_handle() 421 { 422 return &m; 423 } 424 425 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS 426 typedef unique_lock<recursive_timed_mutex> scoped_timed_lock; 427 typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock; 428 typedef scoped_timed_lock scoped_lock; 429 #endif 430 }; 431 432 } 433 434 #include <boost/config/abi_suffix.hpp> 435 436 #endif 437