win_thread.cc 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #if defined(OS_WIN)
  10. // Most Mingw builds support std::thread only when using posix threads.
  11. // In that case, some of these functions will be unavailable.
  12. // Note that we're using either WindowsThread or std::thread, depending on
  13. // which one is available.
  14. #ifndef _POSIX_THREADS
  15. #include "port/win/win_thread.h"
  16. #include <assert.h>
  17. #include <process.h> // __beginthreadex
  18. #include <windows.h>
  19. #include <stdexcept>
  20. #include <system_error>
  21. #include <thread>
  22. namespace ROCKSDB_NAMESPACE {
  23. namespace port {
  24. struct WindowsThread::Data {
  25. std::function<void()> func_;
  26. uintptr_t handle_;
  27. Data(std::function<void()>&& func) : func_(std::move(func)), handle_(0) {}
  28. Data(const Data&) = delete;
  29. Data& operator=(const Data&) = delete;
  30. static unsigned int __stdcall ThreadProc(void* arg);
  31. };
  32. void WindowsThread::Init(std::function<void()>&& func) {
  33. data_ = std::make_shared<Data>(std::move(func));
  34. // We create another instance of std::shared_ptr to get an additional ref
  35. // since we may detach and destroy this instance before the threadproc
  36. // may start to run. We choose to allocate this additional ref on the heap
  37. // so we do not need to synchronize and allow this thread to proceed
  38. std::unique_ptr<std::shared_ptr<Data>> th_data(
  39. new std::shared_ptr<Data>(data_));
  40. data_->handle_ = _beginthreadex(NULL,
  41. 0, // stack size
  42. &Data::ThreadProc, th_data.get(),
  43. 0, // init flag
  44. &th_id_);
  45. if (data_->handle_ == 0) {
  46. throw std::system_error(
  47. std::make_error_code(std::errc::resource_unavailable_try_again),
  48. "Unable to create a thread");
  49. }
  50. th_data.release();
  51. }
  52. WindowsThread::WindowsThread() : data_(nullptr), th_id_(0) {}
  53. WindowsThread::~WindowsThread() {
  54. // Must be joined or detached
  55. // before destruction.
  56. // This is the same as std::thread
  57. if (data_) {
  58. if (joinable()) {
  59. assert(false);
  60. std::terminate();
  61. }
  62. data_.reset();
  63. }
  64. }
  65. WindowsThread::WindowsThread(WindowsThread&& o) noexcept : WindowsThread() {
  66. *this = std::move(o);
  67. }
  68. WindowsThread& WindowsThread::operator=(WindowsThread&& o) noexcept {
  69. if (joinable()) {
  70. assert(false);
  71. std::terminate();
  72. }
  73. data_ = std::move(o.data_);
  74. // Per spec both instances will have the same id
  75. th_id_ = o.th_id_;
  76. return *this;
  77. }
  78. bool WindowsThread::joinable() const { return (data_ && data_->handle_ != 0); }
  79. WindowsThread::native_handle_type WindowsThread::native_handle() const {
  80. return reinterpret_cast<native_handle_type>(data_->handle_);
  81. }
  82. unsigned WindowsThread::hardware_concurrency() {
  83. return std::thread::hardware_concurrency();
  84. }
  85. void WindowsThread::join() {
  86. if (!joinable()) {
  87. assert(false);
  88. throw std::system_error(std::make_error_code(std::errc::invalid_argument),
  89. "Thread is no longer joinable");
  90. }
  91. if (GetThreadId(GetCurrentThread()) == th_id_) {
  92. assert(false);
  93. throw std::system_error(
  94. std::make_error_code(std::errc::resource_deadlock_would_occur),
  95. "Can not join itself");
  96. }
  97. auto ret =
  98. WaitForSingleObject(reinterpret_cast<HANDLE>(data_->handle_), INFINITE);
  99. if (ret != WAIT_OBJECT_0) {
  100. auto lastError = GetLastError();
  101. assert(false);
  102. throw std::system_error(static_cast<int>(lastError), std::system_category(),
  103. "WaitForSingleObjectFailed: thread join");
  104. }
  105. BOOL rc
  106. #if defined(_MSC_VER)
  107. = FALSE;
  108. #else
  109. __attribute__((__unused__));
  110. #endif
  111. rc = CloseHandle(reinterpret_cast<HANDLE>(data_->handle_));
  112. assert(rc != 0);
  113. data_->handle_ = 0;
  114. }
  115. bool WindowsThread::detach() {
  116. if (!joinable()) {
  117. assert(false);
  118. throw std::system_error(std::make_error_code(std::errc::invalid_argument),
  119. "Thread is no longer available");
  120. }
  121. BOOL ret = CloseHandle(reinterpret_cast<HANDLE>(data_->handle_));
  122. data_->handle_ = 0;
  123. return (ret != 0);
  124. }
  125. void WindowsThread::swap(WindowsThread& o) {
  126. data_.swap(o.data_);
  127. std::swap(th_id_, o.th_id_);
  128. }
  129. unsigned int __stdcall WindowsThread::Data::ThreadProc(void* arg) {
  130. auto ptr = reinterpret_cast<std::shared_ptr<Data>*>(arg);
  131. std::unique_ptr<std::shared_ptr<Data>> data(ptr);
  132. (*data)->func_();
  133. return 0;
  134. }
  135. } // namespace port
  136. } // namespace ROCKSDB_NAMESPACE
  137. #endif // !_POSIX_THREADS
  138. #endif // OS_WIN