]> git.proxmox.com Git - ceph.git/blob - ceph/src/rocksdb/port/win/win_thread.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / rocksdb / port / win / win_thread.cc
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
10 #if defined(OS_WIN)
11
12 #include "port/win/win_thread.h"
13
14 #include <assert.h>
15 #include <process.h> // __beginthreadex
16 #include <windows.h>
17
18 #include <stdexcept>
19 #include <system_error>
20 #include <thread>
21
22 namespace ROCKSDB_NAMESPACE {
23 namespace port {
24
25 struct WindowsThread::Data {
26
27 std::function<void()> func_;
28 uintptr_t handle_;
29
30 Data(std::function<void()>&& func) :
31 func_(std::move(func)),
32 handle_(0) {
33 }
34
35 Data(const Data&) = delete;
36 Data& operator=(const Data&) = delete;
37
38 static unsigned int __stdcall ThreadProc(void* arg);
39 };
40
41
42 void WindowsThread::Init(std::function<void()>&& func) {
43
44 data_ = std::make_shared<Data>(std::move(func));
45 // We create another instance of std::shared_ptr to get an additional ref
46 // since we may detach and destroy this instance before the threadproc
47 // may start to run. We choose to allocate this additional ref on the heap
48 // so we do not need to synchronize and allow this thread to proceed
49 std::unique_ptr<std::shared_ptr<Data>> th_data(new std::shared_ptr<Data>(data_));
50
51 data_->handle_ = _beginthreadex(NULL,
52 0, // stack size
53 &Data::ThreadProc,
54 th_data.get(),
55 0, // init flag
56 &th_id_);
57
58 if (data_->handle_ == 0) {
59 throw std::system_error(std::make_error_code(
60 std::errc::resource_unavailable_try_again),
61 "Unable to create a thread");
62 }
63 th_data.release();
64 }
65
66 WindowsThread::WindowsThread() :
67 data_(nullptr),
68 th_id_(0)
69 {}
70
71
72 WindowsThread::~WindowsThread() {
73 // Must be joined or detached
74 // before destruction.
75 // This is the same as std::thread
76 if (data_) {
77 if (joinable()) {
78 assert(false);
79 std::terminate();
80 }
81 data_.reset();
82 }
83 }
84
85 WindowsThread::WindowsThread(WindowsThread&& o) noexcept :
86 WindowsThread() {
87 *this = std::move(o);
88 }
89
90 WindowsThread& WindowsThread::operator=(WindowsThread&& o) noexcept {
91
92 if (joinable()) {
93 assert(false);
94 std::terminate();
95 }
96
97 data_ = std::move(o.data_);
98
99 // Per spec both instances will have the same id
100 th_id_ = o.th_id_;
101
102 return *this;
103 }
104
105 bool WindowsThread::joinable() const {
106 return (data_ && data_->handle_ != 0);
107 }
108
109 WindowsThread::native_handle_type WindowsThread::native_handle() const {
110 return reinterpret_cast<native_handle_type>(data_->handle_);
111 }
112
113 unsigned WindowsThread::hardware_concurrency() {
114 return std::thread::hardware_concurrency();
115 }
116
117 void WindowsThread::join() {
118
119 if (!joinable()) {
120 assert(false);
121 throw std::system_error(
122 std::make_error_code(std::errc::invalid_argument),
123 "Thread is no longer joinable");
124 }
125
126 if (GetThreadId(GetCurrentThread()) == th_id_) {
127 assert(false);
128 throw std::system_error(
129 std::make_error_code(std::errc::resource_deadlock_would_occur),
130 "Can not join itself");
131 }
132
133 auto ret = WaitForSingleObject(reinterpret_cast<HANDLE>(data_->handle_),
134 INFINITE);
135 if (ret != WAIT_OBJECT_0) {
136 auto lastError = GetLastError();
137 assert(false);
138 throw std::system_error(static_cast<int>(lastError),
139 std::system_category(),
140 "WaitForSingleObjectFailed: thread join");
141 }
142
143 BOOL rc
144 #if defined(_MSC_VER)
145 = FALSE;
146 #else
147 __attribute__((__unused__));
148 #endif
149 rc = CloseHandle(reinterpret_cast<HANDLE>(data_->handle_));
150 assert(rc != 0);
151 data_->handle_ = 0;
152 }
153
154 bool WindowsThread::detach() {
155
156 if (!joinable()) {
157 assert(false);
158 throw std::system_error(
159 std::make_error_code(std::errc::invalid_argument),
160 "Thread is no longer available");
161 }
162
163 BOOL ret = CloseHandle(reinterpret_cast<HANDLE>(data_->handle_));
164 data_->handle_ = 0;
165
166 return (ret != 0);
167 }
168
169 void WindowsThread::swap(WindowsThread& o) {
170 data_.swap(o.data_);
171 std::swap(th_id_, o.th_id_);
172 }
173
174 unsigned int __stdcall WindowsThread::Data::ThreadProc(void* arg) {
175 auto ptr = reinterpret_cast<std::shared_ptr<Data>*>(arg);
176 std::unique_ptr<std::shared_ptr<Data>> data(ptr);
177 (*data)->func_();
178 return 0;
179 }
180 } // namespace port
181 } // namespace ROCKSDB_NAMESPACE
182
183 #endif