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