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