#endif
#endif
+namespace {
+
+#if FOLLY_HAVE_PTHREAD
+pthread_t stdTidToPthreadId(std::thread::id tid) {
+ 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));
+ return id;
+}
+#endif
+
+} // namespace
+
bool canSetCurrentThreadName() {
#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || \
FOLLY_HAS_PTHREAD_SETNAME_NP_NAME
static constexpr size_t kMaxThreadNameLength = 16;
-Optional<std::string> getCurrentThreadName() {
+Optional<std::string> getThreadName(std::thread::id id) {
#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || \
FOLLY_HAS_PTHREAD_SETNAME_NP_NAME
std::array<char, kMaxThreadNameLength> buf;
- if (pthread_getname_np(pthread_self(), buf.data(), buf.size()) != 0) {
+ if (pthread_getname_np(stdTidToPthreadId(id), buf.data(), buf.size()) != 0) {
return Optional<std::string>();
}
return make_optional(std::string(buf.data()));
#endif
}
+Optional<std::string> getCurrentThreadName() {
+ return getThreadName(std::this_thread::get_id());
+}
+
bool setThreadName(std::thread::id tid, StringPiece name) {
#if !FOLLY_HAVE_PTHREAD || _WIN32
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));
auto trimmedName = name.fbstr().substr(0, kMaxThreadNameLength - 1);
+ auto id = stdTidToPthreadId(tid);
#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME
return 0 == pthread_setname_np(id, trimmedName.c_str());
#elif FOLLY_HAS_PTHREAD_SETNAME_NP_NAME
}
return false;
#else
+ (void)id;
return false;
#endif
#endif
#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();
+
+/**
+ * Get the name of the given thread, or nothing if an error occurs
+ * or the functionality is not available.
+ */
+Optional<std::string> getThreadName(std::thread::id tid);
+
/**
- * Get the name of the current string, or nothing if an error occurs.
+ * Equivalent to getThreadName(std::this_thread::get_id());
*/
Optional<std::string> getCurrentThreadName();
+/**
+ * Set the name of the given thread.
+ * Returns false on failure, if an error occurs or the functionality
+ * is not available.
+ */
bool setThreadName(std::thread::id tid, StringPiece name);
#if FOLLY_HAVE_PTHREAD
bool setThreadName(pthread_t pid, StringPiece name);
#endif
+
+/**
+ * Equivalent to setThreadName(std::this_thread::get_id(), name);
+ */
bool setThreadName(StringPiece name);
}
using namespace std;
using namespace folly;
-static bool expectedSetOtherThreadNameResult = folly::canSetOtherThreadName();
-static bool expectedSetSelfThreadNameResult = folly::canSetCurrentThreadName();
+namespace {
+
+const bool expectedSetOtherThreadNameResult = folly::canSetOtherThreadName();
+const bool expectedSetSelfThreadNameResult = folly::canSetCurrentThreadName();
+constexpr StringPiece kThreadName{"rockin-thread"};
+
+} // namespace
TEST(ThreadName, getCurrentThreadName) {
- static constexpr StringPiece kThreadName{"rockin-thread"};
thread th([] {
EXPECT_EQ(expectedSetSelfThreadNameResult, setThreadName(kThreadName));
if (expectedSetSelfThreadNameResult) {
- EXPECT_EQ(kThreadName.toString(), getCurrentThreadName().value());
+ EXPECT_EQ(kThreadName.toString(), *getCurrentThreadName());
}
});
SCOPE_EXIT { th.join(); };
}
-TEST(ThreadName, setThreadName_self) {
- thread th([] {
- EXPECT_EQ(expectedSetSelfThreadNameResult, setThreadName("rockin-thread"));
- });
- SCOPE_EXIT { th.join(); };
-}
-
TEST(ThreadName, setThreadName_other_pthread) {
Baton<> handle_set;
Baton<> let_thread_end;
handle_set.wait();
SCOPE_EXIT { let_thread_end.post(); };
EXPECT_EQ(
- expectedSetOtherThreadNameResult, setThreadName(handle, "rockin-thread"));
-}
-
-TEST(ThreadName, setThreadName_other_native) {
- Baton<> let_thread_end;
- thread th([&] {
- let_thread_end.wait();
- });
- SCOPE_EXIT { th.join(); };
- SCOPE_EXIT { let_thread_end.post(); };
- EXPECT_EQ(
- expectedSetOtherThreadNameResult,
- setThreadName(th.native_handle(), "rockin-thread"));
+ expectedSetOtherThreadNameResult, setThreadName(handle, kThreadName));
}
TEST(ThreadName, setThreadName_other_id) {
SCOPE_EXIT { let_thread_end.post(); };
EXPECT_EQ(
expectedSetOtherThreadNameResult,
- setThreadName(th.get_id(), "rockin-thread"));
+ setThreadName(th.get_id(), kThreadName));
+ if (expectedSetOtherThreadNameResult) {
+ EXPECT_EQ(*getThreadName(th.get_id()), kThreadName);
+ }
}