win_thread.cc 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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. #include "port/win/win_thread.h"
  10. #include <assert.h>
  11. #include <process.h> // __beginthreadex
  12. #include <windows.h>
  13. #include <stdexcept>
  14. #include <system_error>
  15. #include <thread>
  16. namespace ROCKSDB_NAMESPACE {
  17. namespace port {
  18. struct WindowsThread::Data {
  19. std::function<void()> func_;
  20. uintptr_t handle_;
  21. Data(std::function<void()>&& func) :
  22. func_(std::move(func)),
  23. handle_(0) {
  24. }
  25. Data(const Data&) = delete;
  26. Data& operator=(const Data&) = delete;
  27. static unsigned int __stdcall ThreadProc(void* arg);
  28. };
  29. void WindowsThread::Init(std::function<void()>&& func) {
  30. data_ = std::make_shared<Data>(std::move(func));
  31. // We create another instance of std::shared_ptr to get an additional ref
  32. // since we may detach and destroy this instance before the threadproc
  33. // may start to run. We choose to allocate this additional ref on the heap
  34. // so we do not need to synchronize and allow this thread to proceed
  35. std::unique_ptr<std::shared_ptr<Data>> th_data(new std::shared_ptr<Data>(data_));
  36. data_->handle_ = _beginthreadex(NULL,
  37. 0, // stack size
  38. &Data::ThreadProc,
  39. th_data.get(),
  40. 0, // init flag
  41. &th_id_);
  42. if (data_->handle_ == 0) {
  43. throw std::system_error(std::make_error_code(
  44. std::errc::resource_unavailable_try_again),
  45. "Unable to create a thread");
  46. }
  47. th_data.release();
  48. }
  49. WindowsThread::WindowsThread() :
  50. data_(nullptr),
  51. th_id_(0)
  52. {}
  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 :
  66. WindowsThread() {
  67. *this = std::move(o);
  68. }
  69. WindowsThread& WindowsThread::operator=(WindowsThread&& o) noexcept {
  70. if (joinable()) {
  71. assert(false);
  72. std::terminate();
  73. }
  74. data_ = std::move(o.data_);
  75. // Per spec both instances will have the same id
  76. th_id_ = o.th_id_;
  77. return *this;
  78. }
  79. bool WindowsThread::joinable() const {
  80. return (data_ && data_->handle_ != 0);
  81. }
  82. WindowsThread::native_handle_type WindowsThread::native_handle() const {
  83. return reinterpret_cast<native_handle_type>(data_->handle_);
  84. }
  85. unsigned WindowsThread::hardware_concurrency() {
  86. return std::thread::hardware_concurrency();
  87. }
  88. void WindowsThread::join() {
  89. if (!joinable()) {
  90. assert(false);
  91. throw std::system_error(
  92. std::make_error_code(std::errc::invalid_argument),
  93. "Thread is no longer joinable");
  94. }
  95. if (GetThreadId(GetCurrentThread()) == th_id_) {
  96. assert(false);
  97. throw std::system_error(
  98. std::make_error_code(std::errc::resource_deadlock_would_occur),
  99. "Can not join itself");
  100. }
  101. auto ret = WaitForSingleObject(reinterpret_cast<HANDLE>(data_->handle_),
  102. INFINITE);
  103. if (ret != WAIT_OBJECT_0) {
  104. auto lastError = GetLastError();
  105. assert(false);
  106. throw std::system_error(static_cast<int>(lastError),
  107. std::system_category(),
  108. "WaitForSingleObjectFailed: thread join");
  109. }
  110. BOOL rc
  111. #if defined(_MSC_VER)
  112. = FALSE;
  113. #else
  114. __attribute__((__unused__));
  115. #endif
  116. rc = CloseHandle(reinterpret_cast<HANDLE>(data_->handle_));
  117. assert(rc != 0);
  118. data_->handle_ = 0;
  119. }
  120. bool WindowsThread::detach() {
  121. if (!joinable()) {
  122. assert(false);
  123. throw std::system_error(
  124. std::make_error_code(std::errc::invalid_argument),
  125. "Thread is no longer available");
  126. }
  127. BOOL ret = CloseHandle(reinterpret_cast<HANDLE>(data_->handle_));
  128. data_->handle_ = 0;
  129. return (ret != 0);
  130. }
  131. void WindowsThread::swap(WindowsThread& o) {
  132. data_.swap(o.data_);
  133. std::swap(th_id_, o.th_id_);
  134. }
  135. unsigned int __stdcall WindowsThread::Data::ThreadProc(void* arg) {
  136. auto ptr = reinterpret_cast<std::shared_ptr<Data>*>(arg);
  137. std::unique_ptr<std::shared_ptr<Data>> data(ptr);
  138. (*data)->func_();
  139. return 0;
  140. }
  141. } // namespace port
  142. } // namespace ROCKSDB_NAMESPACE