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