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