Chris@16: // Chris@16: // detail/impl/win_thread.ipp Chris@16: // ~~~~~~~~~~~~~~~~~~~~~~~~~~ Chris@16: // Chris@101: // Copyright (c) 2003-2015 Christopher M. Kohlhoff (chris at kohlhoff dot com) Chris@16: // Chris@16: // Distributed under the Boost Software License, Version 1.0. (See accompanying Chris@16: // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: // Chris@16: Chris@16: #ifndef BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP Chris@16: #define BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP Chris@16: Chris@16: #if defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: # pragma once Chris@16: #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) Chris@16: Chris@16: #include Chris@16: Chris@16: #if defined(BOOST_ASIO_WINDOWS) && !defined(UNDER_CE) Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { Chris@16: namespace asio { Chris@16: namespace detail { Chris@16: Chris@16: win_thread::~win_thread() Chris@16: { Chris@16: ::CloseHandle(thread_); Chris@16: Chris@16: // The exit_event_ handle is deliberately allowed to leak here since it Chris@16: // is an error for the owner of an internal thread not to join() it. Chris@16: } Chris@16: Chris@16: void win_thread::join() Chris@16: { Chris@16: HANDLE handles[2] = { exit_event_, thread_ }; Chris@16: ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); Chris@16: ::CloseHandle(exit_event_); Chris@16: if (terminate_threads()) Chris@16: { Chris@16: ::TerminateThread(thread_, 0); Chris@16: } Chris@16: else Chris@16: { Chris@16: ::QueueUserAPC(apc_function, thread_, 0); Chris@16: ::WaitForSingleObject(thread_, INFINITE); Chris@16: } Chris@16: } Chris@16: Chris@16: void win_thread::start_thread(func_base* arg, unsigned int stack_size) Chris@16: { Chris@16: ::HANDLE entry_event = 0; Chris@16: arg->entry_event_ = entry_event = ::CreateEvent(0, true, false, 0); Chris@16: if (!entry_event) Chris@16: { Chris@16: DWORD last_error = ::GetLastError(); Chris@16: delete arg; Chris@16: boost::system::error_code ec(last_error, Chris@16: boost::asio::error::get_system_category()); Chris@16: boost::asio::detail::throw_error(ec, "thread.entry_event"); Chris@16: } Chris@16: Chris@16: arg->exit_event_ = exit_event_ = ::CreateEvent(0, true, false, 0); Chris@16: if (!exit_event_) Chris@16: { Chris@16: DWORD last_error = ::GetLastError(); Chris@16: delete arg; Chris@16: boost::system::error_code ec(last_error, Chris@16: boost::asio::error::get_system_category()); Chris@16: boost::asio::detail::throw_error(ec, "thread.exit_event"); Chris@16: } Chris@16: Chris@16: unsigned int thread_id = 0; Chris@16: thread_ = reinterpret_cast(::_beginthreadex(0, Chris@16: stack_size, win_thread_function, arg, 0, &thread_id)); Chris@16: if (!thread_) Chris@16: { Chris@16: DWORD last_error = ::GetLastError(); Chris@16: delete arg; Chris@16: if (entry_event) Chris@16: ::CloseHandle(entry_event); Chris@16: if (exit_event_) Chris@16: ::CloseHandle(exit_event_); Chris@16: boost::system::error_code ec(last_error, Chris@16: boost::asio::error::get_system_category()); Chris@16: boost::asio::detail::throw_error(ec, "thread"); Chris@16: } Chris@16: Chris@16: if (entry_event) Chris@16: { Chris@16: ::WaitForSingleObject(entry_event, INFINITE); Chris@16: ::CloseHandle(entry_event); Chris@16: } Chris@16: } Chris@16: Chris@16: unsigned int __stdcall win_thread_function(void* arg) Chris@16: { Chris@16: win_thread::auto_func_base_ptr func = { Chris@16: static_cast(arg) }; Chris@16: Chris@16: ::SetEvent(func.ptr->entry_event_); Chris@16: Chris@16: func.ptr->run(); Chris@16: Chris@16: // Signal that the thread has finished its work, but rather than returning go Chris@16: // to sleep to put the thread into a well known state. If the thread is being Chris@16: // joined during global object destruction then it may be killed using Chris@16: // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx Chris@16: // call will be interrupted using QueueUserAPC and the thread will shut down Chris@16: // cleanly. Chris@16: HANDLE exit_event = func.ptr->exit_event_; Chris@16: delete func.ptr; Chris@16: func.ptr = 0; Chris@16: ::SetEvent(exit_event); Chris@16: ::SleepEx(INFINITE, TRUE); Chris@16: Chris@16: return 0; Chris@16: } Chris@16: Chris@16: #if defined(WINVER) && (WINVER < 0x0500) Chris@16: void __stdcall apc_function(ULONG) {} Chris@16: #else Chris@16: void __stdcall apc_function(ULONG_PTR) {} Chris@16: #endif Chris@16: Chris@16: } // namespace detail Chris@16: } // namespace asio Chris@16: } // namespace boost Chris@16: Chris@16: #include Chris@16: Chris@16: #endif // defined(BOOST_ASIO_WINDOWS) && !defined(UNDER_CE) Chris@16: Chris@16: #endif // BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP