/home/arjun/llvm-project/llvm/lib/Support/Unix/Threading.inc
Line | Count | Source (jump to first uncovered line) |
1 | | //===- Unix/Threading.inc - Unix Threading Implementation ----- -*- C++ -*-===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | // |
9 | | // This file provides the Unix specific implementation of Threading functions. |
10 | | // |
11 | | //===----------------------------------------------------------------------===// |
12 | | |
13 | | #include "Unix.h" |
14 | | #include "llvm/ADT/ScopeExit.h" |
15 | | #include "llvm/ADT/SmallString.h" |
16 | | #include "llvm/ADT/Twine.h" |
17 | | |
18 | | #if defined(__APPLE__) |
19 | | #include <mach/mach_init.h> |
20 | | #include <mach/mach_port.h> |
21 | | #endif |
22 | | |
23 | | #include <pthread.h> |
24 | | |
25 | | #if defined(__FreeBSD__) || defined(__OpenBSD__) |
26 | | #include <pthread_np.h> // For pthread_getthreadid_np() / pthread_set_name_np() |
27 | | #endif |
28 | | |
29 | | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
30 | | #include <errno.h> |
31 | | #include <sys/sysctl.h> |
32 | | #include <sys/user.h> |
33 | | #include <unistd.h> |
34 | | #endif |
35 | | |
36 | | #if defined(__NetBSD__) |
37 | | #include <lwp.h> // For _lwp_self() |
38 | | #endif |
39 | | |
40 | | #if defined(__linux__) |
41 | | #include <sched.h> // For sched_getaffinity |
42 | | #include <sys/syscall.h> // For syscall codes |
43 | | #include <unistd.h> // For syscall() |
44 | | #endif |
45 | | |
46 | 0 | static void *threadFuncSync(void *Arg) { |
47 | 0 | SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg); |
48 | 0 | TI->UserFn(TI->UserData); |
49 | 0 | return nullptr; |
50 | 0 | } |
51 | | |
52 | 0 | static void *threadFuncAsync(void *Arg) { |
53 | 0 | std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg)); |
54 | 0 | (*Info)(); |
55 | 0 | return nullptr; |
56 | 0 | } |
57 | | |
58 | | static void |
59 | | llvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg, |
60 | | llvm::Optional<unsigned> StackSizeInBytes, |
61 | 0 | JoiningPolicy JP) { |
62 | 0 | int errnum; |
63 | 0 |
|
64 | 0 | // Construct the attributes object. |
65 | 0 | pthread_attr_t Attr; |
66 | 0 | if ((errnum = ::pthread_attr_init(&Attr)) != 0) { |
67 | 0 | ReportErrnumFatal("pthread_attr_init failed", errnum); |
68 | 0 | } |
69 | 0 | |
70 | 0 | auto AttrGuard = llvm::make_scope_exit([&] { |
71 | 0 | if ((errnum = ::pthread_attr_destroy(&Attr)) != 0) { |
72 | 0 | ReportErrnumFatal("pthread_attr_destroy failed", errnum); |
73 | 0 | } |
74 | 0 | }); |
75 | 0 |
|
76 | 0 | // Set the requested stack size, if given. |
77 | 0 | if (StackSizeInBytes) { |
78 | 0 | if ((errnum = ::pthread_attr_setstacksize(&Attr, *StackSizeInBytes)) != 0) { |
79 | 0 | ReportErrnumFatal("pthread_attr_setstacksize failed", errnum); |
80 | 0 | } |
81 | 0 | } |
82 | 0 | |
83 | 0 | // Construct and execute the thread. |
84 | 0 | pthread_t Thread; |
85 | 0 | if ((errnum = ::pthread_create(&Thread, &Attr, ThreadFunc, Arg)) != 0) |
86 | 0 | ReportErrnumFatal("pthread_create failed", errnum); |
87 | 0 | |
88 | 0 | if (JP == JoiningPolicy::Join) { |
89 | 0 | // Wait for the thread |
90 | 0 | if ((errnum = ::pthread_join(Thread, nullptr)) != 0) { |
91 | 0 | ReportErrnumFatal("pthread_join failed", errnum); |
92 | 0 | } |
93 | 0 | } |
94 | 0 | } |
95 | | |
96 | 0 | uint64_t llvm::get_threadid() { |
97 | | #if defined(__APPLE__) |
98 | | // Calling "mach_thread_self()" bumps the reference count on the thread |
99 | | // port, so we need to deallocate it. mach_task_self() doesn't bump the ref |
100 | | // count. |
101 | | thread_port_t Self = mach_thread_self(); |
102 | | mach_port_deallocate(mach_task_self(), Self); |
103 | | return Self; |
104 | | #elif defined(__FreeBSD__) |
105 | | return uint64_t(pthread_getthreadid_np()); |
106 | | #elif defined(__NetBSD__) |
107 | | return uint64_t(_lwp_self()); |
108 | | #elif defined(__ANDROID__) |
109 | | return uint64_t(gettid()); |
110 | | #elif defined(__linux__) |
111 | | return uint64_t(syscall(SYS_gettid)); |
112 | | #else |
113 | | return uint64_t(pthread_self()); |
114 | | #endif |
115 | | } |
116 | | |
117 | | |
118 | 0 | static constexpr uint32_t get_max_thread_name_length_impl() { |
119 | | #if defined(__NetBSD__) |
120 | | return PTHREAD_MAX_NAMELEN_NP; |
121 | | #elif defined(__APPLE__) |
122 | | return 64; |
123 | | #elif defined(__linux__) |
124 | | #if HAVE_PTHREAD_SETNAME_NP |
125 | 0 | return 16; |
126 | | #else |
127 | | return 0; |
128 | | #endif |
129 | | #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
130 | | return 16; |
131 | | #elif defined(__OpenBSD__) |
132 | | return 32; |
133 | | #else |
134 | | return 0; |
135 | | #endif |
136 | | } |
137 | | |
138 | 0 | uint32_t llvm::get_max_thread_name_length() { |
139 | 0 | return get_max_thread_name_length_impl(); |
140 | 0 | } |
141 | | |
142 | 0 | void llvm::set_thread_name(const Twine &Name) { |
143 | 0 | // Make sure the input is null terminated. |
144 | 0 | SmallString<64> Storage; |
145 | 0 | StringRef NameStr = Name.toNullTerminatedStringRef(Storage); |
146 | 0 |
|
147 | 0 | // Truncate from the beginning, not the end, if the specified name is too |
148 | 0 | // long. For one, this ensures that the resulting string is still null |
149 | 0 | // terminated, but additionally the end of a long thread name will usually |
150 | 0 | // be more unique than the beginning, since a common pattern is for similar |
151 | 0 | // threads to share a common prefix. |
152 | 0 | // Note that the name length includes the null terminator. |
153 | 0 | if (get_max_thread_name_length() > 0) |
154 | 0 | NameStr = NameStr.take_back(get_max_thread_name_length() - 1); |
155 | 0 | (void)NameStr; |
156 | 0 | #if defined(__linux__) |
157 | 0 | #if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) |
158 | 0 | #if HAVE_PTHREAD_SETNAME_NP |
159 | 0 | ::pthread_setname_np(::pthread_self(), NameStr.data()); |
160 | 0 | #endif |
161 | 0 | #endif |
162 | | #elif defined(__FreeBSD__) || defined(__OpenBSD__) |
163 | | ::pthread_set_name_np(::pthread_self(), NameStr.data()); |
164 | | #elif defined(__NetBSD__) |
165 | | ::pthread_setname_np(::pthread_self(), "%s", |
166 | | const_cast<char *>(NameStr.data())); |
167 | | #elif defined(__APPLE__) |
168 | | ::pthread_setname_np(NameStr.data()); |
169 | | #endif |
170 | | } |
171 | | |
172 | 0 | void llvm::get_thread_name(SmallVectorImpl<char> &Name) { |
173 | 0 | Name.clear(); |
174 | 0 |
|
175 | | #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) |
176 | | int pid = ::getpid(); |
177 | | uint64_t tid = get_threadid(); |
178 | | |
179 | | struct kinfo_proc *kp = nullptr, *nkp; |
180 | | size_t len = 0; |
181 | | int error; |
182 | | int ctl[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, |
183 | | (int)pid }; |
184 | | |
185 | | while (1) { |
186 | | error = sysctl(ctl, 4, kp, &len, nullptr, 0); |
187 | | if (kp == nullptr || (error != 0 && errno == ENOMEM)) { |
188 | | // Add extra space in case threads are added before next call. |
189 | | len += sizeof(*kp) + len / 10; |
190 | | nkp = (struct kinfo_proc *)::realloc(kp, len); |
191 | | if (nkp == nullptr) { |
192 | | free(kp); |
193 | | return; |
194 | | } |
195 | | kp = nkp; |
196 | | continue; |
197 | | } |
198 | | if (error != 0) |
199 | | len = 0; |
200 | | break; |
201 | | } |
202 | | |
203 | | for (size_t i = 0; i < len / sizeof(*kp); i++) { |
204 | | if (kp[i].ki_tid == (lwpid_t)tid) { |
205 | | Name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname)); |
206 | | break; |
207 | | } |
208 | | } |
209 | | free(kp); |
210 | | return; |
211 | | #elif defined(__NetBSD__) |
212 | | constexpr uint32_t len = get_max_thread_name_length_impl(); |
213 | | char buf[len]; |
214 | | ::pthread_getname_np(::pthread_self(), buf, len); |
215 | | |
216 | | Name.append(buf, buf + strlen(buf)); |
217 | | #elif defined(__OpenBSD__) |
218 | | constexpr uint32_t len = get_max_thread_name_length_impl(); |
219 | | char buf[len]; |
220 | | ::pthread_get_name_np(::pthread_self(), buf, len); |
221 | | |
222 | | Name.append(buf, buf + strlen(buf)); |
223 | | #elif defined(__linux__) |
224 | | #if HAVE_PTHREAD_GETNAME_NP |
225 | 0 | constexpr uint32_t len = get_max_thread_name_length_impl(); |
226 | 0 | char Buffer[len] = {'\0'}; // FIXME: working around MSan false positive. |
227 | 0 | if (0 == ::pthread_getname_np(::pthread_self(), Buffer, len)) |
228 | 0 | Name.append(Buffer, Buffer + strlen(Buffer)); |
229 | 0 | #endif |
230 | 0 | #endif |
231 | 0 | } |
232 | | |
233 | 0 | SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) { |
234 | 0 | #if defined(__linux__) && defined(SCHED_IDLE) |
235 | 0 | // Some *really* old glibcs are missing SCHED_IDLE. |
236 | 0 | // http://man7.org/linux/man-pages/man3/pthread_setschedparam.3.html |
237 | 0 | // http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html |
238 | 0 | sched_param priority; |
239 | 0 | // For each of the above policies, param->sched_priority must be 0. |
240 | 0 | priority.sched_priority = 0; |
241 | 0 | // SCHED_IDLE for running very low priority background jobs. |
242 | 0 | // SCHED_OTHER the standard round-robin time-sharing policy; |
243 | 0 | return !pthread_setschedparam( |
244 | 0 | pthread_self(), |
245 | 0 | Priority == ThreadPriority::Background ? SCHED_IDLE : SCHED_OTHER, |
246 | 0 | &priority) |
247 | 0 | ? SetThreadPriorityResult::SUCCESS |
248 | 0 | : SetThreadPriorityResult::FAILURE; |
249 | | #elif defined(__APPLE__) |
250 | | // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getpriority.2.html |
251 | | // When setting a thread into background state the scheduling priority is set |
252 | | // to lowest value, disk and network IO are throttled. Network IO will be |
253 | | // throttled for any sockets the thread opens after going into background |
254 | | // state. Any previously opened sockets are not affected. |
255 | | |
256 | | // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/getiopolicy_np.3.html |
257 | | // I/Os with THROTTLE policy are called THROTTLE I/Os. If a THROTTLE I/O |
258 | | // request occurs within a small time window (usually a fraction of a second) |
259 | | // of another NORMAL I/O request, the thread that issues the THROTTLE I/O is |
260 | | // forced to sleep for a certain interval. This slows down the thread that |
261 | | // issues the THROTTLE I/O so that NORMAL I/Os can utilize most of the disk |
262 | | // I/O bandwidth. |
263 | | return !setpriority(PRIO_DARWIN_THREAD, 0, |
264 | | Priority == ThreadPriority::Background ? PRIO_DARWIN_BG |
265 | | : 0) |
266 | | ? SetThreadPriorityResult::SUCCESS |
267 | | : SetThreadPriorityResult::FAILURE; |
268 | | #endif |
269 | 0 | return SetThreadPriorityResult::FAILURE; |
270 | 0 | } |
271 | | |
272 | | #include <thread> |
273 | | |
274 | 0 | int computeHostNumHardwareThreads() { |
275 | 0 | #ifdef __linux__ |
276 | 0 | cpu_set_t Set; |
277 | 0 | if (sched_getaffinity(0, sizeof(Set), &Set) == 0) |
278 | 0 | return CPU_COUNT(&Set); |
279 | 0 | #endif |
280 | 0 | // Guard against std::thread::hardware_concurrency() returning 0. |
281 | 0 | if (unsigned Val = std::thread::hardware_concurrency()) |
282 | 0 | return Val; |
283 | 0 | return 1; |
284 | 0 | } |
285 | | |
286 | | void llvm::ThreadPoolStrategy::apply_thread_strategy( |
287 | 0 | unsigned ThreadPoolNum) const {} |
288 | | |
289 | 0 | llvm::BitVector llvm::get_thread_affinity_mask() { |
290 | 0 | // FIXME: Implement |
291 | 0 | llvm_unreachable("Not implemented!"); |
292 | 0 | } |
293 | | |
294 | 0 | unsigned llvm::get_cpus() { return 1; } |