Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r66228 - in trunk: boost/thread/pthread libs/thread/src/pthread
From: anthony_at_[hidden]
Date: 2010-10-28 10:18:03


Author: anthonyw
Date: 2010-10-28 10:18:00 EDT (Thu, 28 Oct 2010)
New Revision: 66228
URL: http://svn.boost.org/trac/boost/changeset/66228

Log:
Fix for issue #2330 - remove race condition in condition_variable::wait wrt interruption checking
Text files modified:
   trunk/boost/thread/pthread/condition_variable.hpp | 72 ++++++++++++++++++++++++++++++----------
   trunk/boost/thread/pthread/condition_variable_fwd.hpp | 10 +++++
   trunk/boost/thread/pthread/pthread_mutex_scoped_lock.hpp | 14 ++++++-
   trunk/boost/thread/pthread/thread_data.hpp | 26 +++++++++++--
   trunk/libs/thread/src/pthread/thread.cpp | 1
   5 files changed, 97 insertions(+), 26 deletions(-)

Modified: trunk/boost/thread/pthread/condition_variable.hpp
==============================================================================
--- trunk/boost/thread/pthread/condition_variable.hpp (original)
+++ trunk/boost/thread/pthread/condition_variable.hpp 2010-10-28 10:18:00 EDT (Thu, 28 Oct 2010)
@@ -14,17 +14,55 @@
 
 namespace boost
 {
+ namespace this_thread
+ {
+ void BOOST_THREAD_DECL interruption_point();
+ }
+
+ namespace thread_cv_detail
+ {
+ template<typename MutexType>
+ 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<mutex>& m)
     {
- detail::interruption_checker check_for_interruption(&cond);
- BOOST_VERIFY(!pthread_cond_wait(&cond,m.mutex()->native_handle()));
+ thread_cv_detail::lock_on_exit<unique_lock<mutex> > 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<mutex>& m,boost::system_time const& wait_until)
     {
- detail::interruption_checker check_for_interruption(&cond);
+ thread_cv_detail::lock_on_exit<unique_lock<mutex> > 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 @@
 
     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 @@
         {
             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<lock_type> 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 @@
             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<lock_type> 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)
             {

Modified: trunk/boost/thread/pthread/condition_variable_fwd.hpp
==============================================================================
--- trunk/boost/thread/pthread/condition_variable_fwd.hpp (original)
+++ trunk/boost/thread/pthread/condition_variable_fwd.hpp 2010-10-28 10:18:00 EDT (Thu, 28 Oct 2010)
@@ -20,6 +20,7 @@
     class condition_variable
     {
     private:
+ pthread_mutex_t internal_mutex;
         pthread_cond_t cond;
         
         condition_variable(condition_variable&);
@@ -28,14 +29,21 @@
     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));
         }
 

Modified: trunk/boost/thread/pthread/pthread_mutex_scoped_lock.hpp
==============================================================================
--- trunk/boost/thread/pthread/pthread_mutex_scoped_lock.hpp (original)
+++ trunk/boost/thread/pthread/pthread_mutex_scoped_lock.hpp 2010-10-28 10:18:00 EDT (Thu, 28 Oct 2010)
@@ -18,15 +18,25 @@
         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();
+ }
             }
             
         };

Modified: trunk/boost/thread/pthread/thread_data.hpp
==============================================================================
--- trunk/boost/thread/pthread/thread_data.hpp (original)
+++ trunk/boost/thread/pthread/thread_data.hpp 2010-10-28 10:18:00 EDT (Thu, 28 Oct 2010)
@@ -12,6 +12,7 @@
 #include <boost/thread/mutex.hpp>
 #include <boost/optional.hpp>
 #include <pthread.h>
+#include <boost/assert.hpp>
 #include "condition_variable_fwd.hpp"
 #include <map>
 
@@ -55,6 +56,7 @@
             std::map<void const*,boost::detail::tss_data_node> 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 @@
         class interruption_checker
         {
             thread_data_base* const thread_info;
+ pthread_mutex_t* m;
+ bool set;
 
             void check_for_interruption()
             {
@@ -88,23 +92,35 @@
             
             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<mutex> 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<mutex> 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));
                 }
             }
         };

Modified: trunk/libs/thread/src/pthread/thread.cpp
==============================================================================
--- trunk/libs/thread/src/pthread/thread.cpp (original)
+++ trunk/libs/thread/src/pthread/thread.cpp 2010-10-28 10:18:00 EDT (Thu, 28 Oct 2010)
@@ -411,6 +411,7 @@
             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));
             }
         }


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk