File indexing completed on 2025-02-22 10:29:21
0001 #ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
0002 #define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
0003
0004
0005
0006
0007
0008
0009 #include <pthread.h>
0010 #include <boost/throw_exception.hpp>
0011 #include <boost/thread/exceptions.hpp>
0012 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
0013 #include <boost/thread/lock_types.hpp>
0014 #endif
0015 #include <boost/thread/thread_time.hpp>
0016 #include <boost/assert.hpp>
0017 #ifndef _WIN32
0018 #include <unistd.h>
0019 #endif
0020 #include <boost/date_time/posix_time/conversion.hpp>
0021 #include <errno.h>
0022 #include <boost/thread/detail/platform_time.hpp>
0023 #include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
0024 #include <boost/thread/pthread/pthread_helpers.hpp>
0025 #ifdef BOOST_THREAD_USES_CHRONO
0026 #include <boost/chrono/system_clocks.hpp>
0027 #include <boost/chrono/ceil.hpp>
0028 #endif
0029 #include <boost/thread/detail/delete.hpp>
0030
0031
0032 #if defined BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE \
0033 || defined __ANDROID__
0034 #define BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE
0035 #endif
0036
0037 #if defined BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE && defined BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
0038 #define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
0039 #endif
0040
0041 #include <boost/config/abi_prefix.hpp>
0042
0043 namespace boost
0044 {
0045 class recursive_mutex
0046 {
0047 private:
0048 pthread_mutex_t m;
0049 #ifndef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE
0050 pthread_cond_t cond;
0051 bool is_locked;
0052 pthread_t owner;
0053 unsigned count;
0054 #endif
0055 public:
0056 BOOST_THREAD_NO_COPYABLE(recursive_mutex)
0057 recursive_mutex()
0058 {
0059 #ifdef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE
0060 pthread_mutexattr_t attr;
0061
0062 int const init_attr_res=pthread_mutexattr_init(&attr);
0063 if(init_attr_res)
0064 {
0065 boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_init"));
0066 }
0067 int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
0068 if(set_attr_res)
0069 {
0070 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
0071 boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_settype"));
0072 }
0073
0074 int const res=posix::pthread_mutex_init(&m,&attr);
0075 if(res)
0076 {
0077 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
0078 boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init"));
0079 }
0080 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
0081 #else
0082 int const res=posix::pthread_mutex_init(&m);
0083 if(res)
0084 {
0085 boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init"));
0086 }
0087 int const res2=posix::pthread_cond_init(&cond);
0088 if(res2)
0089 {
0090 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
0091 boost::throw_exception(thread_resource_error(res2, "boost:: recursive_mutex constructor failed in pthread_cond_init"));
0092 }
0093 is_locked=false;
0094 count=0;
0095 #endif
0096 }
0097 ~recursive_mutex()
0098 {
0099 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
0100 #ifndef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE
0101 BOOST_VERIFY(!posix::pthread_cond_destroy(&cond));
0102 #endif
0103 }
0104
0105 #ifdef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE
0106 void lock()
0107 {
0108 BOOST_VERIFY(!posix::pthread_mutex_lock(&m));
0109 }
0110
0111 void unlock()
0112 {
0113 BOOST_VERIFY(!posix::pthread_mutex_unlock(&m));
0114 }
0115
0116 bool try_lock() BOOST_NOEXCEPT
0117 {
0118 int const res=posix::pthread_mutex_trylock(&m);
0119 BOOST_ASSERT(!res || res==EBUSY);
0120 return !res;
0121 }
0122 #define BOOST_THREAD_DEFINES_RECURSIVE_MUTEX_NATIVE_HANDLE
0123 typedef pthread_mutex_t* native_handle_type;
0124 native_handle_type native_handle()
0125 {
0126 return &m;
0127 }
0128
0129 #else
0130 void lock()
0131 {
0132 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
0133 if(is_locked && pthread_equal(owner,pthread_self()))
0134 {
0135 ++count;
0136 return;
0137 }
0138
0139 while(is_locked)
0140 {
0141 BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m));
0142 }
0143 is_locked=true;
0144 ++count;
0145 owner=pthread_self();
0146 }
0147
0148 void unlock()
0149 {
0150 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
0151 if(!--count)
0152 {
0153 is_locked=false;
0154 }
0155 BOOST_VERIFY(!posix::pthread_cond_signal(&cond));
0156 }
0157
0158 bool try_lock()
0159 {
0160 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
0161 if(is_locked && !pthread_equal(owner,pthread_self()))
0162 {
0163 return false;
0164 }
0165 is_locked=true;
0166 ++count;
0167 owner=pthread_self();
0168 return true;
0169 }
0170
0171 #endif
0172
0173 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
0174 typedef unique_lock<recursive_mutex> scoped_lock;
0175 typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock;
0176 #endif
0177 };
0178
0179 typedef recursive_mutex recursive_try_mutex;
0180
0181 class recursive_timed_mutex
0182 {
0183 private:
0184 pthread_mutex_t m;
0185 #ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
0186 pthread_cond_t cond;
0187 bool is_locked;
0188 pthread_t owner;
0189 unsigned count;
0190 #endif
0191 public:
0192 BOOST_THREAD_NO_COPYABLE(recursive_timed_mutex)
0193 recursive_timed_mutex()
0194 {
0195 #ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
0196 pthread_mutexattr_t attr;
0197
0198 int const init_attr_res=pthread_mutexattr_init(&attr);
0199 if(init_attr_res)
0200 {
0201 boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_init"));
0202 }
0203 int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
0204 if(set_attr_res)
0205 {
0206 boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_settype"));
0207 }
0208
0209 int const res=posix::pthread_mutex_init(&m,&attr);
0210 if(res)
0211 {
0212 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
0213 boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init"));
0214 }
0215 BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
0216 #else
0217 int const res=posix::pthread_mutex_init(&m);
0218 if(res)
0219 {
0220 boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init"));
0221 }
0222 int const res2=posix::pthread_cond_init(&cond);
0223 if(res2)
0224 {
0225 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
0226 boost::throw_exception(thread_resource_error(res2, "boost:: recursive_timed_mutex constructor failed in pthread_cond_init"));
0227 }
0228 is_locked=false;
0229 count=0;
0230 #endif
0231 }
0232 ~recursive_timed_mutex()
0233 {
0234 BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
0235 #ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
0236 BOOST_VERIFY(!posix::pthread_cond_destroy(&cond));
0237 #endif
0238 }
0239
0240 #if defined BOOST_THREAD_USES_DATETIME
0241 template<typename TimeDuration>
0242 bool timed_lock(TimeDuration const & relative_time)
0243 {
0244 if (relative_time.is_pos_infinity())
0245 {
0246 lock();
0247 return true;
0248 }
0249 if (relative_time.is_special())
0250 {
0251 return true;
0252 }
0253 detail::platform_duration d(relative_time);
0254 #if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
0255 const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
0256 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0257 while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
0258 {
0259 d = ts - detail::mono_platform_clock::now();
0260 if ( d <= detail::platform_duration::zero() ) return false;
0261 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0262 }
0263 return true;
0264 #else
0265 return do_try_lock_until(detail::internal_platform_clock::now() + d);
0266 #endif
0267 }
0268 #endif
0269
0270 #ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
0271 void lock()
0272 {
0273 BOOST_VERIFY(!posix::pthread_mutex_lock(&m));
0274 }
0275
0276 void unlock()
0277 {
0278 BOOST_VERIFY(!posix::pthread_mutex_unlock(&m));
0279 }
0280
0281 bool try_lock()
0282 {
0283 int const res=posix::pthread_mutex_trylock(&m);
0284 BOOST_ASSERT(!res || res==EBUSY);
0285 return !res;
0286 }
0287 private:
0288 bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
0289 {
0290 int const res=pthread_mutex_timedlock(&m,&timeout.getTs());
0291 BOOST_ASSERT(!res || res==ETIMEDOUT);
0292 return !res;
0293 }
0294
0295 public:
0296
0297 #else
0298 void lock()
0299 {
0300 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
0301 if(is_locked && pthread_equal(owner,pthread_self()))
0302 {
0303 ++count;
0304 return;
0305 }
0306
0307 while(is_locked)
0308 {
0309 BOOST_VERIFY(!posix::pthread_cond_wait(&cond,&m));
0310 }
0311 is_locked=true;
0312 ++count;
0313 owner=pthread_self();
0314 }
0315
0316 void unlock()
0317 {
0318 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
0319 if(!--count)
0320 {
0321 is_locked=false;
0322 }
0323 BOOST_VERIFY(!posix::pthread_cond_signal(&cond));
0324 }
0325
0326 bool try_lock() BOOST_NOEXCEPT
0327 {
0328 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
0329 if(is_locked && !pthread_equal(owner,pthread_self()))
0330 {
0331 return false;
0332 }
0333 is_locked=true;
0334 ++count;
0335 owner=pthread_self();
0336 return true;
0337 }
0338
0339 private:
0340 bool do_try_lock_until(detail::internal_platform_timepoint const &timeout)
0341 {
0342 boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
0343 if(is_locked && pthread_equal(owner,pthread_self()))
0344 {
0345 ++count;
0346 return true;
0347 }
0348 while(is_locked)
0349 {
0350 int const cond_res=posix::pthread_cond_timedwait(&cond,&m,&timeout.getTs());
0351 if(cond_res==ETIMEDOUT)
0352 {
0353 break;
0354 }
0355 BOOST_ASSERT(!cond_res);
0356 }
0357 if(is_locked)
0358 {
0359 return false;
0360 }
0361 is_locked=true;
0362 ++count;
0363 owner=pthread_self();
0364 return true;
0365 }
0366 public:
0367
0368 #endif
0369
0370 #if defined BOOST_THREAD_USES_DATETIME
0371 bool timed_lock(system_time const & abs_time)
0372 {
0373 const detail::real_platform_timepoint ts(abs_time);
0374 #if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
0375 detail::platform_duration d(ts - detail::real_platform_clock::now());
0376 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0377 while ( ! do_try_lock_until(detail::internal_platform_clock::now() + d) )
0378 {
0379 d = ts - detail::real_platform_clock::now();
0380 if ( d <= detail::platform_duration::zero() ) return false;
0381 d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
0382 }
0383 return true;
0384 #else
0385 return do_try_lock_until(ts);
0386 #endif
0387 }
0388 #endif
0389 #ifdef BOOST_THREAD_USES_CHRONO
0390 template <class Rep, class Period>
0391 bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
0392 {
0393 return try_lock_until(chrono::steady_clock::now() + rel_time);
0394 }
0395 template <class Clock, class Duration>
0396 bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
0397 {
0398 typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
0399 common_duration d(t - Clock::now());
0400 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
0401 while ( ! try_lock_until(detail::internal_chrono_clock::now() + d))
0402 {
0403 d = t - Clock::now();
0404 if ( d <= common_duration::zero() ) return false;
0405 d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
0406 }
0407 return true;
0408
0409 }
0410 template <class Duration>
0411 bool try_lock_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
0412 {
0413 detail::internal_platform_timepoint ts(t);
0414 return do_try_lock_until(ts);
0415 }
0416 #endif
0417
0418 #define BOOST_THREAD_DEFINES_RECURSIVE_TIMED_MUTEX_NATIVE_HANDLE
0419 typedef pthread_mutex_t* native_handle_type;
0420 native_handle_type native_handle()
0421 {
0422 return &m;
0423 }
0424
0425 #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
0426 typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
0427 typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock;
0428 typedef scoped_timed_lock scoped_lock;
0429 #endif
0430 };
0431
0432 }
0433
0434 #include <boost/config/abi_suffix.hpp>
0435
0436 #endif