[llvm] r296887 - [Support] Provide access to current thread name/thread id.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Fri Mar 3 10:30:44 PST 2017


All of the linux bots have been fixed.  There's still 1 or 2 broken FreeBSD
bots, I have a fix incoming for those.

On Fri, Mar 3, 2017 at 10:27 AM Mike Aizatsky <aizatsky at google.com> wrote:

> Zachary,
>
> I think this breaks multiple bots:
>
> http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-fast/builds/3224
> http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux/builds/1002
>
> Could you take a look?
>
> On Fri, Mar 3, 2017 at 9:27 AM Zachary Turner via llvm-commits <
> llvm-commits at lists.llvm.org> wrote:
>
> Author: zturner
> Date: Fri Mar  3 11:15:17 2017
> New Revision: 296887
>
> URL: http://llvm.org/viewvc/llvm-project?rev=296887&view=rev
> Log:
> [Support] Provide access to current thread name/thread id.
>
> Applications often need the current thread id when making
> system calls, and some operating systems provide the notion
> of a thread name, which can be useful in enabling better
> diagnostics when debugging or logging.
>
> This patch adds an accessor for the thread id, and "best effort"
> getters and setters for the thread name.  Since this is
> non critical functionality, no error is returned to indicate
> that a platform doesn't support thread names.
>
> Differential Revision: https://reviews.llvm.org/D30526
>
> Added:
>     llvm/trunk/lib/Support/Unix/Threading.inc
>     llvm/trunk/lib/Support/Windows/Threading.inc
> Modified:
>     llvm/trunk/include/llvm/Support/Threading.h
>     llvm/trunk/lib/Support/Threading.cpp
>
> Modified: llvm/trunk/include/llvm/Support/Threading.h
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/Threading.h?rev=296887&r1=296886&r2=296887&view=diff
>
> ==============================================================================
> --- llvm/trunk/include/llvm/Support/Threading.h (original)
> +++ llvm/trunk/include/llvm/Support/Threading.h Fri Mar  3 11:15:17 2017
> @@ -15,6 +15,7 @@
>  #ifndef LLVM_SUPPORT_THREADING_H
>  #define LLVM_SUPPORT_THREADING_H
>
> +#include "llvm/ADT/SmallVector.h"
>  #include "llvm/Config/llvm-config.h" // for LLVM_ON_UNIX
>  #include "llvm/Support/Compiler.h"
>  #include <ciso646> // So we can check the C++ standard lib macros.
> @@ -42,24 +43,26 @@
>  #endif
>
>  namespace llvm {
> -  /// Returns true if LLVM is compiled with support for multi-threading,
> and
> -  /// false otherwise.
> -  bool llvm_is_multithreaded();
> -
> -  /// llvm_execute_on_thread - Execute the given \p UserFn on a separate
> -  /// thread, passing it the provided \p UserData and waits for thread
> -  /// completion.
> -  ///
> -  /// This function does not guarantee that the code will actually be
> executed
> -  /// on a separate thread or honoring the requested stack size, but
> tries to do
> -  /// so where system support is available.
> -  ///
> -  /// \param UserFn - The callback to execute.
> -  /// \param UserData - An argument to pass to the callback function.
> -  /// \param RequestedStackSize - If non-zero, a requested size (in
> bytes) for
> -  /// the thread stack.
> -  void llvm_execute_on_thread(void (*UserFn)(void*), void *UserData,
> -                              unsigned RequestedStackSize = 0);
> +class Twine;
> +
> +/// Returns true if LLVM is compiled with support for multi-threading, and
> +/// false otherwise.
> +bool llvm_is_multithreaded();
> +
> +/// llvm_execute_on_thread - Execute the given \p UserFn on a separate
> +/// thread, passing it the provided \p UserData and waits for thread
> +/// completion.
> +///
> +/// This function does not guarantee that the code will actually be
> executed
> +/// on a separate thread or honoring the requested stack size, but tries
> to do
> +/// so where system support is available.
> +///
> +/// \param UserFn - The callback to execute.
> +/// \param UserData - An argument to pass to the callback function.
> +/// \param RequestedStackSize - If non-zero, a requested size (in bytes)
> for
> +/// the thread stack.
> +void llvm_execute_on_thread(void (*UserFn)(void *), void *UserData,
> +                            unsigned RequestedStackSize = 0);
>
>  #if LLVM_THREADING_USE_STD_CALL_ONCE
>
> @@ -127,6 +130,28 @@ namespace llvm {
>    /// thread::hardware_concurrency().
>    /// Returns 1 when LLVM is configured with LLVM_ENABLE_THREADS=OFF
>    unsigned heavyweight_hardware_concurrency();
> +
> +  /// \brief Return the current thread id, as used in various OS system
> calls.
> +  /// Note that not all platforms guarantee that the value returned will
> be
> +  /// unique across the entire system, so portable code should not assume
> +  /// this.
> +  uint64_t get_threadid();
> +
> +  /// \brief Set the name of the current thread.  Setting a thread's name
> can
> +  /// be helpful for enabling useful diagnostics under a debugger or when
> +  /// logging.  The level of support for setting a thread's name varies
> +  /// wildly across operating systems, and we only make a best effort to
> +  /// perform the operation on supported platforms.  No indication of
> success
> +  /// or failure is returned.
> +  void set_thread_name(const Twine &Name);
> +
> +  /// \brief Get the name of the current thread.  The level of support for
> +  /// getting a thread's name varies wildly across operating systems, and
> it
> +  /// is not even guaranteed that if you can successfully set a thread's
> name
> +  /// that you can later get it back.  This function is intended for
> diagnostic
> +  /// purposes, and as with setting a thread's name no indication of
> whether
> +  /// the operation succeeded or failed is returned.
> +  void get_thread_name(SmallVectorImpl<char> &Name);
>  }
>
>  #endif
>
> Modified: llvm/trunk/lib/Support/Threading.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Threading.cpp?rev=296887&r1=296886&r2=296887&view=diff
>
> ==============================================================================
> --- llvm/trunk/lib/Support/Threading.cpp (original)
> +++ llvm/trunk/lib/Support/Threading.cpp Fri Mar  3 11:15:17 2017
> @@ -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 <cassert>
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <string.h>
>
>  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 @@ bool llvm::llvm_is_multithreaded() {
>  #endif
>  }
>
> -#if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H)
> -#include <pthread.h>
> -
> -struct ThreadInfo {
> -  void (*UserFn)(void *);
> -  void *UserData;
> -};
> -static void *ExecuteOnThread_Dispatch(void *Arg) {
> -  ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(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 <process.h>
> -
> -// Windows will at times define MemoryFence.
> -#ifdef MemoryFence
> -#undef MemoryFence
> -#endif
>
> -struct ThreadInfo {
> -  void (*func)(void*);
> -  void *param;
> -};
> -
> -static unsigned __stdcall ThreadCallback(void *param) {
> -  struct ThreadInfo *info = reinterpret_cast<struct ThreadInfo *>(param);
> -  info->func(info->param);
> +unsigned llvm::heavyweight_hardware_concurrency() { return 1; }
>
> -  return 0;
> -}
> +uint64_t llvm::get_threadid_np() { 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,
> -                                            &param, 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);
> -  }
> -}
> -#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);
> -}
> +void llvm::get_thread_name(SmallVectorImpl<char> &Name) { Name.clear(); }
>
> -#endif
> +#else
>
>  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
>
> Added: llvm/trunk/lib/Support/Unix/Threading.inc
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Unix/Threading.inc?rev=296887&view=auto
>
> ==============================================================================
> --- llvm/trunk/lib/Support/Unix/Threading.inc (added)
> +++ llvm/trunk/lib/Support/Unix/Threading.inc Fri Mar  3 11:15:17 2017
> @@ -0,0 +1,181 @@
> +//===- 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"
> +#include "llvm/ADT/Twine.h"
> +
> +#if defined(__APPLE__)
> +#include <mach/mach_init.h>
> +#include <mach/mach_port.h>
> +#endif
> +
> +#include <pthread.h>
> +
> +#if defined(__FreeBSD__)
> +#include <pthread_np.h>
> +#endif
> +
> +#if defined(__NetBSD__)
> +#include <lwp.h>
> +#endif
> +
> +#if defined(__linux__)
> +#include <sys/syscall.h>
> +#endif
> +
> +#if defined(__NetBSD__) || defined(__FreeBSD__) ||
> defined(__FreeBSD_kernel__)
> +#include <sys/sysctl.h>
> +#include <sys/user.h>
> +#endif
> +
> +namespace {
> +  struct ThreadInfo {
> +    void(*UserFn)(void *);
> +    void *UserData;
> +  };
> +}
> +
> +static void *ExecuteOnThread_Dispatch(void *Arg) {
> +  ThreadInfo *TI = reinterpret_cast<ThreadInfo*>(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() {
> +#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<char *>(NameStr.data()));
> +#elif defined(__APPLE__)
> +  ::pthread_setname_np(NameStr.data());
> +#endif
> +}
> +
> +void llvm::get_thread_name(SmallVectorImpl<char> &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
> +}
>
> Added: llvm/trunk/lib/Support/Windows/Threading.inc
> URL:
> http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/Windows/Threading.inc?rev=296887&view=auto
>
> ==============================================================================
> --- llvm/trunk/lib/Support/Windows/Threading.inc (added)
> +++ llvm/trunk/lib/Support/Windows/Threading.inc Fri Mar  3 11:15:17 2017
> @@ -0,0 +1,101 @@
> +//===- 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 "llvm/ADT/Twine.h"
> +
> +#include "Windows/WindowsSupport.h"
> +#include <process.h>
> +
> +// 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<struct ThreadInfo *>(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,
> +    &param, 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() {
> +  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<char> &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();
> +}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>
> --
> Mike
> Sent from phone
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20170303/15ec3cc3/attachment.html>


More information about the llvm-commits mailing list