1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
|
//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2025
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#pragma once
#include "td/utils/port/config.h"
#ifdef TD_THREAD_STL
#include "td/utils/common.h"
#include "td/utils/invoke.h"
#if TD_WINDOWS && TD_MSVC
#include "td/utils/port/detail/NativeFd.h"
#endif
#include "td/utils/port/detail/ThreadIdGuard.h"
#include "td/utils/port/thread_local.h"
#include "td/utils/Slice.h"
#include "td/utils/Status.h"
#include <thread>
#include <tuple>
#include <type_traits>
#include <utility>
#if TD_WINDOWS && TD_MSVC
#define TD_HAVE_THREAD_AFFINITY 1
#endif
namespace td {
namespace detail {
class ThreadStl {
public:
ThreadStl() = default;
ThreadStl(const ThreadStl &) = delete;
ThreadStl &operator=(const ThreadStl &) = delete;
ThreadStl(ThreadStl &&) = default;
ThreadStl &operator=(ThreadStl &&) = default;
~ThreadStl() {
join();
}
template <class Function, class... Args>
explicit ThreadStl(Function &&f, Args &&...args) {
thread_ = std::thread([args = std::make_tuple(decay_copy(std::forward<Function>(f)),
decay_copy(std::forward<Args>(args))...)]() mutable {
ThreadIdGuard thread_id_guard;
invoke_tuple(std::move(args));
clear_thread_locals();
});
}
void join() {
if (thread_.joinable()) {
thread_.join();
}
}
void detach() {
if (thread_.joinable()) {
thread_.detach();
}
}
void set_name(CSlice name) {
// not supported
}
static unsigned hardware_concurrency() {
return std::thread::hardware_concurrency();
}
#if TD_WINDOWS && TD_MSVC
using id = DWORD;
#else
using id = std::thread::id;
#endif
id get_id() noexcept {
#if TD_WINDOWS && TD_MSVC
static_assert(std::is_same<decltype(thread_.native_handle()), HANDLE>::value,
"Expected HANDLE as native thread type");
return GetThreadId(thread_.native_handle());
#else
return thread_.get_id();
#endif
}
static void send_real_time_signal(id thread_id, int real_time_signal_number) {
// not supported
}
#if TD_HAVE_THREAD_AFFINITY
static Status set_affinity_mask(id thread_id, uint64 mask) {
if (static_cast<DWORD_PTR>(mask) != mask) {
return Status::Error("Invalid thread affinity mask specified");
}
auto handle = OpenThread(THREAD_SET_LIMITED_INFORMATION | THREAD_QUERY_LIMITED_INFORMATION, FALSE, thread_id);
if (handle == nullptr) {
return Status::Error("Failed to access thread");
}
NativeFd thread_handle(handle);
if (SetThreadAffinityMask(thread_handle.fd(), static_cast<DWORD_PTR>(mask))) {
return Status::OK();
}
return OS_ERROR("Failed to set thread affinity mask");
}
static uint64 get_affinity_mask(id thread_id) {
DWORD_PTR process_mask = 0;
DWORD_PTR system_mask = 0;
if (GetProcessAffinityMask(GetCurrentProcess(), &process_mask, &system_mask)) {
auto handle = OpenThread(THREAD_SET_LIMITED_INFORMATION | THREAD_QUERY_LIMITED_INFORMATION, FALSE, thread_id);
if (handle == nullptr) {
return 0;
}
NativeFd thread_handle(handle);
auto result = SetThreadAffinityMask(thread_handle.fd(), process_mask);
if (result != 0 && result != process_mask) {
SetThreadAffinityMask(thread_handle.fd(), result);
}
return result;
}
return 0;
}
#endif
private:
std::thread thread_;
template <class T>
std::decay_t<T> decay_copy(T &&v) {
return std::forward<T>(v);
}
};
namespace this_thread_stl {
#if TD_WINDOWS && TD_MSVC
inline ThreadStl::id get_id() {
return GetCurrentThreadId();
}
#else
using std::this_thread::get_id;
#endif
} // namespace this_thread_stl
} // namespace detail
} // namespace td
#endif
|