forked from lix-project/lix
unnamed threads: Obliterate
Ever read gdb output and you just kinda get a headache because you have
to infer what a thread is by reading the stack trace? It's not hard, but
we could also just never have to do that again, which is also not hard.
Sample:
(gdb) info thr
Id Target Id Frame
* 1 LWP 3719283 "nix-daemon" 0x00007e558587da0f in accept ()
from target:/nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib/libc.so.6
2 LWP 3719284 "signal handler" 0x00007e55857b2bea in sigtimedwait ()
from target:/nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib/libc.so.6
The API design for this is forced by the macOS pthread_setname_np only
being able to change the current thread's name, but if we just conform
everything to that, it works everywhere.
Change-Id: I2b1d6ed41e3c94170cb0b4e73ad66f239ebd9c88
This commit is contained in:
parent
6a9b66357e
commit
519957bd59
17
doc/manual/rl-next/thread-names.md
Normal file
17
doc/manual/rl-next/thread-names.md
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
synopsis: All Lix threads are named
|
||||||
|
cls: [2210]
|
||||||
|
category: Development
|
||||||
|
credits: [jade]
|
||||||
|
---
|
||||||
|
|
||||||
|
Lix now sets thread names on all of its secondary threads, which will make debugger usage slightly nicer and easier.
|
||||||
|
|
||||||
|
```
|
||||||
|
(gdb) info thr
|
||||||
|
Id Target Id Frame
|
||||||
|
* 1 LWP 3719283 "nix-daemon" 0x00007e558587da0f in accept ()
|
||||||
|
from target:/nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib/libc.so.6
|
||||||
|
2 LWP 3719284 "signal handler" 0x00007e55857b2bea in sigtimedwait ()
|
||||||
|
from target:/nix/store/c10zhkbp6jmyh0xc5kd123ga8yy2p4hk-glibc-2.39-52/lib/libc.so.6
|
||||||
|
```
|
|
@ -4,6 +4,7 @@
|
||||||
#include "lix/libstore/names.hh"
|
#include "lix/libstore/names.hh"
|
||||||
#include "lix/libutil/terminal.hh"
|
#include "lix/libutil/terminal.hh"
|
||||||
#include "lix/libutil/strings.hh"
|
#include "lix/libutil/strings.hh"
|
||||||
|
#include "lix/libutil/thread-name.hh"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
@ -84,6 +85,7 @@ void ProgressBar::resume()
|
||||||
if (state->paused > 0) return; // recursive pause, wait for the parents to resume too
|
if (state->paused > 0) return; // recursive pause, wait for the parents to resume too
|
||||||
state->haveUpdate = true;
|
state->haveUpdate = true;
|
||||||
updateThread = std::thread([&]() {
|
updateThread = std::thread([&]() {
|
||||||
|
setCurrentThreadName("progress bar");
|
||||||
auto state(state_.lock());
|
auto state(state_.lock());
|
||||||
auto nextWakeup = A_LONG_TIME;
|
auto nextWakeup = A_LONG_TIME;
|
||||||
while (state->paused == 0) {
|
while (state->paused == 0) {
|
||||||
|
|
|
@ -196,7 +196,7 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
|
||||||
|
|
||||||
if (narAccessor->stat(buildIdDir).type == FSAccessor::tDirectory) {
|
if (narAccessor->stat(buildIdDir).type == FSAccessor::tDirectory) {
|
||||||
|
|
||||||
ThreadPool threadPool(25);
|
ThreadPool threadPool("write debuginfo pool", 25);
|
||||||
|
|
||||||
auto doFile = [&](std::string member, std::string key, std::string target) {
|
auto doFile = [&](std::string member, std::string key, std::string target) {
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "lix/libutil/unix-domain-socket.hh"
|
#include "lix/libutil/unix-domain-socket.hh"
|
||||||
#include "lix/libutil/mount.hh"
|
#include "lix/libutil/mount.hh"
|
||||||
#include "lix/libutil/strings.hh"
|
#include "lix/libutil/strings.hh"
|
||||||
|
#include "lix/libutil/thread-name.hh"
|
||||||
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
@ -1224,6 +1225,7 @@ void LocalDerivationGoal::startDaemon()
|
||||||
chownToBuilder(socketPath);
|
chownToBuilder(socketPath);
|
||||||
|
|
||||||
daemonThread = std::thread([this, store]() {
|
daemonThread = std::thread([this, store]() {
|
||||||
|
setCurrentThreadName("recursive nix daemon");
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
|
@ -1244,6 +1246,7 @@ void LocalDerivationGoal::startDaemon()
|
||||||
debug("received daemon connection");
|
debug("received daemon connection");
|
||||||
|
|
||||||
auto workerThread = std::thread([store, remote{std::move(remote)}]() {
|
auto workerThread = std::thread([store, remote{std::move(remote)}]() {
|
||||||
|
setCurrentThreadName("recursive nix worker");
|
||||||
FdSource from(remote.get());
|
FdSource from(remote.get());
|
||||||
FdSink to(remote.get());
|
FdSink to(remote.get());
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include "lix/libstore/s3.hh"
|
#include "lix/libstore/s3.hh"
|
||||||
#include "lix/libutil/signals.hh"
|
#include "lix/libutil/signals.hh"
|
||||||
#include "lix/libutil/strings.hh"
|
#include "lix/libutil/strings.hh"
|
||||||
|
#include "lix/libutil/thread-name.hh"
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
@ -454,7 +455,10 @@ struct curlFileTransfer : public FileTransfer
|
||||||
curl_multi_setopt(curlm.get(), CURLMOPT_MAX_TOTAL_CONNECTIONS,
|
curl_multi_setopt(curlm.get(), CURLMOPT_MAX_TOTAL_CONNECTIONS,
|
||||||
fileTransferSettings.httpConnections.get());
|
fileTransferSettings.httpConnections.get());
|
||||||
|
|
||||||
workerThread = std::thread([&]() { workerThreadEntry(); });
|
workerThread = std::thread([&]() {
|
||||||
|
setCurrentThreadName("curlFileTransfer worker");
|
||||||
|
workerThreadEntry();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
~curlFileTransfer()
|
~curlFileTransfer()
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "lix/libutil/finally.hh"
|
#include "lix/libutil/finally.hh"
|
||||||
#include "lix/libutil/unix-domain-socket.hh"
|
#include "lix/libutil/unix-domain-socket.hh"
|
||||||
#include "lix/libutil/strings.hh"
|
#include "lix/libutil/strings.hh"
|
||||||
|
#include "lix/libutil/thread-name.hh"
|
||||||
|
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
@ -420,7 +421,10 @@ class GCOperation {
|
||||||
throw SysError("making socket '%1%' non-blocking", socketPath);
|
throw SysError("making socket '%1%' non-blocking", socketPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
serverThread = std::thread([this]() { runServerThread(); });
|
serverThread = std::thread([this]() {
|
||||||
|
setCurrentThreadName("gc server");
|
||||||
|
runServerThread();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void addTempRoot(std::string rootHashPart)
|
void addTempRoot(std::string rootHashPart)
|
||||||
|
@ -491,6 +495,7 @@ void GCOperation::runServerThread()
|
||||||
/* Process the connection in a separate thread. */
|
/* Process the connection in a separate thread. */
|
||||||
auto fdClient_ = fdClient.get();
|
auto fdClient_ = fdClient.get();
|
||||||
std::thread clientThread([&, fdClient = std::move(fdClient)]() {
|
std::thread clientThread([&, fdClient = std::move(fdClient)]() {
|
||||||
|
setCurrentThreadName("gc server connection");
|
||||||
Finally cleanup([&]() {
|
Finally cleanup([&]() {
|
||||||
auto conn(connections.lock());
|
auto conn(connections.lock());
|
||||||
auto i = conn->find(fdClient.get());
|
auto i = conn->find(fdClient.get());
|
||||||
|
@ -900,6 +905,7 @@ void LocalStore::autoGC(bool sync)
|
||||||
future = state->gcFuture = promise.get_future().share();
|
future = state->gcFuture = promise.get_future().share();
|
||||||
|
|
||||||
std::thread([promise{std::move(promise)}, this, avail, getAvail]() mutable {
|
std::thread([promise{std::move(promise)}, this, avail, getAvail]() mutable {
|
||||||
|
setCurrentThreadName("auto gc");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ void Store::queryMissing(const std::vector<DerivedPath> & targets,
|
||||||
downloadSize_ = narSize_ = 0;
|
downloadSize_ = narSize_ = 0;
|
||||||
|
|
||||||
// FIXME: make async.
|
// FIXME: make async.
|
||||||
ThreadPool pool(fileTransferSettings.httpConnections);
|
ThreadPool pool("queryMissing pool", fileTransferSettings.httpConnections);
|
||||||
|
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "lix/libutil/logging.hh"
|
#include "lix/libutil/logging.hh"
|
||||||
#include "lix/libstore/filetransfer.hh"
|
#include "lix/libstore/filetransfer.hh"
|
||||||
#include "lix/libutil/strings.hh"
|
#include "lix/libutil/strings.hh"
|
||||||
|
#include "lix/libutil/thread-name.hh"
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
@ -971,6 +972,7 @@ void RemoteStore::ConnectionHandle::withFramedSink(std::function<void(Sink & sin
|
||||||
thread. */
|
thread. */
|
||||||
std::thread stderrThread([&]()
|
std::thread stderrThread([&]()
|
||||||
{
|
{
|
||||||
|
setCurrentThreadName("remote stderr thread");
|
||||||
try {
|
try {
|
||||||
ReceiveInterrupts receiveInterrupts;
|
ReceiveInterrupts receiveInterrupts;
|
||||||
processStderr(nullptr, nullptr, false);
|
processStderr(nullptr, nullptr, false);
|
||||||
|
|
|
@ -306,7 +306,7 @@ void Store::addMultipleToStore(
|
||||||
act.progress(nrDone, pathsToCopy.size(), nrRunning, nrFailed);
|
act.progress(nrDone, pathsToCopy.size(), nrRunning, nrFailed);
|
||||||
};
|
};
|
||||||
|
|
||||||
ThreadPool pool;
|
ThreadPool pool{"addMultipleToStore pool"};
|
||||||
|
|
||||||
processGraph<StorePath>(pool,
|
processGraph<StorePath>(pool,
|
||||||
storePathsToAdd,
|
storePathsToAdd,
|
||||||
|
@ -835,7 +835,7 @@ StorePathSet Store::queryValidPaths(const StorePathSet & paths, SubstituteFlag m
|
||||||
Sync<State> state_(State{paths.size(), StorePathSet()});
|
Sync<State> state_(State{paths.size(), StorePathSet()});
|
||||||
|
|
||||||
std::condition_variable wakeup;
|
std::condition_variable wakeup;
|
||||||
ThreadPool pool;
|
ThreadPool pool{"queryValidPaths pool"};
|
||||||
|
|
||||||
auto doQuery = [&](const StorePath & path) {
|
auto doQuery = [&](const StorePath & path) {
|
||||||
checkInterrupt();
|
checkInterrupt();
|
||||||
|
@ -1136,7 +1136,7 @@ std::map<StorePath, StorePath> copyPaths(
|
||||||
}
|
}
|
||||||
auto pathsMap = copyPaths(srcStore, dstStore, storePaths, repair, checkSigs, substitute);
|
auto pathsMap = copyPaths(srcStore, dstStore, storePaths, repair, checkSigs, substitute);
|
||||||
|
|
||||||
ThreadPool pool;
|
ThreadPool pool{"copyPaths pool"};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Copy the realisation closure
|
// Copy the realisation closure
|
||||||
|
|
|
@ -38,6 +38,7 @@ libutil_sources = files(
|
||||||
'suggestions.cc',
|
'suggestions.cc',
|
||||||
'tarfile.cc',
|
'tarfile.cc',
|
||||||
'terminal.cc',
|
'terminal.cc',
|
||||||
|
'thread-name.cc',
|
||||||
'thread-pool.cc',
|
'thread-pool.cc',
|
||||||
'unix-domain-socket.cc',
|
'unix-domain-socket.cc',
|
||||||
'url.cc',
|
'url.cc',
|
||||||
|
@ -118,6 +119,7 @@ libutil_headers = files(
|
||||||
'sync.hh',
|
'sync.hh',
|
||||||
'tarfile.hh',
|
'tarfile.hh',
|
||||||
'terminal.hh',
|
'terminal.hh',
|
||||||
|
'thread-name.hh',
|
||||||
'thread-pool.hh',
|
'thread-pool.hh',
|
||||||
'topo-sort.hh',
|
'topo-sort.hh',
|
||||||
'types.hh',
|
'types.hh',
|
||||||
|
|
|
@ -4,15 +4,14 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
|
||||||
|
|
||||||
#include "lix/libutil/error.hh"
|
#include "lix/libutil/error.hh"
|
||||||
#include "lix/libutil/file-descriptor.hh"
|
#include "lix/libutil/file-descriptor.hh"
|
||||||
#include "lix/libutil/signals.hh"
|
#include "lix/libutil/signals.hh"
|
||||||
|
#include "lix/libutil/thread-name.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
|
@ -34,6 +33,7 @@ public:
|
||||||
auto &quit_ = this->quit;
|
auto &quit_ = this->quit;
|
||||||
int terminateFd = terminatePipe.readSide.get();
|
int terminateFd = terminatePipe.readSide.get();
|
||||||
thread = std::thread([fd, terminateFd, &quit_]() {
|
thread = std::thread([fd, terminateFd, &quit_]() {
|
||||||
|
setCurrentThreadName("MonitorFdHup");
|
||||||
while (!quit_) {
|
while (!quit_) {
|
||||||
/* Wait indefinitely until a POLLHUP occurs. */
|
/* Wait indefinitely until a POLLHUP occurs. */
|
||||||
struct pollfd fds[2];
|
struct pollfd fds[2];
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#include "lix/libutil/error.hh"
|
#include "lix/libutil/error.hh"
|
||||||
#include "lix/libutil/sync.hh"
|
#include "lix/libutil/sync.hh"
|
||||||
#include "lix/libutil/terminal.hh"
|
#include "lix/libutil/terminal.hh"
|
||||||
|
#include "lix/libutil/thread-name.hh"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
@ -49,6 +50,7 @@ static Sync<InterruptCallbacks> _interruptCallbacks;
|
||||||
|
|
||||||
static void signalHandlerThread(sigset_t set)
|
static void signalHandlerThread(sigset_t set)
|
||||||
{
|
{
|
||||||
|
setCurrentThreadName("signal handler");
|
||||||
while (true) {
|
while (true) {
|
||||||
int signal = 0;
|
int signal = 0;
|
||||||
sigwait(&set, &signal);
|
sigwait(&set, &signal);
|
||||||
|
|
20
src/libutil/thread-name.cc
Normal file
20
src/libutil/thread-name.cc
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#include <pthread.h>
|
||||||
|
#if defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
|
#include <pthread_np.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
void setCurrentThreadName(const char * name)
|
||||||
|
{
|
||||||
|
// https://stackoverflow.com/questions/2369738/how-to-set-the-name-of-a-thread-in-linux-pthreads/7989973
|
||||||
|
#if defined(__linux__)
|
||||||
|
pthread_setname_np(pthread_self(), name);
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
pthread_setname_np(name);
|
||||||
|
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
|
pthread_set_name_np(pthread_self(), name);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
12
src/libutil/thread-name.hh
Normal file
12
src/libutil/thread-name.hh
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
#pragma once
|
||||||
|
///@file
|
||||||
|
|
||||||
|
namespace nix {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the name of the current operating system thread for the benefit of
|
||||||
|
* debuggers.
|
||||||
|
*/
|
||||||
|
void setCurrentThreadName(const char * name);
|
||||||
|
|
||||||
|
}
|
|
@ -1,11 +1,12 @@
|
||||||
#include "lix/libutil/thread-pool.hh"
|
#include "lix/libutil/thread-pool.hh"
|
||||||
#include "lix/libutil/logging.hh"
|
#include "lix/libutil/logging.hh"
|
||||||
#include "lix/libutil/signals.hh"
|
#include "lix/libutil/signals.hh"
|
||||||
|
#include "lix/libutil/thread-name.hh"
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
ThreadPool::ThreadPool(size_t _maxThreads)
|
ThreadPool::ThreadPool(const char * name, size_t _maxThreads)
|
||||||
: maxThreads(_maxThreads)
|
: maxThreads(_maxThreads), name(name)
|
||||||
{
|
{
|
||||||
if (!maxThreads) {
|
if (!maxThreads) {
|
||||||
maxThreads = std::thread::hardware_concurrency();
|
maxThreads = std::thread::hardware_concurrency();
|
||||||
|
@ -81,8 +82,10 @@ void ThreadPool::doWork(bool mainThread)
|
||||||
{
|
{
|
||||||
ReceiveInterrupts receiveInterrupts;
|
ReceiveInterrupts receiveInterrupts;
|
||||||
|
|
||||||
if (!mainThread)
|
if (!mainThread) {
|
||||||
|
setCurrentThreadName(this->name);
|
||||||
interruptCheck = [&]() { return (bool) quit; };
|
interruptCheck = [&]() { return (bool) quit; };
|
||||||
|
}
|
||||||
|
|
||||||
bool didWork = false;
|
bool didWork = false;
|
||||||
std::exception_ptr exc;
|
std::exception_ptr exc;
|
||||||
|
|
|
@ -22,7 +22,7 @@ class ThreadPool
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ThreadPool(size_t maxThreads = 0);
|
ThreadPool(const char * name, size_t maxThreads = 0);
|
||||||
|
|
||||||
~ThreadPool();
|
~ThreadPool();
|
||||||
|
|
||||||
|
@ -56,6 +56,8 @@ private:
|
||||||
|
|
||||||
size_t maxThreads;
|
size_t maxThreads;
|
||||||
|
|
||||||
|
const char * name;
|
||||||
|
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
std::queue<work_t> pending;
|
std::queue<work_t> pending;
|
||||||
|
|
|
@ -38,7 +38,7 @@ struct CmdCopySigs : StorePathsCommand
|
||||||
for (auto & s : substituterUris)
|
for (auto & s : substituterUris)
|
||||||
substituters.push_back(openStore(s));
|
substituters.push_back(openStore(s));
|
||||||
|
|
||||||
ThreadPool pool;
|
ThreadPool pool{"CopySigs pool"};
|
||||||
|
|
||||||
std::string doneLabel = "done";
|
std::string doneLabel = "done";
|
||||||
std::atomic<size_t> added{0};
|
std::atomic<size_t> added{0};
|
||||||
|
|
|
@ -79,7 +79,7 @@ struct CmdVerify : StorePathsCommand
|
||||||
act.progress(done, storePaths.size(), active, failed);
|
act.progress(done, storePaths.size(), active, failed);
|
||||||
};
|
};
|
||||||
|
|
||||||
ThreadPool pool;
|
ThreadPool pool{"Verify pool"};
|
||||||
|
|
||||||
auto doPath = [&](const StorePath & storePath) {
|
auto doPath = [&](const StorePath & storePath) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "lix/libstore/filetransfer.hh"
|
#include "lix/libstore/filetransfer.hh"
|
||||||
#include "lix/libutil/compression.hh"
|
#include "lix/libutil/compression.hh"
|
||||||
|
#include "lix/libutil/thread-name.hh"
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
@ -90,6 +91,7 @@ serveHTTP(std::vector<Reply> replies)
|
||||||
|
|
||||||
std::thread(
|
std::thread(
|
||||||
[replies, at{0}](AutoCloseFD socket, AutoCloseFD trigger) mutable {
|
[replies, at{0}](AutoCloseFD socket, AutoCloseFD trigger) mutable {
|
||||||
|
setCurrentThreadName("test httpd server");
|
||||||
while (true) {
|
while (true) {
|
||||||
pollfd pfds[2] = {
|
pollfd pfds[2] = {
|
||||||
{
|
{
|
||||||
|
@ -120,6 +122,7 @@ serveHTTP(std::vector<Reply> replies)
|
||||||
const auto & reply = replies[at++ % replies.size()];
|
const auto & reply = replies[at++ % replies.size()];
|
||||||
|
|
||||||
std::thread([=, conn{std::move(conn)}] {
|
std::thread([=, conn{std::move(conn)}] {
|
||||||
|
setCurrentThreadName("test httpd connection");
|
||||||
auto send = [&](std::string_view bit) {
|
auto send = [&](std::string_view bit) {
|
||||||
while (!bit.empty()) {
|
while (!bit.empty()) {
|
||||||
auto written = ::send(conn.get(), bit.data(), bit.size(), MSG_NOSIGNAL);
|
auto written = ::send(conn.get(), bit.data(), bit.size(), MSG_NOSIGNAL);
|
||||||
|
|
Loading…
Reference in a new issue