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