Threading.inc revision 360784
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 <sys/syscall.h> // For syscall codes
42#include <unistd.h>      // For syscall()
43#endif
44
45static void *threadFuncSync(void *Arg) {
46  SyncThreadInfo *TI = static_cast<SyncThreadInfo *>(Arg);
47  TI->UserFn(TI->UserData);
48  return nullptr;
49}
50
51static 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;
62
63  // Construct the attributes object.
64  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  });
74
75  // Set the requested stack size, if given.
76  if (StackSizeInBytes) {
77    if ((errnum = ::pthread_attr_setstacksize(&Attr, *StackSizeInBytes)) != 0) {
78      ReportErrnumFatal("pthread_attr_setstacksize failed", errnum);
79    }
80  }
81
82  // Construct and execute the thread.
83  pthread_t Thread;
84  if ((errnum = ::pthread_create(&Thread, &Attr, ThreadFunc, Arg)) != 0)
85    ReportErrnumFatal("pthread_create failed", errnum);
86
87  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  }
93}
94
95uint64_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));
111#else
112  return uint64_t(pthread_self());
113#endif
114}
115
116
117static constexpr uint32_t get_max_thread_name_length_impl() {
118#if defined(__NetBSD__)
119  return PTHREAD_MAX_NAMELEN_NP;
120#elif defined(__APPLE__)
121  return 64;
122#elif defined(__linux__)
123#if HAVE_PTHREAD_SETNAME_NP
124  return 16;
125#else
126  return 0;
127#endif
128#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
129  return 16;
130#elif defined(__OpenBSD__)
131  return 32;
132#else
133  return 0;
134#endif
135}
136
137uint32_t llvm::get_max_thread_name_length() {
138  return get_max_thread_name_length_impl();
139}
140
141void 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);
145
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.
151  // Note that the name length includes the null terminator.
152  if (get_max_thread_name_length() > 0)
153    NameStr = NameStr.take_back(get_max_thread_name_length() - 1);
154  (void)NameStr;
155#if defined(__linux__)
156#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__)
157#if HAVE_PTHREAD_SETNAME_NP
158  ::pthread_setname_np(::pthread_self(), NameStr.data());
159#endif
160#endif
161#elif defined(__FreeBSD__) || defined(__OpenBSD__)
162  ::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__)
175  int pid = ::getpid();
176  uint64_t tid = get_threadid();
177
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;
189      nkp = (struct kinfo_proc *)::realloc(kp, len);
190      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__)
211  constexpr uint32_t len = get_max_thread_name_length_impl();
212  char buf[len];
213  ::pthread_getname_np(::pthread_self(), buf, len);
214
215  Name.append(buf, buf + strlen(buf));
216#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));
222#elif defined(__linux__)
223#if HAVE_PTHREAD_GETNAME_NP
224  constexpr uint32_t len = get_max_thread_name_length_impl();
225  char Buffer[len] = {'\0'};  // FIXME: working around MSan false positive.
226  if (0 == ::pthread_getname_np(::pthread_self(), Buffer, len))
227    Name.append(Buffer, Buffer + strlen(Buffer));
228#endif
229#endif
230}
231
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}
270