mirror of
https://github.com/XRPLF/rippled.git
synced 2026-04-29 15:37:57 +00:00
fix: Truncate thread name to 15 chars on Linux (#5758)
This change: * Truncates thread names if more than 15 chars with `snprintf`. * Adds warnings for truncated thread names if `-DTRUNCATED_THREAD_NAME_LOGS=ON`. * Add a static assert for string literals to stop compiling if > 15 chars. * Shortens `Resource::Manager` to `Resource::Mngr` to fix the static assert failure. * Updates `CurrentThreadName_test` unit test specifically for Linux to verify truncation.
This commit is contained in:
@@ -68,6 +68,21 @@ if(is_linux)
|
||||
option(perf "Enables flags that assist with perf recording" OFF)
|
||||
option(use_gold "enables detection of gold (binutils) linker" ON)
|
||||
option(use_mold "enables detection of mold (binutils) linker" ON)
|
||||
# Set a default value for the log flag based on the build type.
|
||||
# This provides a sensible default (on for debug, off for release)
|
||||
# while still allowing the user to override it for any build.
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(TRUNCATED_LOGS_DEFAULT ON)
|
||||
else()
|
||||
set(TRUNCATED_LOGS_DEFAULT OFF)
|
||||
endif()
|
||||
option(TRUNCATED_THREAD_NAME_LOGS
|
||||
"Show warnings about truncated thread names on Linux."
|
||||
${TRUNCATED_LOGS_DEFAULT}
|
||||
)
|
||||
if(TRUNCATED_THREAD_NAME_LOGS)
|
||||
add_compile_definitions(TRUNCATED_THREAD_NAME_LOGS)
|
||||
endif()
|
||||
else()
|
||||
# we are not ready to allow shared-libs on windows because it would require
|
||||
# export declarations. On macos it's more feasible, but static openssl
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
#ifndef BEAST_CORE_CURRENT_THREAD_NAME_H_INCLUDED
|
||||
#define BEAST_CORE_CURRENT_THREAD_NAME_H_INCLUDED
|
||||
|
||||
#include <boost/predef.h>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
@@ -35,6 +37,31 @@ namespace beast {
|
||||
void
|
||||
setCurrentThreadName(std::string_view newThreadName);
|
||||
|
||||
#if BOOST_OS_LINUX
|
||||
|
||||
// On Linux, thread names are limited to 16 bytes including the null terminator.
|
||||
// Maximum number of characters is therefore 15.
|
||||
constexpr std::size_t maxThreadNameLength = 15;
|
||||
|
||||
/** Sets the name of the caller thread with compile-time size checking.
|
||||
@tparam N The size of the string literal including null terminator
|
||||
@param newThreadName A string literal to set as the thread name
|
||||
|
||||
This template overload enforces that thread names are at most 16 characters
|
||||
(including null terminator) at compile time, matching Linux's limit.
|
||||
*/
|
||||
template <std::size_t N>
|
||||
void
|
||||
setCurrentThreadName(char const (&newThreadName)[N])
|
||||
{
|
||||
static_assert(
|
||||
N <= maxThreadNameLength + 1,
|
||||
"Thread name cannot exceed 15 characters");
|
||||
|
||||
setCurrentThreadName(std::string_view(newThreadName, N - 1));
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Returns the name of the caller thread.
|
||||
|
||||
The name returned is the name as set by a call to setCurrentThreadName().
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
|
||||
#include <xrpl/beast/core/CurrentThreadName.h>
|
||||
|
||||
#include <boost/predef.h>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
@@ -96,12 +94,32 @@ setCurrentThreadNameImpl(std::string_view name)
|
||||
#if BOOST_OS_LINUX
|
||||
#include <pthread.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace beast::detail {
|
||||
|
||||
inline void
|
||||
setCurrentThreadNameImpl(std::string_view name)
|
||||
{
|
||||
pthread_setname_np(pthread_self(), name.data());
|
||||
// truncate and set the thread name.
|
||||
char boundedName[maxThreadNameLength + 1];
|
||||
std::snprintf(
|
||||
boundedName,
|
||||
sizeof(boundedName),
|
||||
"%.*s",
|
||||
static_cast<int>(maxThreadNameLength),
|
||||
name.data());
|
||||
|
||||
pthread_setname_np(pthread_self(), boundedName);
|
||||
|
||||
#ifdef TRUNCATED_THREAD_NAME_LOGS
|
||||
if (name.size() > maxThreadNameLength)
|
||||
{
|
||||
std::cerr << "WARNING: Thread name \"" << name << "\" (length "
|
||||
<< name.size() << ") exceeds maximum of "
|
||||
<< maxThreadNameLength << " characters on Linux.\n";
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace beast::detail
|
||||
|
||||
@@ -159,7 +159,7 @@ private:
|
||||
void
|
||||
run()
|
||||
{
|
||||
beast::setCurrentThreadName("Resource::Manager");
|
||||
beast::setCurrentThreadName("Resource::Mngr");
|
||||
for (;;)
|
||||
{
|
||||
logic_.periodicActivity();
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <xrpl/beast/core/CurrentThreadName.h>
|
||||
#include <xrpl/beast/unit_test.h>
|
||||
|
||||
#include <boost/predef/os.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace ripple {
|
||||
@@ -56,33 +58,71 @@ private:
|
||||
if (beast::getCurrentThreadName() == myName)
|
||||
*state = 2;
|
||||
}
|
||||
#if BOOST_OS_LINUX
|
||||
// Helper function to test a specific name.
|
||||
// It creates a thread, sets the name, and checks if the OS-level
|
||||
// name matches the expected (potentially truncated) name.
|
||||
void
|
||||
testName(std::string const& nameToSet, std::string const& expectedName)
|
||||
{
|
||||
std::thread t([&] {
|
||||
beast::setCurrentThreadName(nameToSet);
|
||||
|
||||
// Initialize buffer to be safe.
|
||||
char actualName[beast::maxThreadNameLength + 1] = {};
|
||||
pthread_getname_np(pthread_self(), actualName, sizeof(actualName));
|
||||
|
||||
BEAST_EXPECT(std::string(actualName) == expectedName);
|
||||
});
|
||||
t.join();
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
// Make two different threads with two different names. Make sure
|
||||
// that the expected thread names are still there when the thread
|
||||
// exits.
|
||||
std::atomic<bool> stop{false};
|
||||
// Make two different threads with two different names.
|
||||
// Make sure that the expected thread names are still there
|
||||
// when the thread exits.
|
||||
{
|
||||
std::atomic<bool> stop{false};
|
||||
|
||||
std::atomic<int> stateA{0};
|
||||
std::thread tA(exerciseName, "tA", &stop, &stateA);
|
||||
std::atomic<int> stateA{0};
|
||||
std::thread tA(exerciseName, "tA", &stop, &stateA);
|
||||
|
||||
std::atomic<int> stateB{0};
|
||||
std::thread tB(exerciseName, "tB", &stop, &stateB);
|
||||
std::atomic<int> stateB{0};
|
||||
std::thread tB(exerciseName, "tB", &stop, &stateB);
|
||||
|
||||
// Wait until both threads have set their names.
|
||||
while (stateA == 0 || stateB == 0)
|
||||
;
|
||||
// Wait until both threads have set their names.
|
||||
while (stateA == 0 || stateB == 0)
|
||||
;
|
||||
|
||||
stop = true;
|
||||
tA.join();
|
||||
tB.join();
|
||||
stop = true;
|
||||
tA.join();
|
||||
tB.join();
|
||||
|
||||
// Both threads should still have the expected name when they exit.
|
||||
BEAST_EXPECT(stateA == 2);
|
||||
BEAST_EXPECT(stateB == 2);
|
||||
// Both threads should still have the expected name when they exit.
|
||||
BEAST_EXPECT(stateA == 2);
|
||||
BEAST_EXPECT(stateB == 2);
|
||||
}
|
||||
#if BOOST_OS_LINUX
|
||||
// On Linux, verify that thread names longer than 15 characters
|
||||
// are truncated to 15 characters (the 16th character is reserved for
|
||||
// the null terminator).
|
||||
{
|
||||
testName(
|
||||
"123456789012345",
|
||||
"123456789012345"); // 15 chars, no truncation
|
||||
testName(
|
||||
"1234567890123456", "123456789012345"); // 16 chars, truncated
|
||||
testName(
|
||||
"ThisIsAVeryLongThreadNameExceedingLimit",
|
||||
"ThisIsAVeryLong"); // 39 chars, truncated
|
||||
testName("", ""); // empty name
|
||||
testName("short", "short"); // short name, no truncation
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user