Shift the implementation of setThreadName out of the header
authorChristopher Dykes <cdykes@fb.com>
Tue, 25 Apr 2017 01:41:06 +0000 (18:41 -0700)
committerFacebook Github Bot <facebook-github-bot@users.noreply.github.com>
Tue, 25 Apr 2017 01:50:03 +0000 (18:50 -0700)
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
folly/ThreadName.cpp [new file with mode: 0644]
folly/ThreadName.h
folly/test/ThreadNameTest.cpp

index 3d5fd9b..692a719 100644 (file)
@@ -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 (file)
index 0000000..acd6163
--- /dev/null
@@ -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 <folly/ThreadName.h>
+
+#include <type_traits>
+
+#include <folly/Portability.h>
+#include <folly/Traits.h>
+#include <folly/portability/PThread.h>
+
+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<pthread_t, std::thread::native_handle_type>::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<pthread_t, std::thread::native_handle_type>::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);
+}
+}
index 52b0cda..b55793c 100644 (file)
 #pragma once
 
 #include <thread>
-#include <type_traits>
 
 #include <folly/Range.h>
-#include <folly/Traits.h>
 #include <folly/portability/Config.h>
 #include <folly/portability/PThread.h>
 
 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 <typename T>
-inline bool setThreadName(T /* id */, StringPiece /* name */) {
-  static_assert(
-#if FOLLY_HAVE_PTHREAD
-      std::is_same<T, pthread_t>::value ||
-#endif
-      std::is_same<T, std::thread::id>::value ||
-      std::is_same<T, std::thread::native_handle_type>::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<pthread_t, std::thread::native_handle_type>::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<pthread_t, std::thread::native_handle_type>::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);
 }
index 1b3b043..57eae21 100644 (file)
 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([] {