#if !defined(_MSC_VER) #include "debugging.h" #include #include #include #include #if !(defined(__GLIBC__) || defined(__APPLE__)) // for pthread_getname_np_gcompat #include // errno #include // O_CLOEXEC, O_RDONLY #include // open, read #include #include #endif namespace cpputils { namespace { constexpr size_t MAX_NAME_LEN = 16; // this length includes the terminating null character at the end } void set_thread_name(const char* name) { std::string name_(name); if (name_.size() > MAX_NAME_LEN - 1) { name_.resize(MAX_NAME_LEN - 1); } #if defined(__APPLE__) int result = pthread_setname_np(name_.c_str()); #else int result = pthread_setname_np(pthread_self(), name_.c_str()); #endif if (0 != result) { throw std::runtime_error("Error setting thread name with pthread_setname_np. Code: " + std::to_string(result)); } } 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::array name{}; #if defined(__GLIBC__) || defined(__APPLE__) int result = pthread_getname_np(thread, name.data(), MAX_NAME_LEN); #else int result = pthread_getname_np_gcompat(thread, name.data(), MAX_NAME_LEN); #endif if (0 != result) { throw std::runtime_error("Error getting thread name with pthread_getname_np. Code: " + std::to_string(result)); } // pthread_getname_np returns a null terminated string with maximum 16 bytes. // but just to be safe against a buggy implementation, let's set the last byte to zero. name[MAX_NAME_LEN - 1] = '\0'; return name.data(); } } std::string get_thread_name() { return get_thread_name(pthread_self()); } #if defined(__GLIBC__) || defined(__APPLE__) std::string get_thread_name(std::thread* thread) { ASSERT(thread->joinable(), "Thread not running"); return get_thread_name(thread->native_handle()); } #endif } #endif