win_thread.ipp 4.0 KB

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