Line data Source code
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 : 46 428531 : mutex() 47 428531 : { 48 428531 : int const res=posix::pthread_mutex_init(&m); 49 428531 : if(res) 50 : { 51 0 : boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init")); 52 : } 53 428531 : } 54 428603 : ~mutex() 55 428603 : { 56 857206 : BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); 57 428603 : } 58 : 59 715374 : void lock() BOOST_THREAD_ACQUIRE() 60 : { 61 715374 : int res = posix::pthread_mutex_lock(&m); 62 715374 : if (res) 63 : { 64 0 : boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); 65 : } 66 715374 : } 67 : 68 716250 : void unlock() BOOST_THREAD_RELEASE() 69 : { 70 1432500 : BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); 71 716250 : } 72 : 73 0 : bool try_lock() BOOST_THREAD_TRY_ACQUIRE(true) 74 : { 75 0 : int res = posix::pthread_mutex_trylock(&m); 76 0 : if (res==EBUSY) 77 : { 78 : return false; 79 : } 80 : 81 0 : return !res; 82 : } 83 : 84 : #define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE 85 : typedef pthread_mutex_t* native_handle_type; 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) 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 : } 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> 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 : } 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 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 : 177 : void unlock() 178 : { 179 : BOOST_VERIFY(!posix::pthread_mutex_unlock(&m)); 180 : } 181 : 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: 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 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> 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> 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> 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; 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