Chris@16: #ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP Chris@16: #define BOOST_THREAD_PTHREAD_MUTEX_HPP Chris@16: // (C) Copyright 2007-8 Anthony Williams Chris@101: // (C) Copyright 2011,2012,2015 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@101: #include Chris@16: #include Chris@16: #include Chris@101: #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: #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@16: Chris@16: Chris@16: #include Chris@16: Chris@16: #ifndef BOOST_THREAD_HAS_NO_EINTR_BUG Chris@16: #define BOOST_THREAD_HAS_EINTR_BUG Chris@16: #endif Chris@16: Chris@16: namespace boost Chris@16: { Chris@16: namespace posix { Chris@16: #ifdef BOOST_THREAD_HAS_EINTR_BUG Chris@16: BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m) Chris@16: { Chris@16: int ret; Chris@16: do Chris@16: { Chris@16: ret = ::pthread_mutex_destroy(m); Chris@16: } while (ret == EINTR); Chris@16: return ret; Chris@16: } Chris@16: BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m) Chris@16: { Chris@16: int ret; Chris@16: do Chris@16: { Chris@16: ret = ::pthread_mutex_lock(m); Chris@16: } while (ret == EINTR); Chris@16: return ret; Chris@16: } Chris@16: BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m) Chris@16: { Chris@16: int ret; Chris@16: do Chris@16: { Chris@16: ret = ::pthread_mutex_unlock(m); Chris@16: } while (ret == EINTR); Chris@16: return ret; Chris@16: } Chris@16: #else Chris@16: BOOST_FORCEINLINE int pthread_mutex_destroy(pthread_mutex_t* m) Chris@16: { Chris@16: return ::pthread_mutex_destroy(m); Chris@16: } Chris@16: BOOST_FORCEINLINE int pthread_mutex_lock(pthread_mutex_t* m) Chris@16: { Chris@16: return ::pthread_mutex_lock(m); Chris@16: } Chris@16: BOOST_FORCEINLINE int pthread_mutex_unlock(pthread_mutex_t* m) Chris@16: { Chris@16: return ::pthread_mutex_unlock(m); Chris@16: } Chris@16: Chris@16: #endif Chris@16: Chris@16: } Chris@16: class mutex Chris@16: { Chris@16: private: Chris@16: pthread_mutex_t m; Chris@16: public: Chris@16: BOOST_THREAD_NO_COPYABLE(mutex) Chris@16: Chris@16: mutex() Chris@16: { 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:: mutex constructor failed in pthread_mutex_init")); Chris@16: } Chris@16: } Chris@16: ~mutex() Chris@16: { Chris@101: int const res = posix::pthread_mutex_destroy(&m); Chris@101: boost::ignore_unused(res); Chris@101: BOOST_ASSERT(!res); Chris@16: } Chris@16: Chris@16: void lock() Chris@16: { Chris@16: int res = posix::pthread_mutex_lock(&m); Chris@16: if (res) Chris@16: { Chris@16: boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); Chris@16: } Chris@16: } Chris@16: Chris@16: void unlock() Chris@16: { Chris@16: int res = posix::pthread_mutex_unlock(&m); Chris@101: (void)res; Chris@101: BOOST_ASSERT(res == 0); Chris@101: // if (res) Chris@101: // { Chris@101: // boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); Chris@101: // } Chris@16: } Chris@16: Chris@16: bool try_lock() Chris@16: { Chris@16: int res; Chris@16: do Chris@16: { Chris@16: res = pthread_mutex_trylock(&m); Chris@16: } while (res == EINTR); Chris@16: if (res==EBUSY) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: Chris@16: return !res; Chris@16: } Chris@16: Chris@16: #define BOOST_THREAD_DEFINES_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_lock; Chris@16: typedef detail::try_lock_wrapper scoped_try_lock; Chris@16: #endif Chris@16: }; Chris@16: Chris@16: typedef mutex try_mutex; Chris@16: Chris@16: class timed_mutex Chris@16: { Chris@16: private: Chris@16: pthread_mutex_t m; Chris@16: #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK Chris@16: pthread_cond_t cond; Chris@16: bool is_locked; Chris@16: #endif Chris@16: public: Chris@16: BOOST_THREAD_NO_COPYABLE(timed_mutex) Chris@16: timed_mutex() Chris@16: { 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:: timed_mutex constructor failed in pthread_mutex_init")); Chris@16: } Chris@16: #ifndef BOOST_PTHREAD_HAS_TIMEDLOCK Chris@16: int const res2=pthread_cond_init(&cond,NULL); Chris@16: if(res2) Chris@16: { Chris@16: BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); Chris@16: //BOOST_VERIFY(!pthread_mutex_destroy(&m)); Chris@16: boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init")); Chris@16: } Chris@16: is_locked=false; Chris@16: #endif Chris@16: } Chris@16: ~timed_mutex() Chris@16: { Chris@16: BOOST_VERIFY(!posix::pthread_mutex_destroy(&m)); Chris@16: #ifndef BOOST_PTHREAD_HAS_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: bool timed_lock(boost::xtime const & absolute_time) Chris@16: { Chris@16: return timed_lock(system_time(absolute_time)); Chris@16: } Chris@16: #endif Chris@16: #ifdef BOOST_PTHREAD_HAS_TIMEDLOCK Chris@16: void lock() Chris@16: { Chris@16: int res = posix::pthread_mutex_lock(&m); Chris@16: if (res) Chris@16: { Chris@16: boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); Chris@16: } Chris@16: } Chris@16: Chris@16: void unlock() Chris@16: { Chris@16: int res = posix::pthread_mutex_unlock(&m); Chris@101: (void)res; Chris@101: BOOST_ASSERT(res == 0); Chris@101: // if (res) Chris@101: // { Chris@101: // boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_unlock")); Chris@101: // } Chris@16: } Chris@16: Chris@16: bool try_lock() Chris@16: { Chris@16: int res; Chris@16: do Chris@16: { Chris@16: res = pthread_mutex_trylock(&m); Chris@16: } while (res == EINTR); Chris@16: if (res==EBUSY) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: Chris@16: return !res; Chris@16: } Chris@16: 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: 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: while(is_locked) Chris@16: { Chris@16: BOOST_VERIFY(!pthread_cond_wait(&cond,&m)); Chris@16: } Chris@16: is_locked=true; Chris@16: } Chris@16: Chris@16: void unlock() Chris@16: { Chris@16: boost::pthread::pthread_mutex_scoped_lock const local_lock(&m); Chris@16: is_locked=false; 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) Chris@16: { Chris@16: return false; Chris@16: } Chris@16: is_locked=true; 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: 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: return true; Chris@16: } Chris@16: public: 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=boost::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_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: Chris@16: #endif