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).
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.
12 #include "port/win/win_thread.h"
15 #include <process.h> // __beginthreadex
19 #include <system_error>
22 namespace ROCKSDB_NAMESPACE
{
25 struct WindowsThread::Data
{
27 std::function
<void()> func_
;
30 Data(std::function
<void()>&& func
) :
31 func_(std::move(func
)),
35 Data(const Data
&) = delete;
36 Data
& operator=(const Data
&) = delete;
38 static unsigned int __stdcall
ThreadProc(void* arg
);
42 void WindowsThread::Init(std::function
<void()>&& func
) {
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_
));
51 data_
->handle_
= _beginthreadex(NULL
,
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");
66 WindowsThread::WindowsThread() :
72 WindowsThread::~WindowsThread() {
73 // Must be joined or detached
74 // before destruction.
75 // This is the same as std::thread
85 WindowsThread::WindowsThread(WindowsThread
&& o
) noexcept
:
90 WindowsThread
& WindowsThread::operator=(WindowsThread
&& o
) noexcept
{
97 data_
= std::move(o
.data_
);
99 // Per spec both instances will have the same id
105 bool WindowsThread::joinable() const {
106 return (data_
&& data_
->handle_
!= 0);
109 WindowsThread::native_handle_type
WindowsThread::native_handle() const {
110 return reinterpret_cast<native_handle_type
>(data_
->handle_
);
113 unsigned WindowsThread::hardware_concurrency() {
114 return std::thread::hardware_concurrency();
117 void WindowsThread::join() {
121 throw std::system_error(
122 std::make_error_code(std::errc::invalid_argument
),
123 "Thread is no longer joinable");
126 if (GetThreadId(GetCurrentThread()) == th_id_
) {
128 throw std::system_error(
129 std::make_error_code(std::errc::resource_deadlock_would_occur
),
130 "Can not join itself");
133 auto ret
= WaitForSingleObject(reinterpret_cast<HANDLE
>(data_
->handle_
),
135 if (ret
!= WAIT_OBJECT_0
) {
136 auto lastError
= GetLastError();
138 throw std::system_error(static_cast<int>(lastError
),
139 std::system_category(),
140 "WaitForSingleObjectFailed: thread join");
144 #if defined(_MSC_VER)
147 __attribute__((__unused__
));
149 rc
= CloseHandle(reinterpret_cast<HANDLE
>(data_
->handle_
));
154 bool WindowsThread::detach() {
158 throw std::system_error(
159 std::make_error_code(std::errc::invalid_argument
),
160 "Thread is no longer available");
163 BOOL ret
= CloseHandle(reinterpret_cast<HANDLE
>(data_
->handle_
));
169 void WindowsThread::swap(WindowsThread
& o
) {
171 std::swap(th_id_
, o
.th_id_
);
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
);
181 } // namespace ROCKSDB_NAMESPACE