Skip to content

Commit d35ba1b

Browse files
committed
util: avoid using thread_local variable that has a destructor
Store the thread name in a `thread_local` variable of type `char[]` instead of `std::string`. This avoids calling the destructor when the thread exits. This is a workaround for https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=278701 For type-safety, return `std::string` from `util::ThreadGetInternalName()` instead of `char[]`. As a side effect of this change, we no longer store a reference to a `thread_local` variable in `CLockLocation`. This was dangerous because if the thread quits while the reference still exists (in the global variable `lock_data`, see inside `GetLockData()`) then the reference will become dangling.
1 parent b940619 commit d35ba1b

File tree

4 files changed

+27
-21
lines changed

4 files changed

+27
-21
lines changed

configure.ac

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1049,11 +1049,6 @@ if test "$use_thread_local" = "yes" || test "$use_thread_local" = "auto"; then
10491049
dnl https://gist.github.com/jamesob/fe9a872051a88b2025b1aa37bfa98605
10501050
AC_MSG_RESULT([no])
10511051
;;
1052-
*freebsd*)
1053-
dnl FreeBSD's implementation of thread_local is also buggy (per
1054-
dnl https://groups.google.com/d/msg/bsdmailinglist/22ncTZAbDp4/Dii_pII5AwAJ)
1055-
AC_MSG_RESULT([no])
1056-
;;
10571052
*)
10581053
AC_DEFINE([HAVE_THREAD_LOCAL], [1], [Define if thread_local is supported.])
10591054
AC_MSG_RESULT([yes])

src/sync.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@ struct CLockLocation {
3737
const char* pszFile,
3838
int nLine,
3939
bool fTryIn,
40-
const std::string& thread_name)
40+
std::string&& thread_name)
4141
: fTry(fTryIn),
4242
mutexName(pszName),
4343
sourceFile(pszFile),
44-
m_thread_name(thread_name),
44+
m_thread_name(std::move(thread_name)),
4545
sourceLine(nLine) {}
4646

4747
std::string ToString() const
@@ -60,7 +60,7 @@ struct CLockLocation {
6060
bool fTry;
6161
std::string mutexName;
6262
std::string sourceFile;
63-
const std::string& m_thread_name;
63+
const std::string m_thread_name;
6464
int sourceLine;
6565
};
6666

src/util/threadnames.cpp

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
#include <config/bitcoin-config.h> // IWYU pragma: keep
66

7+
#include <cstring>
78
#include <string>
89
#include <thread>
910
#include <utility>
@@ -40,27 +41,37 @@ static void SetThreadName(const char* name)
4041
// global.
4142
#if defined(HAVE_THREAD_LOCAL)
4243

43-
static thread_local std::string g_thread_name;
44-
const std::string& util::ThreadGetInternalName() { return g_thread_name; }
44+
/**
45+
* The name of the thread. We use char array instead of std::string to avoid
46+
* complications with running a destructor when the thread exits. Avoid adding
47+
* other thread_local variables.
48+
* @see https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=278701
49+
*/
50+
static thread_local char g_thread_name[128]{'\0'};
51+
std::string util::ThreadGetInternalName() { return g_thread_name; }
4552
//! Set the in-memory internal name for this thread. Does not affect the process
4653
//! name.
47-
static void SetInternalName(std::string name) { g_thread_name = std::move(name); }
54+
static void SetInternalName(const std::string& name)
55+
{
56+
const size_t copy_bytes{std::min(sizeof(g_thread_name) - 1, name.length())};
57+
std::memcpy(g_thread_name, name.data(), copy_bytes);
58+
g_thread_name[copy_bytes] = '\0';
59+
}
4860

4961
// Without thread_local available, don't handle internal name at all.
5062
#else
5163

52-
static const std::string empty_string;
53-
const std::string& util::ThreadGetInternalName() { return empty_string; }
54-
static void SetInternalName(std::string name) { }
64+
std::string util::ThreadGetInternalName() { return ""; }
65+
static void SetInternalName(const std::string& name) { }
5566
#endif
5667

57-
void util::ThreadRename(std::string&& name)
68+
void util::ThreadRename(const std::string& name)
5869
{
5970
SetThreadName(("b-" + name).c_str());
60-
SetInternalName(std::move(name));
71+
SetInternalName(name);
6172
}
6273

63-
void util::ThreadSetInternalName(std::string&& name)
74+
void util::ThreadSetInternalName(const std::string& name)
6475
{
65-
SetInternalName(std::move(name));
76+
SetInternalName(name);
6677
}

src/util/threadnames.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ namespace util {
1212
//! as its system thread name.
1313
//! @note Do not call this for the main thread, as this will interfere with
1414
//! UNIX utilities such as top and killall. Use ThreadSetInternalName instead.
15-
void ThreadRename(std::string&&);
15+
void ThreadRename(const std::string&);
1616

1717
//! Set the internal (in-memory) name of the current thread only.
18-
void ThreadSetInternalName(std::string&&);
18+
void ThreadSetInternalName(const std::string&);
1919

2020
//! Get the thread's internal (in-memory) name; used e.g. for identification in
2121
//! logging.
22-
const std::string& ThreadGetInternalName();
22+
std::string ThreadGetInternalName();
2323

2424
} // namespace util
2525

0 commit comments

Comments
 (0)