1// 2// detail/impl/win_thread.ipp 3// ~~~~~~~~~~~~~~~~~~~~~~~~~~ 4// 5// Copyright (c) 2003-2021 Christopher M. Kohlhoff (chris at kohlhoff dot com) 6// 7// Distributed under the Boost Software License, Version 1.0. (See accompanying 8// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 9// 10 11#ifndef BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP 12#define BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP 13 14#if defined(_MSC_VER) && (_MSC_VER >= 1200) 15# pragma once 16#endif // defined(_MSC_VER) && (_MSC_VER >= 1200) 17 18#include <boost/asio/detail/config.hpp> 19 20#if defined(BOOST_ASIO_WINDOWS) \ 21 && !defined(BOOST_ASIO_WINDOWS_APP) \ 22 && !defined(UNDER_CE) 23 24#include <process.h> 25#include <boost/asio/detail/throw_error.hpp> 26#include <boost/asio/detail/win_thread.hpp> 27#include <boost/asio/error.hpp> 28 29#include <boost/asio/detail/push_options.hpp> 30 31namespace boost { 32namespace asio { 33namespace detail { 34 35win_thread::~win_thread() 36{ 37 ::CloseHandle(thread_); 38 39 // The exit_event_ handle is deliberately allowed to leak here since it 40 // is an error for the owner of an internal thread not to join() it. 41} 42 43void win_thread::join() 44{ 45 HANDLE handles[2] = { exit_event_, thread_ }; 46 ::WaitForMultipleObjects(2, handles, FALSE, INFINITE); 47 ::CloseHandle(exit_event_); 48 if (terminate_threads()) 49 { 50 ::TerminateThread(thread_, 0); 51 } 52 else 53 { 54 ::QueueUserAPC(apc_function, thread_, 0); 55 ::WaitForSingleObject(thread_, INFINITE); 56 } 57} 58 59std::size_t win_thread::hardware_concurrency() 60{ 61 SYSTEM_INFO system_info; 62 ::GetSystemInfo(&system_info); 63 return system_info.dwNumberOfProcessors; 64} 65 66void win_thread::start_thread(func_base* arg, unsigned int stack_size) 67{ 68 ::HANDLE entry_event = 0; 69 arg->entry_event_ = entry_event = ::CreateEventW(0, true, false, 0); 70 if (!entry_event) 71 { 72 DWORD last_error = ::GetLastError(); 73 delete arg; 74 boost::system::error_code ec(last_error, 75 boost::asio::error::get_system_category()); 76 boost::asio::detail::throw_error(ec, "thread.entry_event"); 77 } 78 79 arg->exit_event_ = exit_event_ = ::CreateEventW(0, true, false, 0); 80 if (!exit_event_) 81 { 82 DWORD last_error = ::GetLastError(); 83 delete arg; 84 boost::system::error_code ec(last_error, 85 boost::asio::error::get_system_category()); 86 boost::asio::detail::throw_error(ec, "thread.exit_event"); 87 } 88 89 unsigned int thread_id = 0; 90 thread_ = reinterpret_cast<HANDLE>(::_beginthreadex(0, 91 stack_size, win_thread_function, arg, 0, &thread_id)); 92 if (!thread_) 93 { 94 DWORD last_error = ::GetLastError(); 95 delete arg; 96 if (entry_event) 97 ::CloseHandle(entry_event); 98 if (exit_event_) 99 ::CloseHandle(exit_event_); 100 boost::system::error_code ec(last_error, 101 boost::asio::error::get_system_category()); 102 boost::asio::detail::throw_error(ec, "thread"); 103 } 104 105 if (entry_event) 106 { 107 ::WaitForSingleObject(entry_event, INFINITE); 108 ::CloseHandle(entry_event); 109 } 110} 111 112unsigned int __stdcall win_thread_function(void* arg) 113{ 114 win_thread::auto_func_base_ptr func = { 115 static_cast<win_thread::func_base*>(arg) }; 116 117 ::SetEvent(func.ptr->entry_event_); 118 119 func.ptr->run(); 120 121 // Signal that the thread has finished its work, but rather than returning go 122 // to sleep to put the thread into a well known state. If the thread is being 123 // joined during global object destruction then it may be killed using 124 // TerminateThread (to avoid a deadlock in DllMain). Otherwise, the SleepEx 125 // call will be interrupted using QueueUserAPC and the thread will shut down 126 // cleanly. 127 HANDLE exit_event = func.ptr->exit_event_; 128 delete func.ptr; 129 func.ptr = 0; 130 ::SetEvent(exit_event); 131 ::SleepEx(INFINITE, TRUE); 132 133 return 0; 134} 135 136#if defined(WINVER) && (WINVER < 0x0500) 137void __stdcall apc_function(ULONG) {} 138#else 139void __stdcall apc_function(ULONG_PTR) {} 140#endif 141 142} // namespace detail 143} // namespace asio 144} // namespace boost 145 146#include <boost/asio/detail/pop_options.hpp> 147 148#endif // defined(BOOST_ASIO_WINDOWS) 149 // && !defined(BOOST_ASIO_WINDOWS_APP) 150 // && !defined(UNDER_CE) 151 152#endif // BOOST_ASIO_DETAIL_IMPL_WIN_THREAD_IPP 153