|
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