Implement pthread_getname_np_gcompat for musl (#255)
This commit is contained in:
parent
ae680a5bdc
commit
9ee345e16a
@ -9,7 +9,11 @@ namespace cpputils {
|
|||||||
|
|
||||||
void set_thread_name(const char* name);
|
void set_thread_name(const char* name);
|
||||||
std::string get_thread_name();
|
std::string get_thread_name();
|
||||||
|
|
||||||
|
#if defined(__GLIBC__) || defined(__APPLE__) || defined(_MSC_VER)
|
||||||
|
// this is not supported on musl systems, that's why we ifdef it for glibc only.
|
||||||
std::string get_thread_name(std::thread* thread);
|
std::string get_thread_name(std::thread* thread);
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,14 @@
|
|||||||
#include <thread>
|
#include <thread>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <cpp-utils/assert/assert.h>
|
#include <cpp-utils/assert/assert.h>
|
||||||
|
#if !(defined(__GLIBC__) || defined(__APPLE__))
|
||||||
|
// for pthread_getname_np_gcompat
|
||||||
|
#include <errno.h> // errno
|
||||||
|
#include <fcntl.h> // O_CLOEXEC, O_RDONLY
|
||||||
|
#include <unistd.h> // open, read
|
||||||
|
#include <boost/filesystem/path.hpp>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace cpputils {
|
namespace cpputils {
|
||||||
|
|
||||||
@ -28,9 +36,47 @@ void set_thread_name(const char* name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
#if !(defined(__GLIBC__) || defined(__APPLE__))
|
||||||
|
|
||||||
|
struct OpenFileRAII final {
|
||||||
|
explicit OpenFileRAII(const char* filename) : fd(::open(filename, O_RDONLY | O_CLOEXEC)) {}
|
||||||
|
~OpenFileRAII() {
|
||||||
|
int result = close(fd);
|
||||||
|
if (result != 0) {
|
||||||
|
throw std::runtime_error("Error closing file. Errno: " + std::to_string(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
// get the name of a thread
|
||||||
|
int pthread_getname_np_gcompat(pthread_t thread, char *name, size_t len) {
|
||||||
|
ASSERT(thread == pthread_self(), "On musl systems, it's only supported to get the name of the current thread.");
|
||||||
|
|
||||||
|
auto file = OpenFileRAII("/proc/thread-self/comm");
|
||||||
|
ssize_t n;
|
||||||
|
if (file.fd < 0)
|
||||||
|
return errno;
|
||||||
|
n = read(file.fd, name, len);
|
||||||
|
if (n < 0)
|
||||||
|
return errno;
|
||||||
|
// if the trailing newline was not read, the buffer was too small
|
||||||
|
if (n == 0 || name[n - 1] != '\n')
|
||||||
|
return ERANGE;
|
||||||
|
// null-terminate string
|
||||||
|
name[n - 1] = '\0';
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
std::string get_thread_name(pthread_t thread) {
|
std::string get_thread_name(pthread_t thread) {
|
||||||
char name[MAX_NAME_LEN];
|
char name[MAX_NAME_LEN];
|
||||||
|
#if defined(__GLIBC__) || defined(__APPLE__)
|
||||||
int result = pthread_getname_np(thread, name, MAX_NAME_LEN);
|
int result = pthread_getname_np(thread, name, MAX_NAME_LEN);
|
||||||
|
#else
|
||||||
|
int result = pthread_getname_np_gcompat(thread, name, MAX_NAME_LEN);
|
||||||
|
#endif
|
||||||
if (0 != result) {
|
if (0 != result) {
|
||||||
throw std::runtime_error("Error getting thread name with pthread_getname_np. Code: " + std::to_string(result));
|
throw std::runtime_error("Error getting thread name with pthread_getname_np. Code: " + std::to_string(result));
|
||||||
}
|
}
|
||||||
@ -39,16 +85,19 @@ std::string get_thread_name(pthread_t thread) {
|
|||||||
name[MAX_NAME_LEN - 1] = '\0';
|
name[MAX_NAME_LEN - 1] = '\0';
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string get_thread_name() {
|
std::string get_thread_name() {
|
||||||
return get_thread_name(pthread_self());
|
return get_thread_name(pthread_self());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(__GLIBC__) || defined(__APPLE__)
|
||||||
std::string get_thread_name(std::thread* thread) {
|
std::string get_thread_name(std::thread* thread) {
|
||||||
ASSERT(thread->joinable(), "Thread not running");
|
ASSERT(thread->joinable(), "Thread not running");
|
||||||
return get_thread_name(thread->native_handle());
|
return get_thread_name(thread->native_handle());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,24 @@ TEST(ThreadDebuggingTest_ThreadName, givenMainThread_whenSettingAndGetting_thenD
|
|||||||
get_thread_name();
|
get_thread_name();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ThreadDebuggingTest_ThreadName, givenMainThread_whenGettingFromInside_thenIsCorrect) {
|
||||||
|
set_thread_name("my_thread_name");
|
||||||
|
string name = get_thread_name();
|
||||||
|
EXPECT_EQ("my_thread_name", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenGettingFromInside_thenIsCorrect) {
|
||||||
|
std::thread child([] {
|
||||||
|
set_thread_name("my_thread_name");
|
||||||
|
string name = get_thread_name();
|
||||||
|
EXPECT_EQ("my_thread_name", name);
|
||||||
|
});
|
||||||
|
child.join();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__GLIBC__) || defined(__APPLE__) || defined(_MSC_VER)
|
||||||
|
// disabled on musl because getting the thread name for a child thread doesn't work there
|
||||||
TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenSettingAndGetting_thenDoesntCrash) {
|
TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenSettingAndGetting_thenDoesntCrash) {
|
||||||
ConditionBarrier nameIsChecked;
|
ConditionBarrier nameIsChecked;
|
||||||
|
|
||||||
@ -27,37 +45,22 @@ TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenSettingAndGetting_then
|
|||||||
EXPECT_TRUE(child_didnt_crash);
|
EXPECT_TRUE(child_didnt_crash);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ThreadDebuggingTest_ThreadName, givenMainThread_whenGettingFromInside_thenIsCorrect) {
|
|
||||||
set_thread_name("my_thread_name");
|
|
||||||
string name = get_thread_name();
|
|
||||||
EXPECT_EQ("my_thread_name", name);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenGettingFromInside_thenIsCorrect) {
|
|
||||||
std::thread child([] {
|
|
||||||
set_thread_name("my_thread_name");
|
|
||||||
string name = get_thread_name();
|
|
||||||
EXPECT_EQ("my_thread_name", name);
|
|
||||||
});
|
|
||||||
child.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenGettingFromOutside_thenIsCorrect) {
|
TEST(ThreadDebuggingTest_ThreadName, givenChildThread_whenGettingFromOutside_thenIsCorrect) {
|
||||||
ConditionBarrier nameIsSet;
|
ConditionBarrier nameIsSet;
|
||||||
ConditionBarrier nameIsChecked;
|
ConditionBarrier nameIsChecked;
|
||||||
|
|
||||||
std::thread child([&] {
|
std::thread child([&] {
|
||||||
set_thread_name("my_thread_name");
|
set_thread_name("my_thread_name");
|
||||||
nameIsSet.release();
|
nameIsSet.release();
|
||||||
nameIsChecked.wait();
|
nameIsChecked.wait();
|
||||||
});
|
});
|
||||||
|
|
||||||
nameIsSet.wait();
|
nameIsSet.wait();
|
||||||
set_thread_name("outer_thread_name"); // just to make sure the next line doesn't read the outer thread name
|
set_thread_name("outer_thread_name"); // just to make sure the next line doesn't read the outer thread name
|
||||||
string name = get_thread_name(&child);
|
string name = get_thread_name(&child);
|
||||||
EXPECT_EQ("my_thread_name", name);
|
EXPECT_EQ("my_thread_name", name);
|
||||||
|
|
||||||
nameIsChecked.release();
|
nameIsChecked.release();
|
||||||
child.join();
|
child.join();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user