Chris@16: #ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP Chris@16: #define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP Chris@16: // (C) Copyright 2007-8 Anthony Williams Chris@16: // (C) Copyright 2011-2012 Vicente J. Botet Escriba Chris@16: // Distributed under the Boost Software License, Version 1.0. (See Chris@16: // accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS Chris@16: #include Chris@16: #endif Chris@16: #include Chris@16: #include Chris@16: #ifndef _WIN32 Chris@16: #include Chris@16: #endif Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #ifdef BOOST_THREAD_USES_CHRONO Chris@16: #include Chris@16: #include Chris@16: #endif Chris@16: #include Chris@16: Chris@101: #if (defined _POSIX_TIMEOUTS && (_POSIX_TIMEOUTS-0)>=200112L) \ Chris@101: || (defined __ANDROID__ && defined __ANDROID_API__ && __ANDROID_API__ >= 21) Chris@16: #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK Chris@16: #define BOOST_PTHREAD_HAS_TIMEDLOCK Chris@16: #endif Chris@16: #endif Chris@101: Chris@101: #if defined BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE \ Chris@101: || defined __ANDROID__ Chris@101: #define BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE Chris@16: #endif Chris@16: Chris@101: #if defined BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE && defined BOOST_PTHREAD_HAS_TIMEDLOCK Chris@16: #define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK Chris@16: #endif Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: class recursive_mutex Chris@16: { Chris@16: private: Chris@16: pthread_mutex_t m; Chris@101: #ifndef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE Chris@16: pthread_cond_t cond; Chris@16: bool is_locked; Chris@16: pthread_t owner; Chris@16: unsigned count; Chris@16: #endif Chris@16: public: Chris@16: BOOST_THREAD_NO_COPYABLE(recursive_mutex) Chris@16: recursive_mutex() Chris@16: { Chris@101: #ifdef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE Chris@16: pthread_mutexattr_t attr; Chris@16: Chris@16: int const init_attr_res=pthread_mutexattr_init(&attr); Chris@16: if(init_attr_res) Chris@16: { Chris@16: boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_init")); Chris@16: } Chris@16: int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); Chris@16: if(set_attr_res) Chris@16: { Chris@16: BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); Chris@16: boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_settype")); Chris@16: } Chris@16: Chris@16: int const res=pthread_mutex_init(&m,&attr); Chris@16: if(res) Chris@16: { Chris@16: BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); Chris@16: boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init")); Chris@16: } Chris@16: BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); Chris@16: #else Chris@16: int const res=pthread_mutex_init(&m,NULL); Chris@16: if(res) Chris@16: { Chris@16: boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init")); Chris@16: } Chris@16: int const res2=pthread_cond_init(&cond,NULL); Chris@16: if(res2) Chris@16: { Chris@16: BOOST_VERIFY(!pthread_mutex_destroy(&m)); Chris@16: boost::throw_exception(thread_resource_error(res2, "boost:: recursive_mutex constructor failed in pthread_cond_init")); Chris@16: } Chris@16: is_locked=false; Chris@16: count=0; Chris@16: #endif Chris@16: } Chris@16: ~recursive_mutex() Chris@16: { Chris@16: BOOST_VERIFY(!pthread_mutex_destroy(&m)); Chris@101: #ifndef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE Chris@16: BOOST_VERIFY(!pthread_cond_destroy(&cond)); Chris@16: #endif Chris@16: } Chris@16: Chris@101: #ifdef BOOST_THREAD_HAS_PTHREAD_MUTEXATTR_SETTYPE Chris@16: void lock() Chris@16: { Chris@16: BOOST_VERIFY(!pthread_mutex_lock(&m)); Chris@16: } Chris@16: Chris@16: void unlock() Chris@16: { Chris@16: BOOST_VERIFY(!pthread_mutex_unlock(&m)); Chris@16: } Chris@16: Chris@16: bool try_lock() BOOST_NOEXCEPT Chris@16: { Chris@16: int const res=pthread_mutex_trylock(&m); Chris@16: BOOST_ASSERT(!res || res==EBUSY); Chris@16: return !res; Chris@16: } Chris@16: #define BOOST_THREAD_DEFINES_RECURSIVE_MUTEX_NATIVE_HANDLE Chris@16: typedef pthread_mutex_t* native_handle_type; Chris@16: native_handle_type native_handle() Chris@16: { Chris@16: return &m; Chris@16: } Chris@16: Chris@16: #else Chris@16: void lock() Chris@16: { Chris@16: boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); Chris@16: if(is_locked && pthread_equal(owner,pthread_self())) Chris@16: { Chris@16: ++count; Chris@16: return; Chris@16: } Chris@16: Chris@16: while(is_locked) Chris@16: { Chris@16: BOOST_VERIFY(!pthread_cond_wait(&cond,&m)); Chris@16: } Chris@16: is_locked=true; Chris@16: ++count; Chris@16: owner=pthread_self(); Chris@16: } Chris@16: Chris@16: void unlock() Chris@16: { Chris@16: boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); Chris@16: if(!--count) Chris@16: { Chris@16: is_locked=false; Chris@16: } Chris@16: BOOST_VERIFY(!pthread_cond_signal(&cond)); Chris@16: } Chris@16: Chris@16: bool try_lock() Chris@16: { Chris@16: boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); Chris@16: if(is_locked && !pthread_equal(owner,pthread_self())) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: is_locked=true; Chris@16: ++count; Chris@16: owner=pthread_self(); Chris@16: return true; Chris@16: } Chris@16: Chris@16: #endif Chris@16: Chris@16: #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS Chris@16: typedef unique_lock scoped_lock; Chris@16: typedef detail::try_lock_wrapper scoped_try_lock; Chris@16: #endif Chris@16: }; Chris@16: Chris@16: typedef recursive_mutex recursive_try_mutex; Chris@16: Chris@16: class recursive_timed_mutex Chris@16: { Chris@16: private: Chris@16: pthread_mutex_t m; Chris@16: #ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK Chris@16: pthread_cond_t cond; Chris@16: bool is_locked; Chris@16: pthread_t owner; Chris@16: unsigned count; Chris@16: #endif Chris@16: public: Chris@16: BOOST_THREAD_NO_COPYABLE(recursive_timed_mutex) Chris@16: recursive_timed_mutex() Chris@16: { Chris@16: #ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK Chris@16: pthread_mutexattr_t attr; Chris@16: Chris@16: int const init_attr_res=pthread_mutexattr_init(&attr); Chris@16: if(init_attr_res) Chris@16: { Chris@16: boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_init")); Chris@16: } Chris@16: int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE); Chris@16: if(set_attr_res) Chris@16: { Chris@16: boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_settype")); Chris@16: } Chris@16: Chris@16: int const res=pthread_mutex_init(&m,&attr); Chris@16: if(res) Chris@16: { Chris@16: BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); Chris@16: boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init")); Chris@16: } Chris@16: BOOST_VERIFY(!pthread_mutexattr_destroy(&attr)); Chris@16: #else Chris@16: int const res=pthread_mutex_init(&m,NULL); Chris@16: if(res) Chris@16: { Chris@16: boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init")); Chris@16: } Chris@16: int const res2=pthread_cond_init(&cond,NULL); Chris@16: if(res2) Chris@16: { Chris@16: BOOST_VERIFY(!pthread_mutex_destroy(&m)); Chris@16: boost::throw_exception(thread_resource_error(res2, "boost:: recursive_timed_mutex constructor failed in pthread_cond_init")); Chris@16: } Chris@16: is_locked=false; Chris@16: count=0; Chris@16: #endif Chris@16: } Chris@16: ~recursive_timed_mutex() Chris@16: { Chris@16: BOOST_VERIFY(!pthread_mutex_destroy(&m)); Chris@16: #ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK Chris@16: BOOST_VERIFY(!pthread_cond_destroy(&cond)); Chris@16: #endif Chris@16: } Chris@16: Chris@16: #if defined BOOST_THREAD_USES_DATETIME Chris@16: template Chris@16: bool timed_lock(TimeDuration const & relative_time) Chris@16: { Chris@16: return timed_lock(get_system_time()+relative_time); Chris@16: } Chris@16: #endif Chris@16: Chris@16: #ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK Chris@16: void lock() Chris@16: { Chris@16: BOOST_VERIFY(!pthread_mutex_lock(&m)); Chris@16: } Chris@16: Chris@16: void unlock() Chris@16: { Chris@16: BOOST_VERIFY(!pthread_mutex_unlock(&m)); Chris@16: } Chris@16: Chris@16: bool try_lock() Chris@16: { Chris@16: int const res=pthread_mutex_trylock(&m); Chris@16: BOOST_ASSERT(!res || res==EBUSY); Chris@16: return !res; Chris@16: } Chris@16: private: Chris@16: bool do_try_lock_until(struct timespec const &timeout) Chris@16: { Chris@16: int const res=pthread_mutex_timedlock(&m,&timeout); Chris@16: BOOST_ASSERT(!res || res==ETIMEDOUT); Chris@16: return !res; Chris@16: } Chris@16: Chris@16: public: Chris@16: Chris@16: #else Chris@16: void lock() Chris@16: { Chris@16: boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); Chris@16: if(is_locked && pthread_equal(owner,pthread_self())) Chris@16: { Chris@16: ++count; Chris@16: return; Chris@16: } Chris@16: Chris@16: while(is_locked) Chris@16: { Chris@16: BOOST_VERIFY(!pthread_cond_wait(&cond,&m)); Chris@16: } Chris@16: is_locked=true; Chris@16: ++count; Chris@16: owner=pthread_self(); Chris@16: } Chris@16: Chris@16: void unlock() Chris@16: { Chris@16: boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); Chris@16: if(!--count) Chris@16: { Chris@16: is_locked=false; Chris@16: } Chris@16: BOOST_VERIFY(!pthread_cond_signal(&cond)); Chris@16: } Chris@16: Chris@16: bool try_lock() BOOST_NOEXCEPT Chris@16: { Chris@16: boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); Chris@16: if(is_locked && !pthread_equal(owner,pthread_self())) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: is_locked=true; Chris@16: ++count; Chris@16: owner=pthread_self(); Chris@16: return true; Chris@16: } Chris@16: Chris@16: private: Chris@16: bool do_try_lock_until(struct timespec const &timeout) Chris@16: { Chris@16: boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); Chris@16: if(is_locked && pthread_equal(owner,pthread_self())) Chris@16: { Chris@16: ++count; Chris@16: return true; Chris@16: } Chris@16: while(is_locked) Chris@16: { Chris@16: int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout); Chris@16: if(cond_res==ETIMEDOUT) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: BOOST_ASSERT(!cond_res); Chris@16: } Chris@16: is_locked=true; Chris@16: ++count; Chris@16: owner=pthread_self(); Chris@16: return true; Chris@16: } Chris@16: public: Chris@16: Chris@16: #endif Chris@16: Chris@16: #if defined BOOST_THREAD_USES_DATETIME Chris@16: bool timed_lock(system_time const & abs_time) Chris@16: { Chris@16: struct timespec const ts=detail::to_timespec(abs_time); Chris@16: return do_try_lock_until(ts); Chris@16: } Chris@16: #endif Chris@16: #ifdef BOOST_THREAD_USES_CHRONO Chris@16: template Chris@16: bool try_lock_for(const chrono::duration& rel_time) Chris@16: { Chris@16: return try_lock_until(chrono::steady_clock::now() + rel_time); Chris@16: } Chris@16: template Chris@16: bool try_lock_until(const chrono::time_point& t) Chris@16: { Chris@16: using namespace chrono; Chris@16: system_clock::time_point s_now = system_clock::now(); Chris@16: typename Clock::time_point c_now = Clock::now(); Chris@16: return try_lock_until(s_now + ceil(t - c_now)); Chris@16: } Chris@16: template Chris@16: bool try_lock_until(const chrono::time_point& t) Chris@16: { Chris@16: using namespace chrono; Chris@16: typedef time_point nano_sys_tmpt; Chris@16: return try_lock_until(nano_sys_tmpt(ceil(t.time_since_epoch()))); Chris@16: } Chris@16: bool try_lock_until(const chrono::time_point& tp) Chris@16: { Chris@16: //using namespace chrono; Chris@16: chrono::nanoseconds d = tp.time_since_epoch(); Chris@16: timespec ts = boost::detail::to_timespec(d); Chris@16: return do_try_lock_until(ts); Chris@16: } Chris@16: #endif Chris@16: Chris@16: #define BOOST_THREAD_DEFINES_RECURSIVE_TIMED_MUTEX_NATIVE_HANDLE Chris@16: typedef pthread_mutex_t* native_handle_type; Chris@16: native_handle_type native_handle() Chris@16: { Chris@16: return &m; Chris@16: } Chris@16: Chris@16: #if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS Chris@16: typedef unique_lock scoped_timed_lock; Chris@16: typedef detail::try_lock_wrapper scoped_try_lock; Chris@16: typedef scoped_timed_lock scoped_lock; Chris@16: #endif Chris@16: }; Chris@16: Chris@16: } Chris@16: Chris@16: #include Chris@16: Chris@16: #endif