1757dbc9fSZachary Turner//===- Unix/Threading.inc - Unix Threading Implementation ----- -*- C++ -*-===//
2757dbc9fSZachary Turner//
32946cd70SChandler Carruth// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth// See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6757dbc9fSZachary Turner//
7757dbc9fSZachary Turner//===----------------------------------------------------------------------===//
8757dbc9fSZachary Turner//
9757dbc9fSZachary Turner// This file provides the Unix specific implementation of Threading functions.
10757dbc9fSZachary Turner//
11757dbc9fSZachary Turner//===----------------------------------------------------------------------===//
12757dbc9fSZachary Turner
13a9c3c176SSam McCall#include "Unix.h"
14a9c3c176SSam McCall#include "llvm/ADT/ScopeExit.h"
15757dbc9fSZachary Turner#include "llvm/ADT/SmallString.h"
16757dbc9fSZachary Turner#include "llvm/ADT/Twine.h"
17757dbc9fSZachary Turner
18757dbc9fSZachary Turner#if defined(__APPLE__)
19757dbc9fSZachary Turner#include <mach/mach_init.h>
20757dbc9fSZachary Turner#include <mach/mach_port.h>
21*9902a094Sstk#include <pthread/qos.h>
22757dbc9fSZachary Turner#endif
23757dbc9fSZachary Turner
24757dbc9fSZachary Turner#include <pthread.h>
25757dbc9fSZachary Turner
268c17d592SBrad Smith#if defined(__FreeBSD__) || defined(__OpenBSD__)
278c17d592SBrad Smith#include <pthread_np.h> // For pthread_getthreadid_np() / pthread_set_name_np()
28d9738136SZachary Turner#endif
29d9738136SZachary Turner
30d9738136SZachary Turner#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
316bda14b3SChandler Carruth#include <errno.h>
32d989ffd1SDimitry Andric#include <sys/cpuset.h>
3371efce23SKamil Rytarowski#include <sys/sysctl.h>
3471efce23SKamil Rytarowski#include <sys/user.h>
35d9738136SZachary Turner#include <unistd.h>
36757dbc9fSZachary Turner#endif
37757dbc9fSZachary Turner
38757dbc9fSZachary Turner#if defined(__NetBSD__)
39d9738136SZachary Turner#include <lwp.h> // For _lwp_self()
40757dbc9fSZachary Turner#endif
41757dbc9fSZachary Turner
4266b7ba52SBrad Smith#if defined(__OpenBSD__)
4366b7ba52SBrad Smith#include <unistd.h> // For getthrid()
4466b7ba52SBrad Smith#endif
4566b7ba52SBrad Smith
46757dbc9fSZachary Turner#if defined(__linux__)
47041a3557SFangrui Song#include <sched.h>       // For sched_getaffinity
48d9738136SZachary Turner#include <sys/syscall.h> // For syscall codes
496bda14b3SChandler Carruth#include <unistd.h>      // For syscall()
50757dbc9fSZachary Turner#endif
51757dbc9fSZachary Turner
520c39f82fSTim Northovernamespace llvm {
5348c68a63STim Northoverpthread_t
540c39f82fSTim Northoverllvm_execute_on_thread_impl(void *(*ThreadFunc)(void *), void *Arg,
5548c68a63STim Northover                            llvm::Optional<unsigned> StackSizeInBytes) {
56a9c3c176SSam McCall  int errnum;
57757dbc9fSZachary Turner
58757dbc9fSZachary Turner  // Construct the attributes object.
59a9c3c176SSam McCall  pthread_attr_t Attr;
60a9c3c176SSam McCall  if ((errnum = ::pthread_attr_init(&Attr)) != 0) {
61a9c3c176SSam McCall    ReportErrnumFatal("pthread_attr_init failed", errnum);
62a9c3c176SSam McCall  }
63a9c3c176SSam McCall
64a9c3c176SSam McCall  auto AttrGuard = llvm::make_scope_exit([&] {
65a9c3c176SSam McCall    if ((errnum = ::pthread_attr_destroy(&Attr)) != 0) {
66a9c3c176SSam McCall      ReportErrnumFatal("pthread_attr_destroy failed", errnum);
67a9c3c176SSam McCall    }
68a9c3c176SSam McCall  });
69757dbc9fSZachary Turner
70757dbc9fSZachary Turner  // Set the requested stack size, if given.
71a9c3c176SSam McCall  if (StackSizeInBytes) {
72a9c3c176SSam McCall    if ((errnum = ::pthread_attr_setstacksize(&Attr, *StackSizeInBytes)) != 0) {
73a9c3c176SSam McCall      ReportErrnumFatal("pthread_attr_setstacksize failed", errnum);
74a9c3c176SSam McCall    }
75757dbc9fSZachary Turner  }
76757dbc9fSZachary Turner
77757dbc9fSZachary Turner  // Construct and execute the thread.
78a9c3c176SSam McCall  pthread_t Thread;
79a9c3c176SSam McCall  if ((errnum = ::pthread_create(&Thread, &Attr, ThreadFunc, Arg)) != 0)
80a9c3c176SSam McCall    ReportErrnumFatal("pthread_create failed", errnum);
81757dbc9fSZachary Turner
8248c68a63STim Northover  return Thread;
83757dbc9fSZachary Turner}
8448c68a63STim Northover
850c39f82fSTim Northovervoid llvm_thread_detach_impl(pthread_t Thread) {
8648c68a63STim Northover  int errnum;
8748c68a63STim Northover
88e0968ad4SNathan James  if ((errnum = ::pthread_detach(Thread)) != 0) {
89e0968ad4SNathan James    ReportErrnumFatal("pthread_detach failed", errnum);
90e0968ad4SNathan James  }
91a9c3c176SSam McCall}
9248c68a63STim Northover
930c39f82fSTim Northovervoid llvm_thread_join_impl(pthread_t Thread) {
9448c68a63STim Northover  int errnum;
9548c68a63STim Northover
9648c68a63STim Northover  if ((errnum = ::pthread_join(Thread, nullptr)) != 0) {
9748c68a63STim Northover    ReportErrnumFatal("pthread_join failed", errnum);
9848c68a63STim Northover  }
9948c68a63STim Northover}
10048c68a63STim Northover
1010c39f82fSTim Northoverpthread_t llvm_thread_get_id_impl(pthread_t Thread) {
10248c68a63STim Northover  return Thread;
10348c68a63STim Northover}
10448c68a63STim Northover
1050c39f82fSTim Northoverpthread_t llvm_thread_get_current_id_impl() {
10648c68a63STim Northover  return ::pthread_self();
107a9c3c176SSam McCall}
108757dbc9fSZachary Turner
1090c39f82fSTim Northover} // namespace llvm
1100c39f82fSTim Northover
111757dbc9fSZachary Turneruint64_t llvm::get_threadid() {
112757dbc9fSZachary Turner#if defined(__APPLE__)
113757dbc9fSZachary Turner  // Calling "mach_thread_self()" bumps the reference count on the thread
114757dbc9fSZachary Turner  // port, so we need to deallocate it. mach_task_self() doesn't bump the ref
115757dbc9fSZachary Turner  // count.
116757dbc9fSZachary Turner  thread_port_t Self = mach_thread_self();
117757dbc9fSZachary Turner  mach_port_deallocate(mach_task_self(), Self);
118757dbc9fSZachary Turner  return Self;
119757dbc9fSZachary Turner#elif defined(__FreeBSD__)
120757dbc9fSZachary Turner  return uint64_t(pthread_getthreadid_np());
121757dbc9fSZachary Turner#elif defined(__NetBSD__)
122757dbc9fSZachary Turner  return uint64_t(_lwp_self());
12366b7ba52SBrad Smith#elif defined(__OpenBSD__)
12466b7ba52SBrad Smith  return uint64_t(getthrid());
125757dbc9fSZachary Turner#elif defined(__ANDROID__)
126757dbc9fSZachary Turner  return uint64_t(gettid());
127757dbc9fSZachary Turner#elif defined(__linux__)
128757dbc9fSZachary Turner  return uint64_t(syscall(SYS_gettid));
129757dbc9fSZachary Turner#else
130757dbc9fSZachary Turner  return uint64_t(pthread_self());
131757dbc9fSZachary Turner#endif
132757dbc9fSZachary Turner}
133757dbc9fSZachary Turner
134757dbc9fSZachary Turner
1351f004c43SZachary Turnerstatic constexpr uint32_t get_max_thread_name_length_impl() {
136777de779SZachary Turner#if defined(__NetBSD__)
137777de779SZachary Turner  return PTHREAD_MAX_NAMELEN_NP;
138777de779SZachary Turner#elif defined(__APPLE__)
139777de779SZachary Turner  return 64;
140777de779SZachary Turner#elif defined(__linux__)
141777de779SZachary Turner#if HAVE_PTHREAD_SETNAME_NP
142777de779SZachary Turner  return 16;
143777de779SZachary Turner#else
144777de779SZachary Turner  return 0;
145777de779SZachary Turner#endif
146777de779SZachary Turner#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
147777de779SZachary Turner  return 16;
1488c17d592SBrad Smith#elif defined(__OpenBSD__)
1498c17d592SBrad Smith  return 32;
150777de779SZachary Turner#else
151777de779SZachary Turner  return 0;
152777de779SZachary Turner#endif
153777de779SZachary Turner}
154777de779SZachary Turner
1551f004c43SZachary Turneruint32_t llvm::get_max_thread_name_length() {
1561f004c43SZachary Turner  return get_max_thread_name_length_impl();
1571f004c43SZachary Turner}
1581f004c43SZachary Turner
159757dbc9fSZachary Turnervoid llvm::set_thread_name(const Twine &Name) {
160757dbc9fSZachary Turner  // Make sure the input is null terminated.
161757dbc9fSZachary Turner  SmallString<64> Storage;
162757dbc9fSZachary Turner  StringRef NameStr = Name.toNullTerminatedStringRef(Storage);
163777de779SZachary Turner
164777de779SZachary Turner  // Truncate from the beginning, not the end, if the specified name is too
165777de779SZachary Turner  // long.  For one, this ensures that the resulting string is still null
166777de779SZachary Turner  // terminated, but additionally the end of a long thread name will usually
167777de779SZachary Turner  // be more unique than the beginning, since a common pattern is for similar
168777de779SZachary Turner  // threads to share a common prefix.
1696358064dSSam McCall  // Note that the name length includes the null terminator.
1701f004c43SZachary Turner  if (get_max_thread_name_length() > 0)
1716358064dSSam McCall    NameStr = NameStr.take_back(get_max_thread_name_length() - 1);
17275464e17SKrzysztof Parzyszek  (void)NameStr;
173757dbc9fSZachary Turner#if defined(__linux__)
174757dbc9fSZachary Turner#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__)
1756cf25403SKrzysztof Parzyszek#if HAVE_PTHREAD_SETNAME_NP
176757dbc9fSZachary Turner  ::pthread_setname_np(::pthread_self(), NameStr.data());
177757dbc9fSZachary Turner#endif
1786cf25403SKrzysztof Parzyszek#endif
1798c17d592SBrad Smith#elif defined(__FreeBSD__) || defined(__OpenBSD__)
180757dbc9fSZachary Turner  ::pthread_set_name_np(::pthread_self(), NameStr.data());
181757dbc9fSZachary Turner#elif defined(__NetBSD__)
182757dbc9fSZachary Turner  ::pthread_setname_np(::pthread_self(), "%s",
183757dbc9fSZachary Turner    const_cast<char *>(NameStr.data()));
184757dbc9fSZachary Turner#elif defined(__APPLE__)
185757dbc9fSZachary Turner  ::pthread_setname_np(NameStr.data());
186757dbc9fSZachary Turner#endif
187757dbc9fSZachary Turner}
188757dbc9fSZachary Turner
189757dbc9fSZachary Turnervoid llvm::get_thread_name(SmallVectorImpl<char> &Name) {
190757dbc9fSZachary Turner  Name.clear();
191757dbc9fSZachary Turner
192757dbc9fSZachary Turner#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
19345337cf7SZachary Turner  int pid = ::getpid();
19445337cf7SZachary Turner  uint64_t tid = get_threadid();
195757dbc9fSZachary Turner
196757dbc9fSZachary Turner  struct kinfo_proc *kp = nullptr, *nkp;
197757dbc9fSZachary Turner  size_t len = 0;
198757dbc9fSZachary Turner  int error;
199757dbc9fSZachary Turner  int ctl[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD,
200757dbc9fSZachary Turner    (int)pid };
201757dbc9fSZachary Turner
202757dbc9fSZachary Turner  while (1) {
203757dbc9fSZachary Turner    error = sysctl(ctl, 4, kp, &len, nullptr, 0);
204757dbc9fSZachary Turner    if (kp == nullptr || (error != 0 && errno == ENOMEM)) {
205757dbc9fSZachary Turner      // Add extra space in case threads are added before next call.
206757dbc9fSZachary Turner      len += sizeof(*kp) + len / 10;
207ce719a0dSSerge Pavlov      nkp = (struct kinfo_proc *)::realloc(kp, len);
208757dbc9fSZachary Turner      if (nkp == nullptr) {
209757dbc9fSZachary Turner        free(kp);
210757dbc9fSZachary Turner        return;
211757dbc9fSZachary Turner      }
212757dbc9fSZachary Turner      kp = nkp;
213757dbc9fSZachary Turner      continue;
214757dbc9fSZachary Turner    }
215757dbc9fSZachary Turner    if (error != 0)
216757dbc9fSZachary Turner      len = 0;
217757dbc9fSZachary Turner    break;
218757dbc9fSZachary Turner  }
219757dbc9fSZachary Turner
220757dbc9fSZachary Turner  for (size_t i = 0; i < len / sizeof(*kp); i++) {
221757dbc9fSZachary Turner    if (kp[i].ki_tid == (lwpid_t)tid) {
222757dbc9fSZachary Turner      Name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname));
223757dbc9fSZachary Turner      break;
224757dbc9fSZachary Turner    }
225757dbc9fSZachary Turner  }
226757dbc9fSZachary Turner  free(kp);
227757dbc9fSZachary Turner  return;
228757dbc9fSZachary Turner#elif defined(__NetBSD__)
2291f004c43SZachary Turner  constexpr uint32_t len = get_max_thread_name_length_impl();
2301f004c43SZachary Turner  char buf[len];
2311f004c43SZachary Turner  ::pthread_getname_np(::pthread_self(), buf, len);
232757dbc9fSZachary Turner
233757dbc9fSZachary Turner  Name.append(buf, buf + strlen(buf));
23401227feaSBrad Smith#elif defined(__OpenBSD__)
23501227feaSBrad Smith  constexpr uint32_t len = get_max_thread_name_length_impl();
23601227feaSBrad Smith  char buf[len];
23701227feaSBrad Smith  ::pthread_get_name_np(::pthread_self(), buf, len);
23801227feaSBrad Smith
23901227feaSBrad Smith  Name.append(buf, buf + strlen(buf));
240757dbc9fSZachary Turner#elif defined(__linux__)
2416cf25403SKrzysztof Parzyszek#if HAVE_PTHREAD_GETNAME_NP
2421f004c43SZachary Turner  constexpr uint32_t len = get_max_thread_name_length_impl();
2430e142499SSam McCall  char Buffer[len] = {'\0'};  // FIXME: working around MSan false positive.
2441f004c43SZachary Turner  if (0 == ::pthread_getname_np(::pthread_self(), Buffer, len))
245757dbc9fSZachary Turner    Name.append(Buffer, Buffer + strlen(Buffer));
246757dbc9fSZachary Turner#endif
247757dbc9fSZachary Turner#endif
248757dbc9fSZachary Turner}
2498fdc5abfSKadir Cetinkaya
2508fdc5abfSKadir CetinkayaSetThreadPriorityResult llvm::set_thread_priority(ThreadPriority Priority) {
2518fdc5abfSKadir Cetinkaya#if defined(__linux__) && defined(SCHED_IDLE)
2528fdc5abfSKadir Cetinkaya  // Some *really* old glibcs are missing SCHED_IDLE.
2538fdc5abfSKadir Cetinkaya  // http://man7.org/linux/man-pages/man3/pthread_setschedparam.3.html
2548fdc5abfSKadir Cetinkaya  // http://man7.org/linux/man-pages/man2/sched_setscheduler.2.html
2558fdc5abfSKadir Cetinkaya  sched_param priority;
2568fdc5abfSKadir Cetinkaya  // For each of the above policies, param->sched_priority must be 0.
2578fdc5abfSKadir Cetinkaya  priority.sched_priority = 0;
2588fdc5abfSKadir Cetinkaya  // SCHED_IDLE    for running very low priority background jobs.
2598fdc5abfSKadir Cetinkaya  // SCHED_OTHER   the standard round-robin time-sharing policy;
2608fdc5abfSKadir Cetinkaya  return !pthread_setschedparam(
2618fdc5abfSKadir Cetinkaya             pthread_self(),
262*9902a094Sstk             // FIXME: consider SCHED_BATCH for Low
263*9902a094Sstk             Priority == ThreadPriority::Default ? SCHED_OTHER : SCHED_IDLE,
2648fdc5abfSKadir Cetinkaya             &priority)
2658fdc5abfSKadir Cetinkaya             ? SetThreadPriorityResult::SUCCESS
2668fdc5abfSKadir Cetinkaya             : SetThreadPriorityResult::FAILURE;
2678fdc5abfSKadir Cetinkaya#elif defined(__APPLE__)
268*9902a094Sstk  // https://developer.apple.com/documentation/apple-silicon/tuning-your-code-s-performance-for-apple-silicon
269*9902a094Sstk  //
270*9902a094Sstk  // Background - Applies to work that isn’t visible to the user and may take significant
271*9902a094Sstk  // time to complete. Examples include indexing, backing up, or synchronizing data. This
272*9902a094Sstk  // class emphasizes energy efficiency.
273*9902a094Sstk  //
274*9902a094Sstk  // Utility - Applies to work that takes anywhere from a few seconds to a few minutes to
275*9902a094Sstk  // complete. Examples include downloading a document or importing data. This class
276*9902a094Sstk  // offers a balance between responsiveness, performance, and energy efficiency.
277*9902a094Sstk  const auto qosClass = [&](){
278*9902a094Sstk    switch (Priority) {
279*9902a094Sstk      case ThreadPriority::Background: return QOS_CLASS_BACKGROUND;
280*9902a094Sstk      case ThreadPriority::Low: return QOS_CLASS_UTILITY;
281*9902a094Sstk      case ThreadPriority::Default: return QOS_CLASS_DEFAULT;
282*9902a094Sstk    }
283*9902a094Sstk  }();
284*9902a094Sstk  return !pthread_set_qos_class_self_np(qosClass, 0)
2858fdc5abfSKadir Cetinkaya             ? SetThreadPriorityResult::SUCCESS
2868fdc5abfSKadir Cetinkaya             : SetThreadPriorityResult::FAILURE;
2878fdc5abfSKadir Cetinkaya#endif
2888fdc5abfSKadir Cetinkaya  return SetThreadPriorityResult::FAILURE;
2898fdc5abfSKadir Cetinkaya}
2908404aeb5SAlexandre Ganea
2918404aeb5SAlexandre Ganea#include <thread>
2928404aeb5SAlexandre Ganea
2938404aeb5SAlexandre Ganeaint computeHostNumHardwareThreads() {
294d989ffd1SDimitry Andric#if defined(__FreeBSD__)
295d989ffd1SDimitry Andric  cpuset_t mask;
296d989ffd1SDimitry Andric  CPU_ZERO(&mask);
297d989ffd1SDimitry Andric  if (cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_TID, -1, sizeof(mask),
298d989ffd1SDimitry Andric                         &mask) == 0)
299d989ffd1SDimitry Andric    return CPU_COUNT(&mask);
300d989ffd1SDimitry Andric#elif defined(__linux__)
3018404aeb5SAlexandre Ganea  cpu_set_t Set;
30209158252SAlexandre Ganea  if (sched_getaffinity(0, sizeof(Set), &Set) == 0)
3038404aeb5SAlexandre Ganea    return CPU_COUNT(&Set);
3048404aeb5SAlexandre Ganea#endif
3058404aeb5SAlexandre Ganea  // Guard against std::thread::hardware_concurrency() returning 0.
3068404aeb5SAlexandre Ganea  if (unsigned Val = std::thread::hardware_concurrency())
3078404aeb5SAlexandre Ganea    return Val;
3088404aeb5SAlexandre Ganea  return 1;
3098404aeb5SAlexandre Ganea}
3108404aeb5SAlexandre Ganea
3118404aeb5SAlexandre Ganeavoid llvm::ThreadPoolStrategy::apply_thread_strategy(
3128404aeb5SAlexandre Ganea    unsigned ThreadPoolNum) const {}
3138404aeb5SAlexandre Ganea
3148404aeb5SAlexandre Ganeallvm::BitVector llvm::get_thread_affinity_mask() {
3158404aeb5SAlexandre Ganea  // FIXME: Implement
3168404aeb5SAlexandre Ganea  llvm_unreachable("Not implemented!");
3178404aeb5SAlexandre Ganea}
3188404aeb5SAlexandre Ganea
3198404aeb5SAlexandre Ganeaunsigned llvm::get_cpus() { return 1; }
320