blob: afb887fc10960f8155ff634f81574eb0d3a23569 [file] [log] [blame]
Zachary Turner757dbc92017-03-03 17:15:17 +00001//===- Unix/Threading.inc - Unix Threading Implementation ----- -*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Zachary Turner757dbc92017-03-03 17:15:17 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This file provides the Unix specific implementation of Threading functions.
10//
11//===----------------------------------------------------------------------===//
12
Sam McCalla9c3c172019-10-23 15:34:48 +020013#include "Unix.h"
14#include "llvm/ADT/ScopeExit.h"
Zachary Turner757dbc92017-03-03 17:15:17 +000015#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
Brad Smith8c17d592018-06-23 22:02:59 +000025#if defined(__FreeBSD__) || defined(__OpenBSD__)
26#include <pthread_np.h> // For pthread_getthreadid_np() / pthread_set_name_np()
Zachary Turnerd9738132017-03-03 18:38:22 +000027#endif
28
29#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
Chandler Carruth6bda14b2017-06-06 11:49:48 +000030#include <errno.h>
Kamil Rytarowski71efce22017-03-04 17:42:46 +000031#include <sys/sysctl.h>
32#include <sys/user.h>
Zachary Turnerd9738132017-03-03 18:38:22 +000033#include <unistd.h>
Zachary Turner757dbc92017-03-03 17:15:17 +000034#endif
35
36#if defined(__NetBSD__)
Chandler Carruth6bda14b2017-06-06 11:49:48 +000037#include <lwp.h> // For _lwp_self()
Zachary Turner757dbc92017-03-03 17:15:17 +000038#endif
39
40#if defined(__linux__)
Chandler Carruth6bda14b2017-06-06 11:49:48 +000041#include <sys/syscall.h> // For syscall codes
42#include <unistd.h> // For syscall()
Zachary Turner757dbc92017-03-03 17:15:17 +000043#endif
44
Sam McCalla9c3c172019-10-23 15:34:48 +020045static void *threadFuncSync(void *Arg) {
46 SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg);
Zachary Turner757dbc92017-03-03 17:15:17 +000047 TI->UserFn(TI->UserData);
48 return nullptr;
49}
50
Sam McCalla9c3c172019-10-23 15:34:48 +020051static void *threadFuncAsync(void *Arg) {
52 std::unique_ptr<AsyncThreadInfo> Info(static_cast<AsyncThreadInfo *>(Arg));
53 (*Info)();
54 return nullptr;
55}
56
57static void
58llvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg,
59 llvm::Optional<unsigned> StackSizeInBytes,
60 JoiningPolicy JP) {
61 int errnum;
Zachary Turner757dbc92017-03-03 17:15:17 +000062
63 // Construct the attributes object.
Sam McCalla9c3c172019-10-23 15:34:48 +020064 pthread_attr_t Attr;
65 if ((errnum = ::pthread_attr_init(&Attr)) != 0) {
66 ReportErrnumFatal("pthread_attr_init failed", errnum);
67 }
68
69 auto AttrGuard = llvm::make_scope_exit([&] {
70 if ((errnum = ::pthread_attr_destroy(&Attr)) != 0) {
71 ReportErrnumFatal("pthread_attr_destroy failed", errnum);
72 }
73 });
Zachary Turner757dbc92017-03-03 17:15:17 +000074
75 // Set the requested stack size, if given.
Sam McCalla9c3c172019-10-23 15:34:48 +020076 if (StackSizeInBytes) {
77 if ((errnum = ::pthread_attr_setstacksize(&Attr, *StackSizeInBytes)) != 0) {
78 ReportErrnumFatal("pthread_attr_setstacksize failed", errnum);
79 }
Zachary Turner757dbc92017-03-03 17:15:17 +000080 }
81
82 // Construct and execute the thread.
Sam McCalla9c3c172019-10-23 15:34:48 +020083 pthread_t Thread;
84 if ((errnum = ::pthread_create(&Thread, &Attr, ThreadFunc, Arg)) != 0)
85 ReportErrnumFatal("pthread_create failed", errnum);
Zachary Turner757dbc92017-03-03 17:15:17 +000086
Sam McCalla9c3c172019-10-23 15:34:48 +020087 if (JP == JoiningPolicy::Join) {
88 // Wait for the thread
89 if ((errnum = ::pthread_join(Thread, nullptr)) != 0) {
90 ReportErrnumFatal("pthread_join failed", errnum);
91 }
92 }
Zachary Turner757dbc92017-03-03 17:15:17 +000093}
94
Zachary Turner757dbc92017-03-03 17:15:17 +000095uint64_t llvm::get_threadid() {
96#if defined(__APPLE__)
97 // Calling "mach_thread_self()" bumps the reference count on the thread
98 // port, so we need to deallocate it. mach_task_self() doesn't bump the ref
99 // count.
100 thread_port_t Self = mach_thread_self();
101 mach_port_deallocate(mach_task_self(), Self);
102 return Self;
103#elif defined(__FreeBSD__)
104 return uint64_t(pthread_getthreadid_np());
105#elif defined(__NetBSD__)
106 return uint64_t(_lwp_self());
107#elif defined(__ANDROID__)
108 return uint64_t(gettid());
109#elif defined(__linux__)
110 return uint64_t(syscall(SYS_gettid));
Zachary Turner757dbc92017-03-03 17:15:17 +0000111#else
112 return uint64_t(pthread_self());
113#endif
114}
115
116
Zachary Turner1f004c42017-03-04 18:53:09 +0000117static constexpr uint32_t get_max_thread_name_length_impl() {
Zachary Turner777de772017-03-04 16:42:25 +0000118#if defined(__NetBSD__)
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +0000119 return PTHREAD_MAX_NAMELEN_NP;
Zachary Turner777de772017-03-04 16:42:25 +0000120#elif defined(__APPLE__)
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +0000121 return 64;
Zachary Turner777de772017-03-04 16:42:25 +0000122#elif defined(__linux__)
123#if HAVE_PTHREAD_SETNAME_NP
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +0000124 return 16;
Zachary Turner777de772017-03-04 16:42:25 +0000125#else
NAKAMURA Takumia1e97a72017-08-28 06:47:47 +0000126 return 0;
Zachary Turner777de772017-03-04 16:42:25 +0000127#endif
128#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
129 return 16;
Brad Smith8c17d592018-06-23 22:02:59 +0000130#elif defined(__OpenBSD__)
131 return 32;
Zachary Turner777de772017-03-04 16:42:25 +0000132#else
133 return 0;
134#endif
135}
136
Zachary Turner1f004c42017-03-04 18:53:09 +0000137uint32_t llvm::get_max_thread_name_length() {
138 return get_max_thread_name_length_impl();
139}
140
Zachary Turner757dbc92017-03-03 17:15:17 +0000141void llvm::set_thread_name(const Twine &Name) {
142 // Make sure the input is null terminated.
143 SmallString<64> Storage;
144 StringRef NameStr = Name.toNullTerminatedStringRef(Storage);
Zachary Turner777de772017-03-04 16:42:25 +0000145
146 // Truncate from the beginning, not the end, if the specified name is too
147 // long. For one, this ensures that the resulting string is still null
148 // terminated, but additionally the end of a long thread name will usually
149 // be more unique than the beginning, since a common pattern is for similar
150 // threads to share a common prefix.
Sam McCall63580642018-02-13 23:23:59 +0000151 // Note that the name length includes the null terminator.
Zachary Turner1f004c42017-03-04 18:53:09 +0000152 if (get_max_thread_name_length() > 0)
Sam McCall63580642018-02-13 23:23:59 +0000153 NameStr = NameStr.take_back(get_max_thread_name_length() - 1);
Krzysztof Parzyszek75464e12017-03-03 22:21:02 +0000154 (void)NameStr;
Zachary Turner757dbc92017-03-03 17:15:17 +0000155#if defined(__linux__)
156#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__)
Krzysztof Parzyszek6cf25402017-03-03 21:53:12 +0000157#if HAVE_PTHREAD_SETNAME_NP
Zachary Turner757dbc92017-03-03 17:15:17 +0000158 ::pthread_setname_np(::pthread_self(), NameStr.data());
159#endif
Krzysztof Parzyszek6cf25402017-03-03 21:53:12 +0000160#endif
Brad Smith8c17d592018-06-23 22:02:59 +0000161#elif defined(__FreeBSD__) || defined(__OpenBSD__)
Zachary Turner757dbc92017-03-03 17:15:17 +0000162 ::pthread_set_name_np(::pthread_self(), NameStr.data());
163#elif defined(__NetBSD__)
164 ::pthread_setname_np(::pthread_self(), "%s",
165 const_cast<char *>(NameStr.data()));
166#elif defined(__APPLE__)
167 ::pthread_setname_np(NameStr.data());
168#endif
169}
170
171void llvm::get_thread_name(SmallVectorImpl<char> &Name) {
172 Name.clear();
173
174#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
Zachary Turner45337cf2017-03-03 18:21:04 +0000175 int pid = ::getpid();
176 uint64_t tid = get_threadid();
Zachary Turner757dbc92017-03-03 17:15:17 +0000177
178 struct kinfo_proc *kp = nullptr, *nkp;
179 size_t len = 0;
180 int error;
181 int ctl[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
182 (int)pid };
183
184 while (1) {
185 error = sysctl(ctl, 4, kp, &len, nullptr, 0);
186 if (kp == nullptr || (error != 0 && errno == ENOMEM)) {
187 // Add extra space in case threads are added before next call.
188 len += sizeof(*kp) + len / 10;
Serge Pavlovce719a02018-02-15 09:35:36 +0000189 nkp = (struct kinfo_proc *)::realloc(kp, len);
Zachary Turner757dbc92017-03-03 17:15:17 +0000190 if (nkp == nullptr) {
191 free(kp);
192 return;
193 }
194 kp = nkp;
195 continue;
196 }
197 if (error != 0)
198 len = 0;
199 break;
200 }
201
202 for (size_t i = 0; i < len / sizeof(*kp); i++) {
203 if (kp[i].ki_tid == (lwpid_t)tid) {
204 Name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname));
205 break;
206 }
207 }
208 free(kp);
209 return;
210#elif defined(__NetBSD__)
Zachary Turner1f004c42017-03-04 18:53:09 +0000211 constexpr uint32_t len = get_max_thread_name_length_impl();
212 char buf[len];
213 ::pthread_getname_np(::pthread_self(), buf, len);
Zachary Turner757dbc92017-03-03 17:15:17 +0000214
215 Name.append(buf, buf + strlen(buf));
Brad Smith01227fe2019-02-07 02:06:58 +0000216#elif defined(__OpenBSD__)
217 constexpr uint32_t len = get_max_thread_name_length_impl();
218 char buf[len];
219 ::pthread_get_name_np(::pthread_self(), buf, len);
220
221 Name.append(buf, buf + strlen(buf));
Zachary Turner757dbc92017-03-03 17:15:17 +0000222#elif defined(__linux__)
Krzysztof Parzyszek6cf25402017-03-03 21:53:12 +0000223#if HAVE_PTHREAD_GETNAME_NP
Zachary Turner1f004c42017-03-04 18:53:09 +0000224 constexpr uint32_t len = get_max_thread_name_length_impl();
Sam McCall0e142492017-11-02 12:29:47 +0000225 char Buffer[len] = {'\0'}; // FIXME: working around MSan false positive.
Zachary Turner1f004c42017-03-04 18:53:09 +0000226 if (0 == ::pthread_getname_np(::pthread_self(), Buffer, len))
Zachary Turner757dbc92017-03-03 17:15:17 +0000227 Name.append(Buffer, Buffer + strlen(Buffer));
228#endif
229#endif
Zachary Turner757dbc92017-03-03 17:15:17 +0000230}
Kadir Cetinkaya8fdc5ab2019-04-16 14:32:43 +0000231
232SetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
233#if defined(__linux__) && defined(SCHED_IDLE)
234 // Some *really* old glibcs are missing SCHED_IDLE.
235 // http://man7.org/linux/man-pages/man3/pthread_setschedparam.3.html
236 // http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html
237 sched_param priority;
238 // For each of the above policies, param->sched_priority must be 0.
239 priority.sched_priority = 0;
240 // SCHED_IDLE for running very low priority background jobs.
241 // SCHED_OTHER the standard round-robin time-sharing policy;
242 return !pthread_setschedparam(
243 pthread_self(),
244 Priority == ThreadPriority::Background ? SCHED_IDLE : SCHED_OTHER,
245 &priority)
246 ? SetThreadPriorityResult::SUCCESS
247 : SetThreadPriorityResult::FAILURE;
248#elif defined(__APPLE__)
249 // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/getpriority.2.html
250 // When setting a thread into background state the scheduling priority is set
251 // to lowest value, disk and network IO are throttled. Network IO will be
252 // throttled for any sockets the thread opens after going into background
253 // state. Any previously opened sockets are not affected.
254
255 // https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/getiopolicy_np.3.html
256 // I/Os with THROTTLE policy are called THROTTLE I/Os. If a THROTTLE I/O
257 // request occurs within a small time window (usually a fraction of a second)
258 // of another NORMAL I/O request, the thread that issues the THROTTLE I/O is
259 // forced to sleep for a certain interval. This slows down the thread that
260 // issues the THROTTLE I/O so that NORMAL I/Os can utilize most of the disk
261 // I/O bandwidth.
262 return !setpriority(PRIO_DARWIN_THREAD, 0,
263 Priority == ThreadPriority::Background ? PRIO_DARWIN_BG
264 : 0)
265 ? SetThreadPriorityResult::SUCCESS
266 : SetThreadPriorityResult::FAILURE;
267#endif
268 return SetThreadPriorityResult::FAILURE;
269}