From 6bfd09a8b7e021d010760d52d06ff3db2797aa3e Mon Sep 17 00:00:00 2001 From: Christopher Dykes Date: Mon, 24 Apr 2017 18:41:06 -0700 Subject: [PATCH] Shift the implementation of setThreadName out of the header Summary: `folly::setThreadName` is neither performance critical, nor (after this diff) is it a template, so exposing the mess that is its implementation to the world isn't worth it. The implementation is expected to get even more messy as I add support for getting the current thread's name, and eventually also add support for Windows as well. This also required exposing whether the current platform supports setting the name of the current or other threads. Reviewed By: yfeldblum Differential Revision: D4942401 fbshipit-source-id: 0e3be203995fa6ed667a5fd28dac7ba7fa49d683 --- folly/Makefile.am | 1 + folly/ThreadName.cpp | 112 ++++++++++++++++++++++++++++++++++ folly/ThreadName.h | 96 ++++------------------------- folly/test/ThreadNameTest.cpp | 18 +----- 4 files changed, 128 insertions(+), 99 deletions(-) create mode 100644 folly/ThreadName.cpp diff --git a/folly/Makefile.am b/folly/Makefile.am index 3d5fd9ba..692a719c 100644 --- a/folly/Makefile.am +++ b/folly/Makefile.am @@ -529,6 +529,7 @@ libfolly_la_SOURCES = \ stats/Instantiations.cpp \ Subprocess.cpp \ ThreadCachedArena.cpp \ + ThreadName.cpp \ TimeoutQueue.cpp \ Uri.cpp \ Version.cpp \ diff --git a/folly/ThreadName.cpp b/folly/ThreadName.cpp new file mode 100644 index 00000000..acd6163f --- /dev/null +++ b/folly/ThreadName.cpp @@ -0,0 +1,112 @@ +/* + * Copyright 2017 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include +#include +#include + +namespace folly { + +// This looks a bit weird, but it's necessary to avoid +// having an undefined compiler function called. +#if defined(__GLIBC__) && !defined(__APPLE__) && !defined(__ANDROID__) +#if __GLIBC_PREREQ(2, 12) +// has pthread_setname_np(pthread_t, const char*) (2 params) +#define FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME 1 +#endif +#endif + +#if defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED) +#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 +// has pthread_setname_np(const char*) (1 param) +#define FOLLY_HAS_PTHREAD_SETNAME_NP_NAME 1 +#endif +#endif + +bool canSetCurrentThreadName() { +#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || \ + FOLLY_HAS_PTHREAD_SETNAME_NP_NAME + return true; +#else + return false; +#endif +} + +bool canSetOtherThreadName() { +#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME + return true; +#else + return false; +#endif +} + +bool setThreadName(std::thread::id tid, StringPiece name) { +#if !FOLLY_HAVE_PTHREAD + return false; +#else + static_assert( + std::is_same::value, + "This assumes that the native handle type is pthread_t"); + static_assert( + sizeof(std::thread::native_handle_type) == sizeof(std::thread::id), + "This assumes std::thread::id is a thin wrapper around " + "std::thread::native_handle_type, but that doesn't appear to be true."); + // In most implementations, std::thread::id is a thin wrapper around + // std::thread::native_handle_type, which means we can do unsafe things to + // extract it. + pthread_t id; + std::memcpy(&id, &tid, sizeof(id)); +#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME + return 0 == pthread_setname_np(id, name.fbstr().substr(0, 15).c_str()); +#elif FOLLY_HAS_PTHREAD_SETNAME_NP_NAME + // Since OS X 10.6 it is possible for a thread to set its own name, + // but not that of some other thread. + if (pthread_equal(pthread_self(), id)) { + return 0 == pthread_setname_np(name.fbstr().c_str()); + } + return false; +#else + return false; +#endif +#endif +} + +#if FOLLY_HAVE_PTHREAD +bool setThreadName(pthread_t pid, StringPiece name) { + static_assert( + std::is_same::value, + "This assumes that the native handle type is pthread_t"); + static_assert( + sizeof(std::thread::native_handle_type) == sizeof(std::thread::id), + "This assumes std::thread::id is a thin wrapper around " + "std::thread::native_handle_type, but that doesn't appear to be true."); + // In most implementations, std::thread::id is a thin wrapper around + // std::thread::native_handle_type, which means we can do unsafe things to + // extract it. + std::thread::id id; + std::memcpy(&id, &pid, sizeof(id)); + return setThreadName(id, name); +} +#endif + +bool setThreadName(StringPiece name) { + return setThreadName(std::this_thread::get_id(), name); +} +} diff --git a/folly/ThreadName.h b/folly/ThreadName.h index 52b0cdac..b55793ce 100644 --- a/folly/ThreadName.h +++ b/folly/ThreadName.h @@ -17,96 +17,26 @@ #pragma once #include -#include #include -#include #include #include namespace folly { +/** + * This returns true if the current platform supports setting the name of the + * current thread. + */ +bool canSetCurrentThreadName(); +/** + * This returns true if the current platform supports setting the name of + * threads other than the one currently executing. + */ +bool canSetOtherThreadName(); -// This looks a bit weird, but it's necessary to avoid -// having an undefined compiler function called. -#if defined(__GLIBC__) && !defined(__APPLE__) && !defined(__ANDROID__) -#if __GLIBC_PREREQ(2, 12) -// has pthread_setname_np(pthread_t, const char*) (2 params) -#define FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME 1 -#endif -#endif - -#if defined(__APPLE__) && defined(__MAC_OS_X_VERSION_MIN_REQUIRED) -#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 -// has pthread_setname_np(const char*) (1 param) -#define FOLLY_HAS_PTHREAD_SETNAME_NP_NAME 1 -#endif -#endif - -template -inline bool setThreadName(T /* id */, StringPiece /* name */) { - static_assert( -#if FOLLY_HAVE_PTHREAD - std::is_same::value || -#endif - std::is_same::value || - std::is_same::value, - "type must be pthread_t, std::thread::id or " - "std::thread::native_handle_type"); - return false; -} - -template <> -inline bool setThreadName(std::thread::id tid, StringPiece name) { -#if !FOLLY_HAVE_PTHREAD - return false; -#else - static_assert( - std::is_same::value, - "This assumes that the native handle type is pthread_t"); - static_assert( - sizeof(std::thread::native_handle_type) == sizeof(std::thread::id), - "This assumes std::thread::id is a thin wrapper around " - "std::thread::native_handle_type, but that doesn't appear to be true."); - // In most implementations, std::thread::id is a thin wrapper around - // std::thread::native_handle_type, which means we can do unsafe things to - // extract it. - pthread_t id; - std::memcpy(&id, &tid, sizeof(id)); -#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME - return 0 == pthread_setname_np(id, name.fbstr().substr(0, 15).c_str()); -#elif FOLLY_HAS_PTHREAD_SETNAME_NP_NAME - // Since OS X 10.6 it is possible for a thread to set its own name, - // but not that of some other thread. - if (pthread_equal(pthread_self(), id)) { - return 0 == pthread_setname_np(name.fbstr().c_str()); - } - return false; -#else - return false; -#endif -#endif -} - +bool setThreadName(std::thread::id tid, StringPiece name); #if FOLLY_HAVE_PTHREAD -template <> -inline bool setThreadName(pthread_t pid, StringPiece name) { - static_assert( - std::is_same::value, - "This assumes that the native handle type is pthread_t"); - static_assert( - sizeof(std::thread::native_handle_type) == sizeof(std::thread::id), - "This assumes std::thread::id is a thin wrapper around " - "std::thread::native_handle_type, but that doesn't appear to be true."); - // In most implementations, std::thread::id is a thin wrapper around - // std::thread::native_handle_type, which means we can do unsafe things to - // extract it. - std::thread::id id; - std::memcpy(&id, &pid, sizeof(id)); - return setThreadName(id, name); -} +bool setThreadName(pthread_t pid, StringPiece name); #endif - -inline bool setThreadName(StringPiece name) { - return setThreadName(std::this_thread::get_id(), name); -} +bool setThreadName(StringPiece name); } diff --git a/folly/test/ThreadNameTest.cpp b/folly/test/ThreadNameTest.cpp index 1b3b043d..57eae214 100644 --- a/folly/test/ThreadNameTest.cpp +++ b/folly/test/ThreadNameTest.cpp @@ -24,22 +24,8 @@ using namespace std; using namespace folly; -static constexpr bool expectedSetOtherThreadNameResult = -#ifdef FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME - true -#else - false // This system has no known way to set the name of another thread -#endif - ; - -static constexpr bool expectedSetSelfThreadNameResult = -#if defined(FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME) || \ - defined(FOLLY_HAS_PTHREAD_SETNAME_NP_NAME) - true -#else - false // This system has no known way to set its own thread name -#endif - ; +static bool expectedSetOtherThreadNameResult = folly::canSetOtherThreadName(); +static bool expectedSetSelfThreadNameResult = folly::canSetCurrentThreadName(); TEST(ThreadName, setThreadName_self) { thread th([] { -- 2.34.1