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