Boost logo

Boost-Commit :

From: chris_at_[hidden]
Date: 2008-05-30 04:39:20


Author: chris_kohlhoff
Date: 2008-05-30 04:39:19 EDT (Fri, 30 May 2008)
New Revision: 45935
URL: http://svn.boost.org/trac/boost/changeset/45935

Log:
Fix a deadlock that can occur when destroying a thread object with global
lifetime in a dynamically loaded DLL on Windows. Note that deadlock can
still occur if the thread is launched by the constructor of an object with
global lifetime.

Text files modified:
   trunk/boost/asio/detail/null_thread.hpp | 5 ++
   trunk/boost/asio/detail/posix_thread.hpp | 5 ++
   trunk/boost/asio/detail/win_thread.hpp | 73 ++++++++++++++++++++++++++++++++++++++-
   trunk/boost/asio/detail/wince_thread.hpp | 5 ++
   4 files changed, 83 insertions(+), 5 deletions(-)

Modified: trunk/boost/asio/detail/null_thread.hpp
==============================================================================
--- trunk/boost/asio/detail/null_thread.hpp (original)
+++ trunk/boost/asio/detail/null_thread.hpp 2008-05-30 04:39:19 EDT (Fri, 30 May 2008)
@@ -39,9 +39,12 @@
   : private noncopyable
 {
 public:
+ // The purpose of the thread.
+ enum purpose { internal, external };
+
   // Constructor.
   template <typename Function>
- null_thread(Function f)
+ null_thread(Function f, purpose = internal)
   {
     boost::system::system_error e(
         boost::asio::error::operation_not_supported, "thread");

Modified: trunk/boost/asio/detail/posix_thread.hpp
==============================================================================
--- trunk/boost/asio/detail/posix_thread.hpp (original)
+++ trunk/boost/asio/detail/posix_thread.hpp 2008-05-30 04:39:19 EDT (Fri, 30 May 2008)
@@ -43,9 +43,12 @@
   : private noncopyable
 {
 public:
+ // The purpose of the thread.
+ enum purpose { internal, external };
+
   // Constructor.
   template <typename Function>
- posix_thread(Function f)
+ posix_thread(Function f, purpose = internal)
     : joined_(false)
   {
     std::auto_ptr<func_base> arg(new func<Function>(f));

Modified: trunk/boost/asio/detail/win_thread.hpp
==============================================================================
--- trunk/boost/asio/detail/win_thread.hpp (original)
+++ trunk/boost/asio/detail/win_thread.hpp 2008-05-30 04:39:19 EDT (Fri, 30 May 2008)
@@ -44,17 +44,53 @@
   : private noncopyable
 {
 public:
+ // The purpose of the thread.
+ enum purpose { internal, external };
+
   // Constructor.
   template <typename Function>
- win_thread(Function f)
+ win_thread(Function f, purpose p = internal)
+ : exit_event_(0)
   {
     std::auto_ptr<func_base> arg(new func<Function>(f));
+
+ ::HANDLE entry_event = 0;
+ if (p == internal)
+ {
+ arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0);
+ if (!entry_event)
+ {
+ DWORD last_error = ::GetLastError();
+ boost::system::system_error e(
+ boost::system::error_code(last_error,
+ boost::asio::error::get_system_category()),
+ "thread.entry_event");
+ boost::throw_exception(e);
+ }
+
+ arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0);
+ if (!exit_event_)
+ {
+ DWORD last_error = ::GetLastError();
+ ::CloseHandle(entry_event);
+ boost::system::system_error e(
+ boost::system::error_code(last_error,
+ boost::asio::error::get_system_category()),
+ "thread.exit_event");
+ boost::throw_exception(e);
+ }
+ }
+
     unsigned int thread_id = 0;
     thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, 0,
           win_thread_function, arg.get(), 0, &thread_id));
     if (!thread_)
     {
       DWORD last_error = ::GetLastError();
+ if (entry_event)
+ ::CloseHandle(entry_event);
+ if (exit_event_)
+ ::CloseHandle(exit_event_);
       boost::system::system_error e(
           boost::system::error_code(last_error,
             boost::asio::error::get_system_category()),
@@ -62,18 +98,36 @@
       boost::throw_exception(e);
     }
     arg.release();
+
+ if (entry_event)
+ {
+ ::WaitForSingleObject(entry_event, INFINITE);
+ ::CloseHandle(entry_event);
+ }
   }
 
   // Destructor.
   ~win_thread()
   {
     ::CloseHandle(thread_);
+
+ // The exit_event_ handle is deliberately allowed to leak here since it
+ // is an error for the owner of an internal thread not to join() it.
   }
 
   // Wait for the thread to exit.
   void join()
   {
- ::WaitForSingleObject(thread_, INFINITE);
+ if (exit_event_)
+ {
+ ::WaitForSingleObject(exit_event_, INFINITE);
+ ::CloseHandle(exit_event_);
+ ::TerminateThread(thread_, 0);
+ }
+ else
+ {
+ ::WaitForSingleObject(thread_, INFINITE);
+ }
   }
 
 private:
@@ -84,6 +138,8 @@
   public:
     virtual ~func_base() {}
     virtual void run() = 0;
+ ::HANDLE entry_event_;
+ ::HANDLE exit_event_;
   };
 
   template <typename Function>
@@ -106,13 +162,26 @@
   };
 
   ::HANDLE thread_;
+ ::HANDLE exit_event_;
 };
 
 inline unsigned int __stdcall win_thread_function(void* arg)
 {
   std::auto_ptr<win_thread::func_base> func(
       static_cast<win_thread::func_base*>(arg));
+
+ if (func->entry_event_)
+ ::SetEvent(func->entry_event_);
+
   func->run();
+
+ if (HANDLE exit_event = func->exit_event_)
+ {
+ func.reset();
+ ::SetEvent(exit_event);
+ ::Sleep(INFINITE);
+ }
+
   return 0;
 }
 

Modified: trunk/boost/asio/detail/wince_thread.hpp
==============================================================================
--- trunk/boost/asio/detail/wince_thread.hpp (original)
+++ trunk/boost/asio/detail/wince_thread.hpp 2008-05-30 04:39:19 EDT (Fri, 30 May 2008)
@@ -43,9 +43,12 @@
   : private noncopyable
 {
 public:
+ // The purpose of the thread.
+ enum purpose { internal, external };
+
   // Constructor.
   template <typename Function>
- wince_thread(Function f)
+ wince_thread(Function f, purpose = internal)
   {
     std::auto_ptr<func_base> arg(new func<Function>(f));
     DWORD thread_id = 0;


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