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 #include <boost/thread/xtime.hpp> 20 #include <boost/assert.hpp> 21 #include <errno.h> 22 #include <boost/thread/pthread/timespec.hpp> 23 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp> 24 #ifdef BOOST_THREAD_USES_CHRONO 25 #include <boost/chrono/system_clocks.hpp> 26 #include <boost/chrono/ceil.hpp> 27 #endif 28 #include <boost/thread/detail/delete.hpp> 29 30 #if (defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS-0)>=200112L) \ 31 || (defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21) 32 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK 33 #define BOOST_PTHREAD_HAS_TIMEDLOCK 34 #endif 35 #endif 36 37 38 #include <boost/config/abi_prefix.hpp> 39 40 #ifndef BOOST_THREAD_HAS_NO_EINTR_BUG 41 #define BOOST_THREAD_HAS_EINTR_BUG 42 #endif 43 44 namespace boost 45 { 46 namespace posix { 47 #ifdef BOOST_THREAD_HAS_EINTR_BUG pthread_mutex_destroy(pthread_mutex_t * m)48 BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m) 49 { 50 int ret; 51 do 52 { 53 ret = ::pthread_mutex_destroy(m); 54 } while (ret == EINTR); 55 return ret; 56 } pthread_mutex_lock(pthread_mutex_t * m)57 BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m) 58 { 59 int ret; 60 do 61 { 62 ret = ::pthread_mutex_lock(m); 63 } while (ret == EINTR); 64 return ret; 65 } pthread_mutex_unlock(pthread_mutex_t * m)66 BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m) 67 { 68 int ret; 69 do 70 { 71 ret = ::pthread_mutex_unlock(m); 72 } while (ret == EINTR); 73 return ret; 74 } 75 #else 76 BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m) 77 { 78 return ::pthread_mutex_destroy(m); 79 } 80 BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m) 81 { 82 return ::pthread_mutex_lock(m); 83 } 84 BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m) 85 { 86 return ::pthread_mutex_unlock(m); 87 } 88 89 #endif 90 91 } 92 class mutex 93 { 94 private: 95 pthread_mutex_t m; 96 public: 97 BOOST_THREAD_NO_COPYABLE(mutex) 98 mutex()99 mutex() 100 { 101 int const res=pthread_mutex_init(&m,NULL); 102 if(res) 103 { 104 boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init")); 105 } 106 } ~mutex()107 ~mutex() 108 { 109 int const res = posix::pthread_mutex_destroy(&m); 110 boost::ignore_unused(res); 111 BOOST_ASSERT(!res); 112 } 113 lock()114 void lock() 115 { 116 int res = posix::pthread_mutex_lock(&m); 117 if (res) 118 { 119 boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); 120 } 121 } 122 unlock()123 void unlock() 124 { 125 int res = posix::pthread_mutex_unlock(&m); 126 (void)res; 127 BOOST_ASSERT(res == 0); 128 // if (res) 129 // { 130 // boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); 131 // } 132 } 133 try_lock()134 bool try_lock() 135 { 136 int res; 137 do 138 { 139 res = pthread_mutex_trylock(&m); 140 } while (res == EINTR); 141 if (res==EBUSY) 142 { 143 return false; 144 } 145 146 return !res; 147 } 148 149 #define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE 150 typedef pthread_mutex_t* native_handle_type; native_handle()151 native_handle_type native_handle() 152 { 153 return &m; 154 } 155 156 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS 157 typedef unique_lock<mutex> scoped_lock; 158 typedef detail::try_lock_wrapper<mutex> scoped_try_lock; 159 #endif 160 }; 161 162 typedef mutex try_mutex; 163 164 class timed_mutex 165 { 166 private: 167 pthread_mutex_t m; 168 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK 169 pthread_cond_t cond; 170 bool is_locked; 171 #endif 172 public: 173 BOOST_THREAD_NO_COPYABLE(timed_mutex) timed_mutex()174 timed_mutex() 175 { 176 int const res=pthread_mutex_init(&m,NULL); 177 if(res) 178 { 179 boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init")); 180 } 181 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK 182 int const res2=pthread_cond_init(&cond,NULL); 183 if(res2) 184 { 185 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); 186 //BOOST_VERIFY(!pthread_mutex_destroy(&m)); 187 boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init")); 188 } 189 is_locked=false; 190 #endif 191 } ~timed_mutex()192 ~timed_mutex() 193 { 194 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); 195 #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK 196 BOOST_VERIFY(!pthread_cond_destroy(&cond)); 197 #endif 198 } 199 200 #if defined BOOST_THREAD_USES_DATETIME 201 template<typename TimeDuration> timed_lock(TimeDuration const & relative_time)202 bool timed_lock(TimeDuration const & relative_time) 203 { 204 return timed_lock(get_system_time()+relative_time); 205 } timed_lock(boost::xtime const & absolute_time)206 bool timed_lock(boost::xtime const & absolute_time) 207 { 208 return timed_lock(system_time(absolute_time)); 209 } 210 #endif 211 #ifdef BOOST_PTHREAD_HAS_TIMEDLOCK lock()212 void lock() 213 { 214 int res = posix::pthread_mutex_lock(&m); 215 if (res) 216 { 217 boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); 218 } 219 } 220 unlock()221 void unlock() 222 { 223 int res = posix::pthread_mutex_unlock(&m); 224 (void)res; 225 BOOST_ASSERT(res == 0); 226 // if (res) 227 // { 228 // boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); 229 // } 230 } 231 try_lock()232 bool try_lock() 233 { 234 int res; 235 do 236 { 237 res = pthread_mutex_trylock(&m); 238 } while (res == EINTR); 239 if (res==EBUSY) 240 { 241 return false; 242 } 243 244 return !res; 245 } 246 247 248 private: do_try_lock_until(struct timespec const & timeout)249 bool do_try_lock_until(struct timespec const &timeout) 250 { 251 int const res=pthread_mutex_timedlock(&m,&timeout); 252 BOOST_ASSERT(!res || res==ETIMEDOUT); 253 return !res; 254 } 255 public: 256 257 #else 258 void lock() 259 { 260 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 261 while(is_locked) 262 { 263 BOOST_VERIFY(!pthread_cond_wait(&cond,&m)); 264 } 265 is_locked=true; 266 } 267 268 void unlock() 269 { 270 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 271 is_locked=false; 272 BOOST_VERIFY(!pthread_cond_signal(&cond)); 273 } 274 275 bool try_lock() 276 { 277 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 278 if(is_locked) 279 { 280 return false; 281 } 282 is_locked=true; 283 return true; 284 } 285 286 private: 287 bool do_try_lock_until(struct timespec const &timeout) 288 { 289 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); 290 while(is_locked) 291 { 292 int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout); 293 if(cond_res==ETIMEDOUT) 294 { 295 return false; 296 } 297 BOOST_ASSERT(!cond_res); 298 } 299 is_locked=true; 300 return true; 301 } 302 public: 303 #endif 304 305 #if defined BOOST_THREAD_USES_DATETIME timed_lock(system_time const & abs_time)306 bool timed_lock(system_time const & abs_time) 307 { 308 struct timespec const ts=boost::detail::to_timespec(abs_time); 309 return do_try_lock_until(ts); 310 } 311 #endif 312 #ifdef BOOST_THREAD_USES_CHRONO 313 template <class Rep, class Period> try_lock_for(const chrono::duration<Rep,Period> & rel_time)314 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time) 315 { 316 return try_lock_until(chrono::steady_clock::now() + rel_time); 317 } 318 template <class Clock, class Duration> try_lock_until(const chrono::time_point<Clock,Duration> & t)319 bool try_lock_until(const chrono::time_point<Clock, Duration>& t) 320 { 321 using namespace chrono; 322 system_clock::time_point s_now = system_clock::now(); 323 typename Clock::time_point c_now = Clock::now(); 324 return try_lock_until(s_now + ceil<nanoseconds>(t - c_now)); 325 } 326 template <class Duration> try_lock_until(const chrono::time_point<chrono::system_clock,Duration> & t)327 bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t) 328 { 329 using namespace chrono; 330 typedef time_point<system_clock, nanoseconds> nano_sys_tmpt; 331 return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch()))); 332 } try_lock_until(const chrono::time_point<chrono::system_clock,chrono::nanoseconds> & tp)333 bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp) 334 { 335 //using namespace chrono; 336 chrono::nanoseconds d = tp.time_since_epoch(); 337 timespec ts = boost::detail::to_timespec(d); 338 return do_try_lock_until(ts); 339 } 340 #endif 341 342 #define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE 343 typedef pthread_mutex_t* native_handle_type; native_handle()344 native_handle_type native_handle() 345 { 346 return &m; 347 } 348 349 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS 350 typedef unique_lock<timed_mutex> scoped_timed_lock; 351 typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock; 352 typedef scoped_timed_lock scoped_lock; 353 #endif 354 }; 355 356 } 357 358 #include <boost/config/abi_suffix.hpp> 359 360 361 #endif 362