diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index cb413ab6..a4b43432 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -912,10 +912,10 @@ namespace boost void lazy_init() { - if(!future) + if(!atomic_load(&future)) { - future_obtained=false; - future.reset(new detail::future_object); + future_ptr blank; + atomic_compare_exchange(&future,&blank,future_ptr(new detail::future_object)); } } @@ -945,12 +945,14 @@ namespace boost future_obtained(rhs.future_obtained) { future.swap(rhs.future); + rhs.future_obtained=false; } promise & operator=(promise&& rhs) { future.swap(rhs.future); future_obtained=rhs.future_obtained; rhs.future.reset(); + rhs.future_obtained=false; return *this; } #else @@ -958,12 +960,14 @@ namespace boost future(rhs->future),future_obtained(rhs->future_obtained) { rhs->future.reset(); + rhs->future_obtained=false; } promise & operator=(boost::detail::thread_move_t rhs) { future=rhs->future; future_obtained=rhs->future_obtained; rhs->future.reset(); + rhs->future_obtained=false; return *this; } @@ -1047,10 +1051,10 @@ namespace boost void lazy_init() { - if(!future) + if(!atomic_load(&future)) { - future_obtained=false; - future.reset(new detail::future_object); + future_ptr blank; + atomic_compare_exchange(&future,&blank,future_ptr(new detail::future_object)); } } public: @@ -1079,12 +1083,14 @@ namespace boost future_obtained(rhs.future_obtained) { future.swap(rhs.future); + rhs.future_obtained=false; } promise & operator=(promise&& rhs) { future.swap(rhs.future); future_obtained=rhs.future_obtained; rhs.future.reset(); + rhs.future_obtained=false; return *this; } #else @@ -1092,12 +1098,14 @@ namespace boost future(rhs->future),future_obtained(rhs->future_obtained) { rhs->future.reset(); + rhs->future_obtained=false; } promise & operator=(boost::detail::thread_move_t rhs) { future=rhs->future; future_obtained=rhs->future_obtained; rhs->future.reset(); + rhs->future_obtained=false; return *this; } diff --git a/include/boost/thread/pthread/condition_variable.hpp b/include/boost/thread/pthread/condition_variable.hpp index 30470be9..9c5bee27 100644 --- a/include/boost/thread/pthread/condition_variable.hpp +++ b/include/boost/thread/pthread/condition_variable.hpp @@ -14,17 +14,55 @@ namespace boost { + namespace this_thread + { + void BOOST_THREAD_DECL interruption_point(); + } + + namespace thread_cv_detail + { + template + struct lock_on_exit + { + MutexType* m; + + lock_on_exit(): + m(0) + {} + + void activate(MutexType& m_) + { + m_.unlock(); + m=&m_; + } + ~lock_on_exit() + { + if(m) + { + m->lock(); + } + } + }; + } + inline void condition_variable::wait(unique_lock& m) { - detail::interruption_checker check_for_interruption(&cond); - BOOST_VERIFY(!pthread_cond_wait(&cond,m.mutex()->native_handle())); + thread_cv_detail::lock_on_exit > guard; + detail::interruption_checker check_for_interruption(&internal_mutex,&cond); + guard.activate(m); + int const res=pthread_cond_wait(&cond,&internal_mutex); + BOOST_ASSERT(!res); + this_thread::interruption_point(); } inline bool condition_variable::timed_wait(unique_lock& m,boost::system_time const& wait_until) { - detail::interruption_checker check_for_interruption(&cond); + thread_cv_detail::lock_on_exit > guard; + detail::interruption_checker check_for_interruption(&internal_mutex,&cond); + guard.activate(m); struct timespec const timeout=detail::get_timespec(wait_until); - int const cond_res=pthread_cond_timedwait(&cond,m.mutex()->native_handle(),&timeout); + int const cond_res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); + this_thread::interruption_point(); if(cond_res==ETIMEDOUT) { return false; @@ -35,11 +73,13 @@ namespace boost inline void condition_variable::notify_one() { + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); BOOST_VERIFY(!pthread_cond_signal(&cond)); } inline void condition_variable::notify_all() { + boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); BOOST_VERIFY(!pthread_cond_broadcast(&cond)); } @@ -77,13 +117,11 @@ namespace boost { int res=0; { - detail::interruption_checker check_for_interruption(&cond); - { - boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); - m.unlock(); - res=pthread_cond_wait(&cond,&internal_mutex); - } - m.lock(); + thread_cv_detail::lock_on_exit guard; + detail::interruption_checker check_for_interruption(&internal_mutex,&cond); + guard.activate(m); + res=pthread_cond_wait(&cond,&internal_mutex); + this_thread::interruption_point(); } if(res) { @@ -103,13 +141,11 @@ namespace boost struct timespec const timeout=detail::get_timespec(wait_until); int res=0; { - detail::interruption_checker check_for_interruption(&cond); - { - boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex); - m.unlock(); - res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); - } - m.lock(); + thread_cv_detail::lock_on_exit guard; + detail::interruption_checker check_for_interruption(&internal_mutex,&cond); + guard.activate(m); + res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); + this_thread::interruption_point(); } if(res==ETIMEDOUT) { diff --git a/include/boost/thread/pthread/condition_variable_fwd.hpp b/include/boost/thread/pthread/condition_variable_fwd.hpp index 0224d3ac..365f511c 100644 --- a/include/boost/thread/pthread/condition_variable_fwd.hpp +++ b/include/boost/thread/pthread/condition_variable_fwd.hpp @@ -20,6 +20,7 @@ namespace boost class condition_variable { private: + pthread_mutex_t internal_mutex; pthread_cond_t cond; condition_variable(condition_variable&); @@ -28,14 +29,21 @@ namespace boost public: condition_variable() { - int const res=pthread_cond_init(&cond,NULL); + int const res=pthread_mutex_init(&internal_mutex,NULL); if(res) { boost::throw_exception(thread_resource_error()); } + int const res2=pthread_cond_init(&cond,NULL); + if(res2) + { + BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); + boost::throw_exception(thread_resource_error()); + } } ~condition_variable() { + BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex)); BOOST_VERIFY(!pthread_cond_destroy(&cond)); } diff --git a/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp b/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp index 2407f915..cdbf8c67 100644 --- a/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp +++ b/include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp @@ -18,15 +18,25 @@ namespace boost class pthread_mutex_scoped_lock { pthread_mutex_t* m; + bool locked; public: explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_): - m(m_) + m(m_),locked(true) { BOOST_VERIFY(!pthread_mutex_lock(m)); } - ~pthread_mutex_scoped_lock() + void unlock() { BOOST_VERIFY(!pthread_mutex_unlock(m)); + locked=false; + } + + ~pthread_mutex_scoped_lock() + { + if(locked) + { + unlock(); + } } }; diff --git a/include/boost/thread/pthread/thread_data.hpp b/include/boost/thread/pthread/thread_data.hpp index 730c77ca..1bee28b6 100644 --- a/include/boost/thread/pthread/thread_data.hpp +++ b/include/boost/thread/pthread/thread_data.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include "condition_variable_fwd.hpp" #include @@ -55,6 +56,7 @@ namespace boost std::map tss_data; bool interrupt_enabled; bool interrupt_requested; + pthread_mutex_t* cond_mutex; pthread_cond_t* current_cond; thread_data_base(): @@ -76,6 +78,8 @@ namespace boost class interruption_checker { thread_data_base* const thread_info; + pthread_mutex_t* m; + bool set; void check_for_interruption() { @@ -88,23 +92,35 @@ namespace boost void operator=(interruption_checker&); public: - explicit interruption_checker(pthread_cond_t* cond): - thread_info(detail::get_current_thread_data()) + explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond): + thread_info(detail::get_current_thread_data()),m(cond_mutex), + set(thread_info && thread_info->interrupt_enabled) { - if(thread_info && thread_info->interrupt_enabled) + if(set) { lock_guard guard(thread_info->data_mutex); check_for_interruption(); + thread_info->cond_mutex=cond_mutex; thread_info->current_cond=cond; + BOOST_VERIFY(!pthread_mutex_lock(m)); + } + else + { + BOOST_VERIFY(!pthread_mutex_lock(m)); } } ~interruption_checker() { - if(thread_info && thread_info->interrupt_enabled) + if(set) { + BOOST_VERIFY(!pthread_mutex_unlock(m)); lock_guard guard(thread_info->data_mutex); + thread_info->cond_mutex=NULL; thread_info->current_cond=NULL; - check_for_interruption(); + } + else + { + BOOST_VERIFY(!pthread_mutex_unlock(m)); } } }; diff --git a/include/boost/thread/thread_time.hpp b/include/boost/thread/thread_time.hpp index 8b557d5c..ffdcf850 100644 --- a/include/boost/thread/thread_time.hpp +++ b/include/boost/thread/thread_time.hpp @@ -6,6 +6,7 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#include #include #include @@ -17,7 +18,11 @@ namespace boost inline system_time get_system_time() { +#if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) return boost::date_time::microsec_clock::universal_time(); +#else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) + return boost::date_time::second_clock::universal_time(); +#endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK) } namespace detail diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 4ff40a90..187c024f 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -411,6 +411,7 @@ namespace boost local_thread_info->interrupt_requested=true; if(local_thread_info->current_cond) { + boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info->cond_mutex); BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond)); } } diff --git a/src/tss_null.cpp b/src/tss_null.cpp index ff13b30f..e93ba0ff 100644 --- a/src/tss_null.cpp +++ b/src/tss_null.cpp @@ -8,13 +8,15 @@ #if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE)) +namespace boost +{ /* This file is a "null" implementation of tss cleanup; it's purpose is to to eliminate link errors in cases where it is known that tss cleanup is not needed. */ - extern "C" void tss_cleanup_implemented(void) + void tss_cleanup_implemented(void) { /* This function's sole purpose is to cause a link error in cases where @@ -30,5 +32,7 @@ longer needed and can be removed. */ } + +} #endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) && !defined(_MSC_VER) diff --git a/src/win32/tss_pe.cpp b/src/win32/tss_pe.cpp index fb49ac3e..32de7868 100644 --- a/src/win32/tss_pe.cpp +++ b/src/win32/tss_pe.cpp @@ -38,6 +38,12 @@ namespace { } } +#if (__MINGW32_MAJOR_VERSION >3) || ((__MINGW32_MAJOR_VERSION==3) && (__MINGW32_MINOR_VERSION>=18)) +extern "C" +{ + PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback; +} +#else extern "C" { void (* after_ctors )() __attribute__((section(".ctors"))) = boost::on_process_enter; @@ -50,10 +56,8 @@ extern "C" { PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0; - PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback; PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0; } - extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) = { (DWORD) &__tls_start__, @@ -63,6 +67,7 @@ extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata (DWORD) 0, (DWORD) 0 }; +#endif #elif defined(_MSC_VER) && !defined(UNDER_CE)