threads: introduce util/threadnames, refactor thread naming
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().
This commit is contained in:
parent
188ca75e5f
commit
ae5f2b6a6c
12 changed files with 103 additions and 36 deletions
|
@ -210,6 +210,7 @@ BITCOIN_CORE_H = \
|
||||||
util/memory.h \
|
util/memory.h \
|
||||||
util/moneystr.h \
|
util/moneystr.h \
|
||||||
util/rbf.h \
|
util/rbf.h \
|
||||||
|
util/threadnames.h \
|
||||||
util/time.h \
|
util/time.h \
|
||||||
util/url.h \
|
util/url.h \
|
||||||
util/validation.h \
|
util/validation.h \
|
||||||
|
@ -491,6 +492,7 @@ libbitcoin_util_a_SOURCES = \
|
||||||
util/system.cpp \
|
util/system.cpp \
|
||||||
util/moneystr.cpp \
|
util/moneystr.cpp \
|
||||||
util/rbf.cpp \
|
util/rbf.cpp \
|
||||||
|
util/threadnames.cpp \
|
||||||
util/strencodings.cpp \
|
util/strencodings.cpp \
|
||||||
util/time.cpp \
|
util/time.cpp \
|
||||||
util/url.cpp \
|
util/url.cpp \
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
#include <httpserver.h>
|
#include <httpserver.h>
|
||||||
#include <httprpc.h>
|
#include <httprpc.h>
|
||||||
|
#include <util/threadnames.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
#include <walletinitinterface.h>
|
#include <walletinitinterface.h>
|
||||||
|
|
||||||
|
@ -64,6 +65,8 @@ static bool AppInit(int argc, char* argv[])
|
||||||
|
|
||||||
bool fRet = false;
|
bool fRet = false;
|
||||||
|
|
||||||
|
util::ThreadRename("init");
|
||||||
|
|
||||||
//
|
//
|
||||||
// Parameters
|
// Parameters
|
||||||
//
|
//
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <chainparamsbase.h>
|
#include <chainparamsbase.h>
|
||||||
#include <compat.h>
|
#include <compat.h>
|
||||||
|
#include <util/threadnames.h>
|
||||||
#include <util/system.h>
|
#include <util/system.h>
|
||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
#include <netbase.h>
|
#include <netbase.h>
|
||||||
|
@ -17,7 +18,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
@ -284,7 +285,7 @@ static void http_reject_request_cb(struct evhttp_request* req, void*)
|
||||||
/** Event dispatcher thread */
|
/** Event dispatcher thread */
|
||||||
static bool ThreadHTTP(struct event_base* base)
|
static bool ThreadHTTP(struct event_base* base)
|
||||||
{
|
{
|
||||||
RenameThread("bitcoin-http");
|
util::ThreadRename("http");
|
||||||
LogPrint(BCLog::HTTP, "Entering http event loop\n");
|
LogPrint(BCLog::HTTP, "Entering http event loop\n");
|
||||||
event_base_dispatch(base);
|
event_base_dispatch(base);
|
||||||
// Event loop will be interrupted by InterruptHTTPServer()
|
// Event loop will be interrupted by InterruptHTTPServer()
|
||||||
|
@ -335,9 +336,9 @@ static bool HTTPBindAddresses(struct evhttp* http)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Simple wrapper to set thread name and run work queue */
|
/** Simple wrapper to set thread name and run work queue */
|
||||||
static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue)
|
static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue, int worker_num)
|
||||||
{
|
{
|
||||||
RenameThread("bitcoin-httpworker");
|
util::ThreadRename(strprintf("httpworker.%i", worker_num));
|
||||||
queue->Run();
|
queue->Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,7 +431,7 @@ void StartHTTPServer()
|
||||||
threadHTTP = std::thread(ThreadHTTP, eventBase);
|
threadHTTP = std::thread(ThreadHTTP, eventBase);
|
||||||
|
|
||||||
for (int i = 0; i < rpcThreads; i++) {
|
for (int i = 0; i < rpcThreads; i++) {
|
||||||
g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue);
|
g_thread_http_workers.emplace_back(HTTPWorkQueueRun, workQueue, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include <script/sigcache.h>
|
#include <script/sigcache.h>
|
||||||
#include <scheduler.h>
|
#include <scheduler.h>
|
||||||
#include <shutdown.h>
|
#include <shutdown.h>
|
||||||
|
#include <util/threadnames.h>
|
||||||
#include <timedata.h>
|
#include <timedata.h>
|
||||||
#include <txdb.h>
|
#include <txdb.h>
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
|
@ -208,7 +209,7 @@ void Shutdown(InitInterfaces& interfaces)
|
||||||
/// for example if the data directory was found to be locked.
|
/// 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
|
/// Be sure that anything that writes files or flushes caches only does this if the respective
|
||||||
/// module was initialized.
|
/// module was initialized.
|
||||||
RenameThread("bitcoin-shutoff");
|
util::ThreadRename("shutoff");
|
||||||
mempool.AddTransactionsUpdated(1);
|
mempool.AddTransactionsUpdated(1);
|
||||||
|
|
||||||
StopHTTPRPC();
|
StopHTTPRPC();
|
||||||
|
@ -669,7 +670,7 @@ static void CleanupBlockRevFiles()
|
||||||
static void ThreadImport(std::vector<fs::path> vImportFiles)
|
static void ThreadImport(std::vector<fs::path> vImportFiles)
|
||||||
{
|
{
|
||||||
const CChainParams& chainparams = Params();
|
const CChainParams& chainparams = Params();
|
||||||
RenameThread("bitcoin-loadblk");
|
util::ThreadRename("loadblk");
|
||||||
ScheduleBatchPriority();
|
ScheduleBatchPriority();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1305,7 +1306,7 @@ bool AppInitMain(InitInterfaces& interfaces)
|
||||||
LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads);
|
LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads);
|
||||||
if (nScriptCheckThreads) {
|
if (nScriptCheckThreads) {
|
||||||
for (int i=0; i<nScriptCheckThreads-1; i++)
|
for (int i=0; i<nScriptCheckThreads-1; i++)
|
||||||
threadGroup.create_thread(&ThreadScriptCheck);
|
threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start the lightweight task scheduler thread
|
// Start the lightweight task scheduler thread
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <interfaces/handler.h>
|
#include <interfaces/handler.h>
|
||||||
#include <interfaces/node.h>
|
#include <interfaces/node.h>
|
||||||
#include <noui.h>
|
#include <noui.h>
|
||||||
|
#include <util/threadnames.h>
|
||||||
#include <rpc/server.h>
|
#include <rpc/server.h>
|
||||||
#include <ui_interface.h>
|
#include <ui_interface.h>
|
||||||
#include <uint256.h>
|
#include <uint256.h>
|
||||||
|
@ -149,6 +150,7 @@ void BitcoinCore::initialize()
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
qDebug() << __func__ << ": Running initialization in thread";
|
qDebug() << __func__ << ": Running initialization in thread";
|
||||||
|
util::ThreadRename("qt-init");
|
||||||
bool rv = m_node.appInitMain();
|
bool rv = m_node.appInitMain();
|
||||||
Q_EMIT initializeResult(rv);
|
Q_EMIT initializeResult(rv);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
|
@ -423,6 +425,7 @@ int GuiMain(int argc, char* argv[])
|
||||||
std::tie(argc, argv) = winArgs.get();
|
std::tie(argc, argv) = winArgs.get();
|
||||||
#endif
|
#endif
|
||||||
SetupEnvironment();
|
SetupEnvironment();
|
||||||
|
util::ThreadRename("main");
|
||||||
|
|
||||||
std::unique_ptr<interfaces::Node> node = interfaces::MakeNode();
|
std::unique_ptr<interfaces::Node> node = interfaces::MakeNode();
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,7 @@ TestingSetup::TestingSetup(const std::string& chainName) : BasicTestingSetup(cha
|
||||||
|
|
||||||
nScriptCheckThreads = 3;
|
nScriptCheckThreads = 3;
|
||||||
for (int i = 0; i < nScriptCheckThreads - 1; i++)
|
for (int i = 0; i < nScriptCheckThreads - 1; i++)
|
||||||
threadGroup.create_thread(&ThreadScriptCheck);
|
threadGroup.create_thread([i]() { return ThreadScriptCheck(i); });
|
||||||
|
|
||||||
g_banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
|
g_banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", nullptr, DEFAULT_MISBEHAVING_BANTIME);
|
||||||
g_connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
|
g_connman = MakeUnique<CConnman>(0x1337, 0x1337); // Deterministic randomness for tests.
|
||||||
|
|
|
@ -60,10 +60,6 @@
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_SYS_PRCTL_H
|
|
||||||
#include <sys/prctl.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_MALLOPT_ARENA_MAX
|
#ifdef HAVE_MALLOPT_ARENA_MAX
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -1137,22 +1133,6 @@ void runCommand(const std::string& strCommand)
|
||||||
LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
|
LogPrintf("runCommand error: system(%s) returned %d\n", strCommand, nErr);
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
#ifdef HAVE_MALLOPT_ARENA_MAX
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <fs.h>
|
#include <fs.h>
|
||||||
#include <logging.h>
|
#include <logging.h>
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
|
#include <util/threadnames.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
#include <util/memory.h>
|
#include <util/memory.h>
|
||||||
#include <util/time.h>
|
#include <util/time.h>
|
||||||
|
@ -325,15 +326,12 @@ std::string HelpMessageOpt(const std::string& option, const std::string& message
|
||||||
*/
|
*/
|
||||||
int GetNumCores();
|
int GetNumCores();
|
||||||
|
|
||||||
void RenameThread(const char* name);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* .. and a wrapper that just calls func once
|
* .. and a wrapper that just calls func once
|
||||||
*/
|
*/
|
||||||
template <typename Callable> void TraceThread(const char* name, Callable func)
|
template <typename Callable> void TraceThread(const char* name, Callable func)
|
||||||
{
|
{
|
||||||
std::string s = strprintf("bitcoin-%s", name);
|
util::ThreadRename(name);
|
||||||
RenameThread(s.c_str());
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
LogPrintf("%s thread start\n", name);
|
LogPrintf("%s thread start\n", name);
|
||||||
|
|
57
src/util/threadnames.cpp
Normal file
57
src/util/threadnames.cpp
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have thread_local, just keep thread ID and name in a thread_local
|
||||||
|
// global.
|
||||||
|
#if defined(HAVE_THREAD_LOCAL)
|
||||||
|
|
||||||
|
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); }
|
||||||
|
|
||||||
|
// Without thread_local available, don't handle internal name at all.
|
||||||
|
#else
|
||||||
|
|
||||||
|
static const std::string empty_string;
|
||||||
|
const std::string& util::ThreadGetInternalName() { return empty_string; }
|
||||||
|
static void SetInternalName(std::string name) { }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void util::ThreadRename(std::string&& name)
|
||||||
|
{
|
||||||
|
SetThreadName(("bitcoin-" + name).c_str());
|
||||||
|
SetInternalName(std::move(name));
|
||||||
|
}
|
21
src/util/threadnames.h
Normal file
21
src/util/threadnames.h
Normal file
|
@ -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
|
|
@ -48,6 +48,7 @@
|
||||||
|
|
||||||
#include <future>
|
#include <future>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
|
@ -1654,8 +1655,8 @@ static bool WriteUndoDataForBlock(const CBlockUndo& blockundo, CValidationState&
|
||||||
|
|
||||||
static CCheckQueue<CScriptCheck> scriptcheckqueue(128);
|
static CCheckQueue<CScriptCheck> scriptcheckqueue(128);
|
||||||
|
|
||||||
void ThreadScriptCheck() {
|
void ThreadScriptCheck(int worker_num) {
|
||||||
RenameThread("bitcoin-scriptch");
|
util::ThreadRename(strprintf("scriptch.%i", worker_num));
|
||||||
scriptcheckqueue.Thread();
|
scriptcheckqueue.Thread();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -255,7 +255,7 @@ bool LoadChainTip(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_m
|
||||||
/** Unload database information */
|
/** Unload database information */
|
||||||
void UnloadBlockIndex();
|
void UnloadBlockIndex();
|
||||||
/** Run an instance of the script checking thread */
|
/** 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 or network) */
|
/** Check whether we are doing an initial block download (synchronizing from disk or network) */
|
||||||
bool IsInitialBlockDownload();
|
bool IsInitialBlockDownload();
|
||||||
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
|
/** Retrieve a transaction (from memory pool, or from disk, if possible) */
|
||||||
|
|
Loading…
Reference in a new issue