$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
From: anthony_at_[hidden]
Date: 2007-10-26 03:33:23
Author: anthonyw
Date: 2007-10-26 03:33:22 EDT (Fri, 26 Oct 2007)
New Revision: 40472
URL: http://svn.boost.org/trac/boost/changeset/40472
Log:
added tests for cancellation
Text files modified: 
   trunk/boost/thread/barrier.hpp           |     4                                         
   trunk/boost/thread/pthread/thread.hpp    |    26 +++++++----                             
   trunk/boost/thread/win32/thread.hpp      |    12 ++--                                    
   trunk/libs/thread/src/pthread/thread.cpp |    89 ++++++++++++++++++++++++++++++++++++++- 
   trunk/libs/thread/src/win32/thread.cpp   |     4                                         
   trunk/libs/thread/test/test_once.cpp     |     6 +-                                      
   trunk/libs/thread/test/test_thread.cpp   |    54 +++++++++++++++++++++++                 
   7 files changed, 167 insertions(+), 28 deletions(-)
Modified: trunk/boost/thread/barrier.hpp
==============================================================================
--- trunk/boost/thread/barrier.hpp	(original)
+++ trunk/boost/thread/barrier.hpp	2007-10-26 03:33:22 EDT (Fri, 26 Oct 2007)
@@ -11,7 +11,7 @@
 #include <boost/thread/detail/config.hpp>
 
 #include <boost/thread/mutex.hpp>
-#include <boost/thread/condition.hpp>
+#include <boost/thread/condition_variable.hpp>
 #include <string>
 #include <stdexcept>
 
@@ -48,7 +48,7 @@
 
     private:
         mutex m_mutex;
-        condition m_cond;
+        condition_variable m_cond;
         unsigned int m_threshold;
         unsigned int m_count;
         unsigned int m_generation;
Modified: trunk/boost/thread/pthread/thread.hpp
==============================================================================
--- trunk/boost/thread/pthread/thread.hpp	(original)
+++ trunk/boost/thread/pthread/thread.hpp	2007-10-26 03:33:22 EDT (Fri, 26 Oct 2007)
@@ -92,18 +92,20 @@
         {
             boost::shared_ptr<thread_data_base> self;
             pthread_t thread_handle;
-            boost::mutex done_mutex;
+            boost::mutex data_mutex;
             boost::condition_variable done_condition;
             bool done;
             bool join_started;
             bool joined;
             boost::detail::thread_exit_callback_node* thread_exit_callbacks;
             bool cancel_enabled;
+            bool cancel_requested;
 
             thread_data_base():
                 done(false),join_started(false),joined(false),
                 thread_exit_callbacks(0),
-                cancel_enabled(true)
+                cancel_enabled(true),
+                cancel_requested(false)
             {}
             virtual ~thread_data_base()
             {}
@@ -203,19 +205,19 @@
             disable_cancellation& operator=(const disable_cancellation&);
             
             bool cancel_was_enabled;
-            friend class enable_cancellation;
+            friend class restore_cancellation;
         public:
             disable_cancellation();
             ~disable_cancellation();
         };
 
-        class enable_cancellation
+        class restore_cancellation
         {
-            enable_cancellation(const enable_cancellation&);
-            enable_cancellation& operator=(const enable_cancellation&);
+            restore_cancellation(const restore_cancellation&);
+            restore_cancellation& operator=(const restore_cancellation&);
         public:
-            explicit enable_cancellation(disable_cancellation& d);
-            ~enable_cancellation();
+            explicit restore_cancellation(disable_cancellation& d);
+            ~restore_cancellation();
         };
 
         inline thread::id get_id()
@@ -227,9 +229,13 @@
         bool BOOST_THREAD_DECL cancellation_enabled();
         bool BOOST_THREAD_DECL cancellation_requested();
 
-        void BOOST_THREAD_DECL yield();
+        inline void yield()
+        {
+            thread::yield();
+        }
+        
         template<typename TimeDuration>
-        void sleep(TimeDuration const& rel_time)
+        inline void sleep(TimeDuration const& rel_time)
         {
             thread::sleep(get_system_time()+rel_time);
         }
Modified: trunk/boost/thread/win32/thread.hpp
==============================================================================
--- trunk/boost/thread/win32/thread.hpp	(original)
+++ trunk/boost/thread/win32/thread.hpp	2007-10-26 03:33:22 EDT (Fri, 26 Oct 2007)
@@ -161,19 +161,19 @@
             disable_cancellation& operator=(const disable_cancellation&);
             
             bool cancel_was_enabled;
-            friend class enable_cancellation;
+            friend class restore_cancellation;
         public:
             disable_cancellation();
             ~disable_cancellation();
         };
 
-        class enable_cancellation
+        class restore_cancellation
         {
-            enable_cancellation(const enable_cancellation&);
-            enable_cancellation& operator=(const enable_cancellation&);
+            restore_cancellation(const restore_cancellation&);
+            restore_cancellation& operator=(const restore_cancellation&);
         public:
-            explicit enable_cancellation(disable_cancellation& d);
-            ~enable_cancellation();
+            explicit restore_cancellation(disable_cancellation& d);
+            ~restore_cancellation();
         };
 
         thread::id BOOST_THREAD_DECL get_id();
Modified: trunk/libs/thread/src/pthread/thread.cpp
==============================================================================
--- trunk/libs/thread/src/pthread/thread.cpp	(original)
+++ trunk/libs/thread/src/pthread/thread.cpp	2007-10-26 03:33:22 EDT (Fri, 26 Oct 2007)
@@ -94,7 +94,7 @@
 
                 tls_destructor(thread_info.get());
                 set_current_thread_data(0);
-                boost::lock_guard<boost::mutex> lock(thread_info->done_mutex);
+                boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);
                 thread_info->done=true;
                 thread_info->done_condition.notify_all();
                 return 0;
@@ -147,7 +147,7 @@
             bool do_join=false;
             
             {
-                unique_lock<mutex> lock(local_thread_info->done_mutex);
+                unique_lock<mutex> lock(local_thread_info->data_mutex);
                 while(!local_thread_info->done)
                 {
                     local_thread_info->done_condition.wait(lock);
@@ -171,7 +171,7 @@
                 void* result=0;
                 int const res=pthread_join(local_thread_info->thread_handle,&result);
                 BOOST_ASSERT(!res);
-                lock_guard<mutex> lock(local_thread_info->done_mutex);
+                lock_guard<mutex> lock(local_thread_info->data_mutex);
                 local_thread_info->joined=true;
                 local_thread_info->done_condition.notify_all();
             }
@@ -200,7 +200,7 @@
         
         if(local_thread_info)
         {
-            lock_guard<mutex> lock(local_thread_info->done_mutex);
+            lock_guard<mutex> lock(local_thread_info->data_mutex);
             if(!local_thread_info->join_started)
             {
                 int const res=pthread_detach(local_thread_info->thread_handle);
@@ -278,6 +278,87 @@
         }
     }
 
+    void thread::cancel()
+    {
+        boost::shared_ptr<detail::thread_data_base> local_thread_info=get_thread_info();
+        if(local_thread_info)
+        {
+            lock_guard<mutex> lk(local_thread_info->data_mutex);
+            local_thread_info->cancel_requested=true;
+        }
+    }
+    
+
+    namespace this_thread
+    {
+        void cancellation_point()
+        {
+            boost::detail::thread_data_base* const thread_info=get_current_thread_data();
+            if(thread_info && thread_info->cancel_enabled)
+            {
+                lock_guard<mutex> lg(thread_info->data_mutex);
+                if(thread_info->cancel_requested)
+                {
+                    thread_info->cancel_requested=false;
+                    throw thread_cancelled();
+                }
+            }
+        }
+        
+        bool cancellation_enabled()
+        {
+            boost::detail::thread_data_base* const thread_info=get_current_thread_data();
+            return thread_info && thread_info->cancel_enabled;
+        }
+        
+        bool cancellation_requested()
+        {
+            boost::detail::thread_data_base* const thread_info=get_current_thread_data();
+            if(!thread_info)
+            {
+                return false;
+            }
+            else
+            {
+                lock_guard<mutex> lg(thread_info->data_mutex);
+                return thread_info->cancel_requested;
+            }
+        }
+
+        disable_cancellation::disable_cancellation():
+            cancel_was_enabled(cancellation_enabled())
+        {
+            if(cancel_was_enabled)
+            {
+                get_current_thread_data()->cancel_enabled=false;
+            }
+        }
+        
+        disable_cancellation::~disable_cancellation()
+        {
+            if(get_current_thread_data())
+            {
+                get_current_thread_data()->cancel_enabled=cancel_was_enabled;
+            }
+        }
+
+        restore_cancellation::restore_cancellation(disable_cancellation& d)
+        {
+            if(d.cancel_was_enabled)
+            {
+                get_current_thread_data()->cancel_enabled=true;
+            }
+        }
+        
+        restore_cancellation::~restore_cancellation()
+        {
+            if(get_current_thread_data())
+            {
+                get_current_thread_data()->cancel_enabled=false;
+            }
+        }
+    }
+
     thread_group::thread_group()
     {
     }
Modified: trunk/libs/thread/src/win32/thread.cpp
==============================================================================
--- trunk/libs/thread/src/win32/thread.cpp	(original)
+++ trunk/libs/thread/src/win32/thread.cpp	2007-10-26 03:33:22 EDT (Fri, 26 Oct 2007)
@@ -357,7 +357,7 @@
             }
         }
 
-        enable_cancellation::enable_cancellation(disable_cancellation& d)
+        restore_cancellation::restore_cancellation(disable_cancellation& d)
         {
             if(d.cancel_was_enabled)
             {
@@ -365,7 +365,7 @@
             }
         }
         
-        enable_cancellation::~enable_cancellation()
+        restore_cancellation::~restore_cancellation()
         {
             if(get_current_thread_data())
             {
Modified: trunk/libs/thread/test/test_once.cpp
==============================================================================
--- trunk/libs/thread/test/test_once.cpp	(original)
+++ trunk/libs/thread/test/test_once.cpp	2007-10-26 03:33:22 EDT (Fri, 26 Oct 2007)
@@ -38,7 +38,7 @@
 
 void test_call_once()
 {
-    unsigned const num_threads=100;
+    unsigned const num_threads=20;
     boost::thread_group group;
     
     for(unsigned i=0;i<num_threads;++i)
@@ -85,7 +85,7 @@
 
 void test_call_once_arbitrary_functor()
 {
-    unsigned const num_threads=100;
+    unsigned const num_threads=20;
     boost::thread_group group;
 
     for(unsigned i=0;i<num_threads;++i)
@@ -134,7 +134,7 @@
 
 void test_call_once_retried_on_exception()
 {
-    unsigned const num_threads=100;
+    unsigned const num_threads=20;
     boost::thread_group group;
 
     for(unsigned i=0;i<num_threads;++i)
Modified: trunk/libs/thread/test/test_thread.cpp
==============================================================================
--- trunk/libs/thread/test/test_thread.cpp	(original)
+++ trunk/libs/thread/test/test_thread.cpp	2007-10-26 03:33:22 EDT (Fri, 26 Oct 2007)
@@ -8,6 +8,7 @@
 
 #include <boost/thread/thread.hpp>
 #include <boost/thread/xtime.hpp>
+#include <boost/bind.hpp>
 
 #include <boost/test/unit_test.hpp>
 
@@ -59,7 +60,7 @@
 void do_test_id_comparison()
 {
     boost::thread::id const self=boost::this_thread::get_id();
-    boost::thread thrd(bind(&comparison_thread, self));
+    boost::thread thrd(boost::bind(&comparison_thread, self));
     thrd.join();
 }
 
@@ -68,6 +69,55 @@
     timed_test(&do_test_id_comparison, 1);
 }
 
+void cancellation_point_thread(boost::mutex* m,bool* failed)
+{
+    boost::mutex::scoped_lock lk(*m);
+    boost::this_thread::cancellation_point();
+    *failed=true;
+}
+
+void do_test_thread_cancels_at_cancellation_point()
+{
+    boost::mutex m;
+    bool failed=false;
+    boost::mutex::scoped_lock lk(m);
+    boost::thread thrd(boost::bind(&cancellation_point_thread,&m,&failed));
+    thrd.cancel();
+    lk.unlock();
+    thrd.join();
+    BOOST_CHECK(!failed);
+}
+
+void test_thread_cancels_at_cancellation_point()
+{
+    timed_test(&do_test_thread_cancels_at_cancellation_point, 1);
+}
+
+void disabled_cancellation_point_thread(boost::mutex* m,bool* failed)
+{
+    boost::mutex::scoped_lock lk(*m);
+    boost::this_thread::disable_cancellation dc;
+    boost::this_thread::cancellation_point();
+    *failed=false;
+}
+
+void do_test_thread_no_cancel_if_cancels_disabled_at_cancellation_point()
+{
+    boost::mutex m;
+    bool failed=true;
+    boost::mutex::scoped_lock lk(m);
+    boost::thread thrd(boost::bind(&disabled_cancellation_point_thread,&m,&failed));
+    thrd.cancel();
+    lk.unlock();
+    thrd.join();
+    BOOST_CHECK(!failed);
+}
+
+void test_thread_no_cancel_if_cancels_disabled_at_cancellation_point()
+{
+    timed_test(&do_test_thread_no_cancel_if_cancels_disabled_at_cancellation_point, 1);
+}
+
 boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
 {
     boost::unit_test_framework::test_suite* test =
@@ -76,6 +126,8 @@
     test->add(BOOST_TEST_CASE(test_sleep));
     test->add(BOOST_TEST_CASE(test_creation));
     test->add(BOOST_TEST_CASE(test_id_comparison));
+    test->add(BOOST_TEST_CASE(test_thread_cancels_at_cancellation_point));
+    test->add(BOOST_TEST_CASE(test_thread_no_cancel_if_cancels_disabled_at_cancellation_point));
 
     return test;
 }