Commit af5ec753 authored by Giuseppe Ottaviano's avatar Giuseppe Ottaviano Committed by Facebook Github Bot

Add support for getting other threads' names

Summary: Complete the `ThreadName.h` API.

Reviewed By: luciang, Orvid

Differential Revision: D5289160

fbshipit-source-id: a48e61093008039da50b1c568364fa5b8744b401
parent fc91e303
...@@ -40,6 +40,28 @@ namespace folly { ...@@ -40,6 +40,28 @@ namespace folly {
#endif #endif
#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() { bool canSetCurrentThreadName() {
#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || \ #if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || \
FOLLY_HAS_PTHREAD_SETNAME_NP_NAME FOLLY_HAS_PTHREAD_SETNAME_NP_NAME
...@@ -59,11 +81,11 @@ bool canSetOtherThreadName() { ...@@ -59,11 +81,11 @@ bool canSetOtherThreadName() {
static constexpr size_t kMaxThreadNameLength = 16; 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 || \ #if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME || \
FOLLY_HAS_PTHREAD_SETNAME_NP_NAME FOLLY_HAS_PTHREAD_SETNAME_NP_NAME
std::array<char, kMaxThreadNameLength> buf; 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 Optional<std::string>();
} }
return make_optional(std::string(buf.data())); return make_optional(std::string(buf.data()));
...@@ -72,23 +94,16 @@ Optional<std::string> getCurrentThreadName() { ...@@ -72,23 +94,16 @@ Optional<std::string> getCurrentThreadName() {
#endif #endif
} }
Optional<std::string> getCurrentThreadName() {
return getThreadName(std::this_thread::get_id());
}
bool setThreadName(std::thread::id tid, StringPiece name) { bool setThreadName(std::thread::id tid, StringPiece name) {
#if !FOLLY_HAVE_PTHREAD || _WIN32 #if !FOLLY_HAVE_PTHREAD || _WIN32
return false; return false;
#else #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 trimmedName = name.fbstr().substr(0, kMaxThreadNameLength - 1);
auto id = stdTidToPthreadId(tid);
#if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME #if FOLLY_HAS_PTHREAD_SETNAME_NP_THREAD_NAME
return 0 == pthread_setname_np(id, trimmedName.c_str()); return 0 == pthread_setname_np(id, trimmedName.c_str());
#elif FOLLY_HAS_PTHREAD_SETNAME_NP_NAME #elif FOLLY_HAS_PTHREAD_SETNAME_NP_NAME
...@@ -99,6 +114,7 @@ bool setThreadName(std::thread::id tid, StringPiece name) { ...@@ -99,6 +114,7 @@ bool setThreadName(std::thread::id tid, StringPiece name) {
} }
return false; return false;
#else #else
(void)id;
return false; return false;
#endif #endif
#endif #endif
......
...@@ -25,24 +25,42 @@ ...@@ -25,24 +25,42 @@
#include <folly/portability/PThread.h> #include <folly/portability/PThread.h>
namespace folly { namespace folly {
/** /**
* This returns true if the current platform supports setting the name of the * This returns true if the current platform supports setting the name of the
* current thread. * current thread.
*/ */
bool canSetCurrentThreadName(); bool canSetCurrentThreadName();
/** /**
* This returns true if the current platform supports setting the name of * This returns true if the current platform supports setting the name of
* threads other than the one currently executing. * threads other than the one currently executing.
*/ */
bool canSetOtherThreadName(); 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(); 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); bool setThreadName(std::thread::id tid, StringPiece name);
#if FOLLY_HAVE_PTHREAD #if FOLLY_HAVE_PTHREAD
bool setThreadName(pthread_t pid, StringPiece name); bool setThreadName(pthread_t pid, StringPiece name);
#endif #endif
/**
* Equivalent to setThreadName(std::this_thread::get_id(), name);
*/
bool setThreadName(StringPiece name); bool setThreadName(StringPiece name);
} }
...@@ -24,27 +24,24 @@ ...@@ -24,27 +24,24 @@
using namespace std; using namespace std;
using namespace folly; using namespace folly;
static bool expectedSetOtherThreadNameResult = folly::canSetOtherThreadName(); namespace {
static bool expectedSetSelfThreadNameResult = folly::canSetCurrentThreadName();
const bool expectedSetOtherThreadNameResult = folly::canSetOtherThreadName();
const bool expectedSetSelfThreadNameResult = folly::canSetCurrentThreadName();
constexpr StringPiece kThreadName{"rockin-thread"};
} // namespace
TEST(ThreadName, getCurrentThreadName) { TEST(ThreadName, getCurrentThreadName) {
static constexpr StringPiece kThreadName{"rockin-thread"};
thread th([] { thread th([] {
EXPECT_EQ(expectedSetSelfThreadNameResult, setThreadName(kThreadName)); EXPECT_EQ(expectedSetSelfThreadNameResult, setThreadName(kThreadName));
if (expectedSetSelfThreadNameResult) { if (expectedSetSelfThreadNameResult) {
EXPECT_EQ(kThreadName.toString(), getCurrentThreadName().value()); EXPECT_EQ(kThreadName.toString(), *getCurrentThreadName());
} }
}); });
SCOPE_EXIT { th.join(); }; 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) { TEST(ThreadName, setThreadName_other_pthread) {
Baton<> handle_set; Baton<> handle_set;
Baton<> let_thread_end; Baton<> let_thread_end;
...@@ -58,19 +55,7 @@ TEST(ThreadName, setThreadName_other_pthread) { ...@@ -58,19 +55,7 @@ TEST(ThreadName, setThreadName_other_pthread) {
handle_set.wait(); handle_set.wait();
SCOPE_EXIT { let_thread_end.post(); }; SCOPE_EXIT { let_thread_end.post(); };
EXPECT_EQ( EXPECT_EQ(
expectedSetOtherThreadNameResult, setThreadName(handle, "rockin-thread")); expectedSetOtherThreadNameResult, setThreadName(handle, kThreadName));
}
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"));
} }
TEST(ThreadName, setThreadName_other_id) { TEST(ThreadName, setThreadName_other_id) {
...@@ -82,5 +67,8 @@ TEST(ThreadName, setThreadName_other_id) { ...@@ -82,5 +67,8 @@ TEST(ThreadName, setThreadName_other_id) {
SCOPE_EXIT { let_thread_end.post(); }; SCOPE_EXIT { let_thread_end.post(); };
EXPECT_EQ( EXPECT_EQ(
expectedSetOtherThreadNameResult, expectedSetOtherThreadNameResult,
setThreadName(th.get_id(), "rockin-thread")); setThreadName(th.get_id(), kThreadName));
if (expectedSetOtherThreadNameResult) {
EXPECT_EQ(*getThreadName(th.get_id()), kThreadName);
}
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment