Skip to content

Commit

Permalink
threads: introduce util/threadnames, refactor thread naming
Browse files Browse the repository at this point in the history
This work is prerequisite to attaching thread names to log lines and deadlock
debug utilities. This code allows setting of an "internal" threadname per
thread on platforms where thread_local is available.

This commit also moves RenameThread() out of a more general module and adds a
numeric suffix to disambiguate between threads with the same name. It
explicitly names a few main threads using the new util::ThreadRename().
  • Loading branch information
jamesob authored and dagurval committed Oct 28, 2020
1 parent aa8c976 commit 75a2b79
Show file tree
Hide file tree
Showing 14 changed files with 108 additions and 43 deletions.
5 changes: 4 additions & 1 deletion doc/release-notes.md
Expand Up @@ -18,7 +18,10 @@ Bitcoin Cash Node version 22.2.0 is now available from:

## Added functionality

...
### Thread names in logs

Log lines can be prefixed with the name of the thread that caused the log. To
enable this behavior, use`-logthreadnames=1`.

## Deprecated functionality

Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Expand Up @@ -321,6 +321,7 @@ add_library(util
uint256.cpp
util/system.cpp
util/moneystr.cpp
util/threadnames.cpp
util/strencodings.cpp
util/time.cpp
util/bytevectorhash.cpp
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.am
Expand Up @@ -222,6 +222,7 @@ BITCOIN_CORE_H = \
undo.h \
util/system.h \
util/moneystr.h \
util/threadnames.h \
util/time.h \
util/bitmanip.h \
util/bytevectorhash.h \
Expand Down Expand Up @@ -497,6 +498,7 @@ libbitcoin_util_a_SOURCES = \
util/system.cpp \
util/moneystr.cpp \
util/strencodings.cpp \
util/threadnames.cpp \
util/time.cpp \
util/bytevectorhash.cpp \
$(BITCOIN_CORE_H)
Expand Down
3 changes: 3 additions & 0 deletions src/bitcoind.cpp
Expand Up @@ -21,6 +21,7 @@
#include <shutdown.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <util/threadnames.h>
#include <walletinitinterface.h>

#include <cstdio>
Expand Down Expand Up @@ -72,6 +73,8 @@ static bool AppInit(int argc, char *argv[]) {

bool fRet = false;

util::ThreadRename("init");

//
// Parameters
//
Expand Down
13 changes: 8 additions & 5 deletions src/httpserver.cpp
Expand Up @@ -16,6 +16,7 @@
#include <ui_interface.h>
#include <util/strencodings.h>
#include <util/system.h>
#include <util/threadnames.h>

#include <event2/buffer.h>
#include <event2/bufferevent.h>
Expand Down Expand Up @@ -300,8 +301,9 @@ static void http_reject_request_cb(struct evhttp_request *req, void *) {
}

/** Event dispatcher thread */
static bool ThreadHTTP(struct event_base *base) {
RenameThread("bitcoin-http");
static bool ThreadHTTP(struct event_base* base)
{
util::ThreadRename("http");
LogPrint(BCLog::HTTP, "Entering http event loop\n");
event_base_dispatch(base);
// Event loop will be interrupted by InterruptHTTPServer()
Expand Down Expand Up @@ -357,8 +359,9 @@ static bool HTTPBindAddresses(struct evhttp *http) {
}

/** Simple wrapper to set thread name and run work queue */
static void HTTPWorkQueueRun(WorkQueue<HTTPClosure> *queue) {
RenameThread("bitcoin-httpworker");
static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue, int worker_num)
{
util::ThreadRename(strprintf("httpworker.%i", worker_num));
queue->Run();
}

Expand Down Expand Up @@ -462,7 +465,7 @@ void StartHTTPServer() {
threadHTTP = std::thread(ThreadHTTP, eventBase);

for (int i = 0; i < rpcThreads; i++) {
g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue);
g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue, i);
}
}

Expand Down
15 changes: 8 additions & 7 deletions src/init.cpp
Expand Up @@ -52,6 +52,7 @@
#include <ui_interface.h>
#include <util/moneystr.h>
#include <util/system.h>
#include <util/threadnames.h>
#include <validation.h>
#include <validationinterface.h>
#include <walletinitinterface.h>
Expand Down Expand Up @@ -206,11 +207,11 @@ void Shutdown(InitInterfaces &interfaces) {
return;
}

/// Note: Shutdown() must be able to handle cases in which initialization
/// failed part of the way, for example if the data directory was found to
/// be locked. Be sure that anything that writes files or flushes caches
/// only does this if the respective module was initialized.
RenameThread("bitcoin-shutoff");
/// Note: Shutdown() must be able to handle cases in which initialization failed part of the way,
/// for example if the data directory was found to be locked.
/// Be sure that anything that writes files or flushes caches only does this if the respective
/// module was initialized.
util::ThreadRename("shutoff");
g_mempool.AddTransactionsUpdated(1);

StopHTTPRPC();
Expand Down Expand Up @@ -1216,7 +1217,7 @@ static void CleanupBlockRevFiles() {

static void ThreadImport(const Config &config,
std::vector<fs::path> vImportFiles) {
RenameThread("bitcoin-loadblk");
util::ThreadRename("loadblk");
ScheduleBatchPriority();

{
Expand Down Expand Up @@ -2036,7 +2037,7 @@ bool AppInitMain(Config &config, RPCServer &rpcServer,
nScriptCheckThreads);
if (nScriptCheckThreads) {
for (int i = 0; i < nScriptCheckThreads - 1; i++) {
threadGroup.create_thread(&ThreadScriptCheck);
threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
}
}

Expand Down
3 changes: 3 additions & 0 deletions src/qt/bitcoin.cpp
Expand Up @@ -30,6 +30,7 @@
#include <ui_interface.h>
#include <uint256.h>
#include <util/system.h>
#include <util/threadnames.h>
#include <walletinitinterface.h>
#include <warnings.h>

Expand Down Expand Up @@ -163,6 +164,7 @@ void BitcoinCashNode::initialize(Config *config, RPCServer *rpcServer,
HTTPRPCRequestProcessor *httpRPCRequestProcessor) {
try {
qDebug() << __func__ << ": Running initialization in thread";
util::ThreadRename("qt-init");
bool rv =
m_node.appInitMain(*config, *rpcServer, *httpRPCRequestProcessor);
Q_EMIT initializeResult(rv);
Expand Down Expand Up @@ -516,6 +518,7 @@ int GuiMain(int argc, char *argv[]) {
std::tie(argc, argv) = winArgs.get();
#endif
SetupEnvironment();
util::ThreadRename("main");

std::unique_ptr<interfaces::Node> node = interfaces::MakeNode();

Expand Down
2 changes: 1 addition & 1 deletion src/test/setup_common.cpp
Expand Up @@ -123,7 +123,7 @@ TestingSetup::TestingSetup(const std::string &chainName)
}
nScriptCheckThreads = 3;
for (int i = 0; i < nScriptCheckThreads - 1; i++) {
threadGroup.create_thread(&ThreadScriptCheck);
threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
}

g_banman =
Expand Down
22 changes: 2 additions & 20 deletions src/util/system.cpp
Expand Up @@ -75,10 +75,6 @@
#include <shlobj.h>
#endif

#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif

#ifdef HAVE_MALLOPT_ARENA_MAX
#include <malloc.h>
#endif
Expand Down Expand Up @@ -1340,22 +1336,8 @@ void runCommand(const std::string &strCommand) {
}
}

void RenameThread(const char *name) {
#if defined(PR_SET_NAME)
// Only the first 15 characters are used (16 - NUL terminator)
::prctl(PR_SET_NAME, name, 0, 0, 0);
#elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
pthread_set_name_np(pthread_self(), name);

#elif defined(MAC_OSX)
pthread_setname_np(name);
#else
// Prevent warnings for unused parameters...
(void)name;
#endif
}

void SetupEnvironment() {
void SetupEnvironment()
{
#ifdef HAVE_MALLOPT_ARENA_MAX
// glibc-specific: On 32-bit systems set the number of arenas to 1. By
// default, since glibc 2.10, the C library will create up to two heap
Expand Down
12 changes: 6 additions & 6 deletions src/util/system.h
Expand Up @@ -20,6 +20,7 @@
#include <fs.h>
#include <logging.h>
#include <sync.h>
#include <util/threadnames.h>
#include <tinyformat.h>
#include <util/time.h>

Expand Down Expand Up @@ -345,15 +346,14 @@ std::string HelpMessageOpt(const std::string &option,
*/
int GetNumCores();

void RenameThread(const char *name);

/**
* .. and a wrapper that just calls func once
*/
template <typename Callable> void TraceThread(const char *name, Callable func) {
std::string s = strprintf("bitcoin-%s", name);
RenameThread(s.c_str());
try {
template <typename Callable> void TraceThread(const char* name, Callable func)
{
util::ThreadRename(name);
try
{
LogPrintf("%s thread start\n", name);
func();
LogPrintf("%s thread exit\n", name);
Expand Down
45 changes: 45 additions & 0 deletions src/util/threadnames.cpp
@@ -0,0 +1,45 @@
// Copyright (c) 2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/bitcoin-config.h>
#endif

#include <atomic>
#include <thread>

#include <util/threadnames.h>

#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h> // For prctl, PR_SET_NAME, PR_GET_NAME
#endif

//! Set the thread's name at the process level. Does not affect the
//! internal name.
static void SetThreadName(const char* name)
{
#if defined(PR_SET_NAME)
// Only the first 15 characters are used (16 - NUL terminator)
::prctl(PR_SET_NAME, name, 0, 0, 0);
#elif (defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__))
pthread_set_name_np(pthread_self(), name);
#elif defined(MAC_OSX)
pthread_setname_np(name);
#else
// Prevent warnings for unused parameters...
(void)name;
#endif
}

static thread_local std::string g_thread_name;
const std::string& util::ThreadGetInternalName() { return g_thread_name; }
//! Set the in-memory internal name for this thread. Does not affect the process
//! name.
static void SetInternalName(std::string name) { g_thread_name = std::move(name); }

void util::ThreadRename(std::string&& name)
{
SetThreadName(("bitcoin-" + name).c_str());
SetInternalName(std::move(name));
}
21 changes: 21 additions & 0 deletions src/util/threadnames.h
@@ -0,0 +1,21 @@
// Copyright (c) 2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_UTIL_THREADNAMES_H
#define BITCOIN_UTIL_THREADNAMES_H

#include <string>

namespace util {
//! Rename a thread both in terms of an internal (in-memory) name as well
//! as its system thread name.
void ThreadRename(std::string&&);

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

} // namespace util

#endif // BITCOIN_UTIL_THREADNAMES_H
5 changes: 3 additions & 2 deletions src/validation.cpp
Expand Up @@ -54,6 +54,7 @@
#include <atomic>
#include <future>
#include <sstream>
#include <string>
#include <thread>

#define MICRO 0.000001
Expand Down Expand Up @@ -1532,8 +1533,8 @@ static bool WriteUndoDataForBlock(const CBlockUndo &blockundo,

static CCheckQueue<CScriptCheck> scriptcheckqueue(128);

void ThreadScriptCheck() {
RenameThread("bitcoin-scriptch");
void ThreadScriptCheck(int worker_num) {
util::ThreadRename(strprintf("scriptch.%i", worker_num));
scriptcheckqueue.Thread();
}

Expand Down
2 changes: 1 addition & 1 deletion src/validation.h
Expand Up @@ -393,7 +393,7 @@ void UnloadBlockIndex();
/**
* Run an instance of the script checking thread.
*/
void ThreadScriptCheck();
void ThreadScriptCheck(int worker_num);

/**
* Check whether we are doing an initial block download (synchronizing from disk
Expand Down

0 comments on commit 75a2b79

Please sign in to comment.