Index: llvm/include/llvm/Support/Threading.h =================================================================== --- llvm/include/llvm/Support/Threading.h +++ llvm/include/llvm/Support/Threading.h @@ -15,6 +15,8 @@ #ifndef LLVM_SUPPORT_THREADING_H #define LLVM_SUPPORT_THREADING_H +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX #include "llvm/Support/Compiler.h" #include // So we can check the C++ standard lib macros. @@ -127,6 +129,9 @@ /// thread::hardware_concurrency(). /// Returns 1 when LLVM is configured with LLVM_ENABLE_THREADS=OFF unsigned heavyweight_hardware_concurrency(); + + void set_thread_name(StringRef Name); + void get_thread_name(SmallVectorImpl &Name); } #endif Index: llvm/lib/Support/Threading.cpp =================================================================== --- llvm/lib/Support/Threading.cpp +++ llvm/lib/Support/Threading.cpp @@ -13,12 +13,19 @@ //===----------------------------------------------------------------------===// #include "llvm/Support/Threading.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" #include "llvm/Config/config.h" #include "llvm/Support/Atomic.h" #include "llvm/Support/Host.h" +#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Mutex.h" #include "llvm/Support/thread.h" + #include +#include +#include +#include using namespace llvm; @@ -33,6 +40,17 @@ #if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) #include +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) + +#include +#include + +#if defined(__FreeBSD__) +#include +#endif + +#endif + struct ThreadInfo { void (*UserFn)(void *); void *UserData; @@ -127,3 +145,116 @@ return thread::hardware_concurrency(); return NumPhysical; } + +#if LLVM_ENABLE_THREADS == 0 +void llvm::get_thread_name(SmallVectorImpl &) {} + +void llvm::set_thread_name(StringRef) {} + +#else +void llvm::set_thread_name(StringRef Name) { + // Make sure the input is null terminated. + std::string NameStr(Name); +#if defined(__linux__) +#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) + ::pthread_setname_np(::pthread_self(), NameStr.c_str()); +#endif +#elif defined(__FreeBSD__) + ::pthread_set_name_np(::pthread_self(), NameStr.c_str()); +#elif defined(__NetBSD__) + ::pthread_setname_np(::pthread_self(), "%s", + const_cast(NameStr.c_str())); +#elif defined(__APPLE__) + ::pthread_setname_np(NameStr.c_str()); +#elif defined(_MSC_VER) + constexpr DWORD MS_VC_EXCEPTION = 0x406D1388; + +#pragma pack(push, 8) + struct THREADNAME_INFO { + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to thread name + DWORD dwThreadId; // Thread ID (-1 == current thread) + DWORD dwFlags; // Reserved. Do not use. + }; +#pragma pack(pop) + + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = NameStr.c_str(); + info.dwThreadId = ::GetCurrentThreadId(); + info.dwFlags = 0; + + __try { + ::RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), + (ULONG_PTR *)&info); + } __except (EXCEPTION_EXECUTE_HANDLER) { + } +#endif +} + +void llvm::get_thread_name(SmallVectorImpl &Name) { + Name.clear(); + +#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#if defined(__FreeBSD_kernel__) + int pid = ::pthread_self(); +#else + int pid = ::getpid(); +#endif + + int tid = ::pthread_getthreadid_np(); + + struct kinfo_proc *kp = nullptr, *nkp; + size_t len = 0; + int error; + int ctl[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID | KERN_PROC_INC_THREAD, + (int)pid}; + + while (1) { + error = sysctl(ctl, 4, kp, &len, nullptr, 0); + if (kp == nullptr || (error != 0 && errno == ENOMEM)) { + // Add extra space in case threads are added before next call. + len += sizeof(*kp) + len / 10; + nkp = (struct kinfo_proc *)realloc(kp, len); + if (nkp == nullptr) { + free(kp); + return; + } + kp = nkp; + continue; + } + if (error != 0) + len = 0; + break; + } + + for (size_t i = 0; i < len / sizeof(*kp); i++) { + if (kp[i].ki_tid == (lwpid_t)tid) { + Name.append(kp[i].ki_tdname, kp[i].ki_tdname + strlen(kp[i].ki_tdname)); + break; + } + } + free(kp); + return; +#elif defined(__NetBSD__) + char buf[PTHREAD_MAX_NAMELEN_NP]; + ::pthread_getname_np(::pthread_self(), buf, PTHREAD_MAX_NAMELEN_NP); + + Name.append(buf, buf + strlen(buf)); +#elif defined(__linux__) + // Read /proc/$TID/comm file. + SmallString<64> Path; + raw_svector_ostream Stream(Path); + Stream << "/proc/" << static_cast(::pthread_self()) << "/comm"; + + auto Contents = MemoryBuffer::getFileAsStream(Path); + if (!Contents) + return; + + StringRef CommData = (*Contents)->getBuffer(); + StringRef Result = CommData.split('\n').first; + + Name.append(Result.begin(), Result.end()); +#endif +} +#endif