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/Twine.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,11 @@ /// thread::hardware_concurrency(). /// Returns 1 when LLVM is configured with LLVM_ENABLE_THREADS=OFF unsigned heavyweight_hardware_concurrency(); + + uint64_t get_threadid_np(); + + void set_thread_name(const Twine &Name); + void get_thread_name(SmallVectorImpl &Name); } #endif Index: llvm/lib/Support/Threading.cpp =================================================================== --- llvm/lib/Support/Threading.cpp +++ llvm/lib/Support/Threading.cpp @@ -14,14 +14,21 @@ #include "llvm/Support/Threading.h" #include "llvm/Config/config.h" -#include "llvm/Support/Atomic.h" #include "llvm/Support/Host.h" -#include "llvm/Support/Mutex.h" #include "llvm/Support/thread.h" + #include +#include +#include +#include using namespace llvm; +//===----------------------------------------------------------------------===// +//=== WARNING: Implementation here must contain only TRULY operating system +//=== independent code. +//===----------------------------------------------------------------------===// + bool llvm::llvm_is_multithreaded() { #if LLVM_ENABLE_THREADS != 0 return true; @@ -30,100 +37,38 @@ #endif } -#if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) -#include - -struct ThreadInfo { - void (*UserFn)(void *); - void *UserData; -}; -static void *ExecuteOnThread_Dispatch(void *Arg) { - ThreadInfo *TI = reinterpret_cast(Arg); - TI->UserFn(TI->UserData); - return nullptr; -} - -void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, +#if LLVM_ENABLE_THREADS == 0 || \ + (!defined(LLVM_ON_WIN32) && !defined(HAVE_PTHREAD_H)) +// Support for non-Win32, non-pthread implementation. +void llvm::llvm_execute_on_thread(void (*Fn)(void *), void *UserData, unsigned RequestedStackSize) { - ThreadInfo Info = { Fn, UserData }; - pthread_attr_t Attr; - pthread_t Thread; - - // Construct the attributes object. - if (::pthread_attr_init(&Attr) != 0) - return; - - // Set the requested stack size, if given. - if (RequestedStackSize != 0) { - if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0) - goto error; - } - - // Construct and execute the thread. - if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0) - goto error; - - // Wait for the thread and clean up. - ::pthread_join(Thread, nullptr); - - error: - ::pthread_attr_destroy(&Attr); + (void)RequestedStackSize; + Fn(UserData); } -#elif LLVM_ENABLE_THREADS!=0 && defined(LLVM_ON_WIN32) -#include "Windows/WindowsSupport.h" -#include - -// Windows will at times define MemoryFence. -#ifdef MemoryFence -#undef MemoryFence -#endif -struct ThreadInfo { - void (*func)(void*); - void *param; -}; +unsigned llvm::heavyweight_hardware_concurrency() { return 1; } -static unsigned __stdcall ThreadCallback(void *param) { - struct ThreadInfo *info = reinterpret_cast(param); - info->func(info->param); +uint64_t llvm::get_threadid_np() { return 0; } - return 0; -} - -void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, - unsigned RequestedStackSize) { - struct ThreadInfo param = { Fn, UserData }; +void llvm::set_thread_name(const Twine &Name) {} - HANDLE hThread = (HANDLE)::_beginthreadex(NULL, - RequestedStackSize, ThreadCallback, - ¶m, 0, NULL); +void llvm::get_thread_name(SmallVectorImpl &Name) { Name.clear(); } - if (hThread) { - // We actually don't care whether the wait succeeds or fails, in - // the same way we don't care whether the pthread_join call succeeds - // or fails. There's not much we could do if this were to fail. But - // on success, this call will wait until the thread finishes executing - // before returning. - (void)::WaitForSingleObject(hThread, INFINITE); - ::CloseHandle(hThread); - } -} #else -// Support for non-Win32, non-pthread implementation. -void llvm::llvm_execute_on_thread(void (*Fn)(void*), void *UserData, - unsigned RequestedStackSize) { - (void) RequestedStackSize; - Fn(UserData); -} - -#endif unsigned llvm::heavyweight_hardware_concurrency() { -#if !LLVM_ENABLE_THREADS - return 1; -#endif int NumPhysical = sys::getHostNumPhysicalCores(); if (NumPhysical == -1) return thread::hardware_concurrency(); return NumPhysical; } + +// Include the platform-specific parts of this class. +#ifdef LLVM_ON_UNIX +#include "Unix/Threading.inc" +#endif +#ifdef LLVM_ON_WIN32 +#include "Windows/Threading.inc" +#endif + +#endif Index: llvm/lib/Support/Unix/Threading.inc =================================================================== --- /dev/null +++ llvm/lib/Support/Unix/Threading.inc @@ -0,0 +1,180 @@ +//===- Unix/Threading.inc - Unix Threading Implementation ----- -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Unix specific implementation of Threading functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallString.h" + +#if defined(__APPLE__) +#include +#include +#endif + +#include + +#if defined(__FreeBSD__) +#include +#endif + +#if defined(__NetBSD__) +#include +#endif + +#if defined(__linux__) +#include +#endif + +#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) +#include +#include +#endif + +namespace { + struct ThreadInfo { + void(*UserFn)(void *); + void *UserData; + }; +} + +static void *ExecuteOnThread_Dispatch(void *Arg) { + ThreadInfo *TI = reinterpret_cast(Arg); + TI->UserFn(TI->UserData); + return nullptr; +} + +void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + ThreadInfo Info = { Fn, UserData }; + pthread_attr_t Attr; + pthread_t Thread; + + // Construct the attributes object. + if (::pthread_attr_init(&Attr) != 0) + return; + + // Set the requested stack size, if given. + if (RequestedStackSize != 0) { + if (::pthread_attr_setstacksize(&Attr, RequestedStackSize) != 0) + goto error; + } + + // Construct and execute the thread. + if (::pthread_create(&Thread, &Attr, ExecuteOnThread_Dispatch, &Info) != 0) + goto error; + + // Wait for the thread and clean up. + ::pthread_join(Thread, nullptr); + +error: + ::pthread_attr_destroy(&Attr); +} + + +uint64_t llvm::get_threadid_np() { +#if defined(__APPLE__) + // Calling "mach_thread_self()" bumps the reference count on the thread + // port, so we need to deallocate it. mach_task_self() doesn't bump the ref + // count. + thread_port_t Self = mach_thread_self(); + mach_port_deallocate(mach_task_self(), Self); + return Self; +#elif defined(__FreeBSD__) + return uint64_t(pthread_getthreadid_np()); +#elif defined(__NetBSD__) + return uint64_t(_lwp_self()); +#elif defined(__ANDROID__) + return uint64_t(gettid()); +#elif defined(__linux__) + return uint64_t(syscall(SYS_gettid)); +#elif defined(LLVM_ON_WIN32) + return uint64_t(::GetCurrentThreadId()); +#else + return uint64_t(pthread_self()); +#endif +} + + +void llvm::set_thread_name(const Twine &Name) { + // Make sure the input is null terminated. + SmallString<64> Storage; + StringRef NameStr = Name.toNullTerminatedStringRef(Storage); +#if defined(__linux__) +#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) + ::pthread_setname_np(::pthread_self(), NameStr.data()); +#endif +#elif defined(__FreeBSD__) + ::pthread_set_name_np(::pthread_self(), NameStr.data()); +#elif defined(__NetBSD__) + ::pthread_setname_np(::pthread_self(), "%s", + const_cast(NameStr.data())); +#elif defined(__APPLE__) + ::pthread_setname_np(NameStr.data()); +#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__) +#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || defined(__ANDROID__) + constexpr int MAXNAMELEN = 16; + char Buffer[MAXNAMELEN]; + if (0 == ::pthread_getname_np(::pthread_self(), Buffer, MAXNAMELEN)) + Name.append(Buffer, Buffer + strlen(Buffer)); +#endif +#endif +} Index: llvm/lib/Support/Windows/Threading.inc =================================================================== --- /dev/null +++ llvm/lib/Support/Windows/Threading.inc @@ -0,0 +1,100 @@ +//===- Windows/Threading.inc - Win32 Threading Implementation - -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides the Win32 specific implementation of Threading functions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/SmallString.h" + +#include "Windows/WindowsSupport.h" +#include + +// Windows will at times define MemoryFence. +#ifdef MemoryFence +#undef MemoryFence +#endif + +namespace { + struct ThreadInfo { + void(*func)(void*); + void *param; + }; +} + +static unsigned __stdcall ThreadCallback(void *param) { + struct ThreadInfo *info = reinterpret_cast(param); + info->func(info->param); + + return 0; +} + +void llvm::llvm_execute_on_thread(void(*Fn)(void*), void *UserData, + unsigned RequestedStackSize) { + struct ThreadInfo param = { Fn, UserData }; + + HANDLE hThread = (HANDLE)::_beginthreadex(NULL, + RequestedStackSize, ThreadCallback, + ¶m, 0, NULL); + + if (hThread) { + // We actually don't care whether the wait succeeds or fails, in + // the same way we don't care whether the pthread_join call succeeds + // or fails. There's not much we could do if this were to fail. But + // on success, this call will wait until the thread finishes executing + // before returning. + (void)::WaitForSingleObject(hThread, INFINITE); + ::CloseHandle(hThread); + } +} + +uint64_t llvm::get_threadid_np() { + return uint64_t(::GetCurrentThreadId()); +} + +void llvm::set_thread_name(const Twine &Name) { +#if defined(_MSC_VER) + // Make sure the input is null terminated. + SmallString<64> Storage; + StringRef NameStr = Name.toNullTerminatedStringRef(Storage); + 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.data(); + 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" is not an inherent property of a thread on Windows. In fact, when + // you "set" the name, you are only firing a one-time message to a debugger + // which it interprets as a program setting its threads' name. We may be + // able to get fancy by creating a TLS entry when someone calls + // set_thread_name so that subsequent calls to get_thread_name return this + // value. + Name.clear(); +}