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