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.
10 #include "port/win/win_thread.h"
13 #include <process.h> // __beginthreadex
17 #include <system_error>
23 struct WindowsThread::Data
{
25 std::function
<void()> func_
;
28 Data(std::function
<void()>&& func
) :
29 func_(std::move(func
)),
33 Data(const Data
&) = delete;
34 Data
& operator=(const Data
&) = delete;
36 static unsigned int __stdcall
ThreadProc(void* arg
);
40 void WindowsThread::Init(std::function
<void()>&& func
) {
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_
));
49 data_
->handle_
= _beginthreadex(NULL
,
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");
64 WindowsThread::WindowsThread() :
70 WindowsThread::~WindowsThread() {
71 // Must be joined or detached
72 // before destruction.
73 // This is the same as std::thread
83 WindowsThread::WindowsThread(WindowsThread
&& o
) noexcept
:
88 WindowsThread
& WindowsThread::operator=(WindowsThread
&& o
) noexcept
{
95 data_
= std::move(o
.data_
);
97 // Per spec both instances will have the same id
103 bool WindowsThread::joinable() const {
104 return (data_
&& data_
->handle_
!= 0);
107 WindowsThread::native_handle_type
WindowsThread::native_handle() const {
108 return reinterpret_cast<native_handle_type
>(data_
->handle_
);
111 unsigned WindowsThread::hardware_concurrency() {
112 return std::thread::hardware_concurrency();
115 void WindowsThread::join() {
119 throw std::system_error(
120 std::make_error_code(std::errc::invalid_argument
),
121 "Thread is no longer joinable");
124 if (GetThreadId(GetCurrentThread()) == th_id_
) {
126 throw std::system_error(
127 std::make_error_code(std::errc::resource_deadlock_would_occur
),
128 "Can not join itself");
131 auto ret
= WaitForSingleObject(reinterpret_cast<HANDLE
>(data_
->handle_
),
133 if (ret
!= WAIT_OBJECT_0
) {
134 auto lastError
= GetLastError();
136 throw std::system_error(static_cast<int>(lastError
),
137 std::system_category(),
138 "WaitForSingleObjectFailed: thread join");
142 rc
= CloseHandle(reinterpret_cast<HANDLE
>(data_
->handle_
));
147 bool WindowsThread::detach() {
151 throw std::system_error(
152 std::make_error_code(std::errc::invalid_argument
),
153 "Thread is no longer available");
156 BOOL ret
= CloseHandle(reinterpret_cast<HANDLE
>(data_
->handle_
));
162 void WindowsThread::swap(WindowsThread
& o
) {
164 std::swap(th_id_
, o
.th_id_
);
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
);
174 } // namespace rocksdb