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