1//===- Unix/Threading.inc - Unix Threading Implementation ----- -*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file provides the Unix specific implementation of Threading functions. 11// 12//===----------------------------------------------------------------------===// 13 14#include "llvm/ADT/SmallString.h" 15#include "llvm/ADT/Twine.h" 16 17#if defined(__APPLE__) 18#include <mach/mach_init.h> 19#include <mach/mach_port.h> 20#endif 21 22#include <pthread.h> 23 24#if defined(__FreeBSD__) 25#include <pthread_np.h> 26#endif 27 28#if defined(__NetBSD__) 29#include <lwp.h> 30#endif 31 32#if defined(__linux__) 33#include <unistd.h> 34#include <sys/syscall.h> 35#endif 36 37#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 38#include <sys/sysctl.h> 39#include <sys/user.h> 40#endif 41 42namespace { 43 struct ThreadInfo { 44 void(*UserFn)(void *); 45 void *UserData; 46 }; 47} 48 49static void *ExecuteOnThread_Dispatch(void *Arg) { 50 ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(Arg); 51 TI->UserFn(TI->UserData); 52 return nullptr; 53} 54 55void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData, 56 unsigned RequestedStackSize) { 57 ThreadInfo Info = { Fn, UserData }; 58 pthread_attr_t Attr; 59 pthread_t Thread; 60 61 // Construct the attributes object. 62 if (::pthread_attr_init(&Attr) != 0) 63 return; 64 65 // Set the requested stack size, if given. 66 if (RequestedStackSize != 0) { 67 if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0) 68 goto error; 69 } 70 71 // Construct and execute the thread. 72 if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0) 73 goto error; 74 75 // Wait for the thread and clean up. 76 ::pthread_join(Thread, nullptr); 77 78error: 79 ::pthread_attr_destroy(&Attr); 80} 81 82 83uint64_t llvm::get_threadid() { 84#if defined(__APPLE__) 85 // Calling "mach_thread_self()" bumps the reference count on the thread 86 // port, so we need to deallocate it. mach_task_self() doesn't bump the ref 87 // count. 88 thread_port_t Self = mach_thread_self(); 89 mach_port_deallocate(mach_task_self(), Self); 90 return Self; 91#elif defined(__FreeBSD__) 92 return uint64_t(pthread_getthreadid_np()); 93#elif defined(__NetBSD__) 94 return uint64_t(_lwp_self()); 95#elif defined(__ANDROID__) 96 return uint64_t(gettid()); 97#elif defined(__linux__) 98 return uint64_t(syscall(SYS_gettid)); 99#elif defined(LLVM_ON_WIN32) 100 return uint64_t(::GetCurrentThreadId()); 101#else 102 return uint64_t(pthread_self()); 103#endif 104} 105 106 107void llvm::set_thread_name(const Twine &Name) { 108 // Make sure the input is null terminated. 109 SmallString<64> Storage; 110 StringRef NameStr = Name.toNullTerminatedStringRef(Storage); 111#if defined(__linux__) 112#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) 113 ::pthread_setname_np(::pthread_self(), NameStr.data()); 114#endif 115#elif defined(__FreeBSD__) 116 ::pthread_set_name_np(::pthread_self(), NameStr.data()); 117#elif defined(__NetBSD__) 118 ::pthread_setname_np(::pthread_self(), "%s", 119 const_cast<char *>(NameStr.data())); 120#elif defined(__APPLE__) 121 ::pthread_setname_np(NameStr.data()); 122#endif 123} 124 125void llvm::get_thread_name(SmallVectorImpl<char> &Name) { 126 Name.clear(); 127 128#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) 129#if defined(__FreeBSD_kernel__) 130 auto pid = ::pthread_self(); 131#else 132 auto pid = ::getpid(); 133#endif 134 135 int tid = ::pthread_getthreadid_np(); 136 137 struct kinfo_proc *kp = nullptr, *nkp; 138 size_t len = 0; 139 int error; 140 int ctl[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, 141 (int)pid }; 142 143 while (1) { 144 error = sysctl(ctl, 4, kp, &len, nullptr, 0); 145 if (kp == nullptr || (error != 0 && errno == ENOMEM)) { 146 // Add extra space in case threads are added before next call. 147 len += sizeof(*kp) + len / 10; 148 nkp = (struct kinfo_proc *)realloc(kp, len); 149 if (nkp == nullptr) { 150 free(kp); 151 return; 152 } 153 kp = nkp; 154 continue; 155 } 156 if (error != 0) 157 len = 0; 158 break; 159 } 160 161 for (size_t i = 0; i < len / sizeof(*kp); i++) { 162 if (kp[i].ki_tid == (lwpid_t)tid) { 163 Name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname)); 164 break; 165 } 166 } 167 free(kp); 168 return; 169#elif defined(__NetBSD__) 170 char buf[PTHREAD_MAX_NAMELEN_NP]; 171 ::pthread_getname_np(::pthread_self(), buf, PTHREAD_MAX_NAMELEN_NP); 172 173 Name.append(buf, buf + strlen(buf)); 174#elif defined(__linux__) 175#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) 176 constexpr int MAXNAMELEN = 16; 177 char Buffer[MAXNAMELEN]; 178 if (0 == ::pthread_getname_np(::pthread_self(), Buffer, MAXNAMELEN)) 179 Name.append(Buffer, Buffer + strlen(Buffer)); 180#endif 181#endif 182} 183