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/libutil/terminal.hh"
|
||||
#include "lix/libutil/strings.hh"
|
||||
#include "lix/libutil/thread-name.hh"
|
||||
|
||||
#include <map>
|
||||
#include <thread>
|
||||
|
@ -84,6 +85,7 @@ void ProgressBar::resume()
|
|||
if (state->paused > 0) return; // recursive pause, wait for the parents to resume too
|
||||
state->haveUpdate = true;
|
||||
updateThread = std::thread([&]() {
|
||||
setCurrentThreadName("progress bar");
|
||||
auto state(state_.lock());
|
||||
auto nextWakeup = A_LONG_TIME;
|
||||
while (state->paused == 0) {
|
||||
|
|
|
@ -196,7 +196,7 @@ ref<const ValidPathInfo> BinaryCacheStore::addToStoreCommon(
|
|||
|
||||
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) {
|
||||
checkInterrupt();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "lix/libutil/unix-domain-socket.hh"
|
||||
#include "lix/libutil/mount.hh"
|
||||
#include "lix/libutil/strings.hh"
|
||||
#include "lix/libutil/thread-name.hh"
|
||||
|
||||
#include <regex>
|
||||
#include <queue>
|
||||
|
@ -1224,6 +1225,7 @@ void LocalDerivationGoal::startDaemon()
|
|||
chownToBuilder(socketPath);
|
||||
|
||||
daemonThread = std::thread([this, store]() {
|
||||
setCurrentThreadName("recursive nix daemon");
|
||||
|
||||
while (true) {
|
||||
|
||||
|
@ -1244,6 +1246,7 @@ void LocalDerivationGoal::startDaemon()
|
|||
debug("received daemon connection");
|
||||
|
||||
auto workerThread = std::thread([store, remote{std::move(remote)}]() {
|
||||
setCurrentThreadName("recursive nix worker");
|
||||
FdSource from(remote.get());
|
||||
FdSink to(remote.get());
|
||||
try {
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "lix/libstore/s3.hh"
|
||||
#include "lix/libutil/signals.hh"
|
||||
#include "lix/libutil/strings.hh"
|
||||
#include "lix/libutil/thread-name.hh"
|
||||
#include <cstddef>
|
||||
|
||||
#include <cstdio>
|
||||
|
@ -454,7 +455,10 @@ struct curlFileTransfer : public FileTransfer
|
|||
curl_multi_setopt(curlm.get(), CURLMOPT_MAX_TOTAL_CONNECTIONS,
|
||||
fileTransferSettings.httpConnections.get());
|
||||
|
||||
workerThread = std::thread([&]() { workerThreadEntry(); });
|
||||
workerThread = std::thread([&]() {
|
||||
setCurrentThreadName("curlFileTransfer worker");
|
||||
workerThreadEntry();
|
||||
});
|
||||
}
|
||||
|
||||
~curlFileTransfer()
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "lix/libutil/finally.hh"
|
||||
#include "lix/libutil/unix-domain-socket.hh"
|
||||
#include "lix/libutil/strings.hh"
|
||||
#include "lix/libutil/thread-name.hh"
|
||||
|
||||
#include <queue>
|
||||
#include <regex>
|
||||
|
@ -420,7 +421,10 @@ class GCOperation {
|
|||
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)
|
||||
|
@ -491,6 +495,7 @@ void GCOperation::runServerThread()
|
|||
/* Process the connection in a separate thread. */
|
||||
auto fdClient_ = fdClient.get();
|
||||
std::thread clientThread([&, fdClient = std::move(fdClient)]() {
|
||||
setCurrentThreadName("gc server connection");
|
||||
Finally cleanup([&]() {
|
||||
auto conn(connections.lock());
|
||||
auto i = conn->find(fdClient.get());
|
||||
|
@ -900,6 +905,7 @@ void LocalStore::autoGC(bool sync)
|
|||
future = state->gcFuture = promise.get_future().share();
|
||||
|
||||
std::thread([promise{std::move(promise)}, this, avail, getAvail]() mutable {
|
||||
setCurrentThreadName("auto gc");
|
||||
|
||||
try {
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ void Store::queryMissing(const std::vector<DerivedPath> & targets,
|
|||
downloadSize_ = narSize_ = 0;
|
||||
|
||||
// FIXME: make async.
|
||||
ThreadPool pool(fileTransferSettings.httpConnections);
|
||||
ThreadPool pool("queryMissing pool", fileTransferSettings.httpConnections);
|
||||
|
||||
struct State
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "lix/libutil/logging.hh"
|
||||
#include "lix/libstore/filetransfer.hh"
|
||||
#include "lix/libutil/strings.hh"
|
||||
#include "lix/libutil/thread-name.hh"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
|
@ -971,6 +972,7 @@ void RemoteStore::ConnectionHandle::withFramedSink(std::function<void(Sink & sin
|
|||
thread. */
|
||||
std::thread stderrThread([&]()
|
||||
{
|
||||
setCurrentThreadName("remote stderr thread");
|
||||
try {
|
||||
ReceiveInterrupts receiveInterrupts;
|
||||
processStderr(nullptr, nullptr, false);
|
||||
|
|
|
@ -306,7 +306,7 @@ void Store::addMultipleToStore(
|
|||
act.progress(nrDone, pathsToCopy.size(), nrRunning, nrFailed);
|
||||
};
|
||||
|
||||
ThreadPool pool;
|
||||
ThreadPool pool{"addMultipleToStore pool"};
|
||||
|
||||
processGraph<StorePath>(pool,
|
||||
storePathsToAdd,
|
||||
|
@ -835,7 +835,7 @@ StorePathSet Store::queryValidPaths(const StorePathSet & paths, SubstituteFlag m
|
|||
Sync<State> state_(State{paths.size(), StorePathSet()});
|
||||
|
||||
std::condition_variable wakeup;
|
||||
ThreadPool pool;
|
||||
ThreadPool pool{"queryValidPaths pool"};
|
||||
|
||||
auto doQuery = [&](const StorePath & path) {
|
||||
checkInterrupt();
|
||||
|
@ -1136,7 +1136,7 @@ std::map<StorePath, StorePath> copyPaths(
|
|||
}
|
||||
auto pathsMap = copyPaths(srcStore, dstStore, storePaths, repair, checkSigs, substitute);
|
||||
|
||||
ThreadPool pool;
|
||||
ThreadPool pool{"copyPaths pool"};
|
||||
|
||||
try {
|
||||
// Copy the realisation closure
|
||||
|
|
|
@ -38,6 +38,7 @@ libutil_sources = files(
|
|||
'suggestions.cc',
|
||||
'tarfile.cc',
|
||||
'terminal.cc',
|
||||
'thread-name.cc',
|
||||
'thread-pool.cc',
|
||||
'unix-domain-socket.cc',
|
||||
'url.cc',
|
||||
|
@ -118,6 +119,7 @@ libutil_headers = files(
|
|||
'sync.hh',
|
||||
'tarfile.hh',
|
||||
'terminal.hh',
|
||||
'thread-name.hh',
|
||||
'thread-pool.hh',
|
||||
'topo-sort.hh',
|
||||
'types.hh',
|
||||
|
|
|
@ -4,15 +4,14 @@
|
|||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <poll.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "lix/libutil/error.hh"
|
||||
#include "lix/libutil/file-descriptor.hh"
|
||||
#include "lix/libutil/signals.hh"
|
||||
#include "lix/libutil/thread-name.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
@ -34,6 +33,7 @@ public:
|
|||
auto &quit_ = this->quit;
|
||||
int terminateFd = terminatePipe.readSide.get();
|
||||
thread = std::thread([fd, terminateFd, &quit_]() {
|
||||
setCurrentThreadName("MonitorFdHup");
|
||||
while (!quit_) {
|
||||
/* Wait indefinitely until a POLLHUP occurs. */
|
||||
struct pollfd fds[2];
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "lix/libutil/error.hh"
|
||||
#include "lix/libutil/sync.hh"
|
||||
#include "lix/libutil/terminal.hh"
|
||||
#include "lix/libutil/thread-name.hh"
|
||||
|
||||
#include <map>
|
||||
#include <thread>
|
||||
|
@ -49,6 +50,7 @@ static Sync<InterruptCallbacks> _interruptCallbacks;
|
|||
|
||||
static void signalHandlerThread(sigset_t set)
|
||||
{
|
||||
setCurrentThreadName("signal handler");
|
||||
while (true) {
|
||||
int signal = 0;
|
||||
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/logging.hh"
|
||||
#include "lix/libutil/signals.hh"
|
||||
#include "lix/libutil/thread-name.hh"
|
||||
|
||||
namespace nix {
|
||||
|
||||
ThreadPool::ThreadPool(size_t _maxThreads)
|
||||
: maxThreads(_maxThreads)
|
||||
ThreadPool::ThreadPool(const char * name, size_t _maxThreads)
|
||||
: maxThreads(_maxThreads), name(name)
|
||||
{
|
||||
if (!maxThreads) {
|
||||
maxThreads = std::thread::hardware_concurrency();
|
||||
|
@ -81,8 +82,10 @@ void ThreadPool::doWork(bool mainThread)
|
|||
{
|
||||
ReceiveInterrupts receiveInterrupts;
|
||||
|
||||
if (!mainThread)
|
||||
if (!mainThread) {
|
||||
setCurrentThreadName(this->name);
|
||||
interruptCheck = [&]() { return (bool) quit; };
|
||||
}
|
||||
|
||||
bool didWork = false;
|
||||
std::exception_ptr exc;
|
||||
|
|
|
@ -22,7 +22,7 @@ class ThreadPool
|
|||
{
|
||||
public:
|
||||
|
||||
ThreadPool(size_t maxThreads = 0);
|
||||
ThreadPool(const char * name, size_t maxThreads = 0);
|
||||
|
||||
~ThreadPool();
|
||||
|
||||
|
@ -56,6 +56,8 @@ private:
|
|||
|
||||
size_t maxThreads;
|
||||
|
||||
const char * name;
|
||||
|
||||
struct State
|
||||
{
|
||||
std::queue<work_t> pending;
|
||||
|
|
|
@ -38,7 +38,7 @@ struct CmdCopySigs : StorePathsCommand
|
|||
for (auto & s : substituterUris)
|
||||
substituters.push_back(openStore(s));
|
||||
|
||||
ThreadPool pool;
|
||||
ThreadPool pool{"CopySigs pool"};
|
||||
|
||||
std::string doneLabel = "done";
|
||||
std::atomic<size_t> added{0};
|
||||
|
|
|
@ -79,7 +79,7 @@ struct CmdVerify : StorePathsCommand
|
|||
act.progress(done, storePaths.size(), active, failed);
|
||||
};
|
||||
|
||||
ThreadPool pool;
|
||||
ThreadPool pool{"Verify pool"};
|
||||
|
||||
auto doPath = [&](const StorePath & storePath) {
|
||||
try {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "lix/libstore/filetransfer.hh"
|
||||
#include "lix/libutil/compression.hh"
|
||||
#include "lix/libutil/thread-name.hh"
|
||||
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
|
@ -90,6 +91,7 @@ serveHTTP(std::vector<Reply> replies)
|
|||
|
||||
std::thread(
|
||||
[replies, at{0}](AutoCloseFD socket, AutoCloseFD trigger) mutable {
|
||||
setCurrentThreadName("test httpd server");
|
||||
while (true) {
|
||||
pollfd pfds[2] = {
|
||||
{
|
||||
|
@ -120,6 +122,7 @@ serveHTTP(std::vector<Reply> replies)
|
|||
const auto & reply = replies[at++ % replies.size()];
|
||||
|
||||
std::thread([=, conn{std::move(conn)}] {
|
||||
setCurrentThreadName("test httpd connection");
|
||||
auto send = [&](std::string_view bit) {
|
||||
while (!bit.empty()) {
|
||||
auto written = ::send(conn.get(), bit.data(), bit.size(), MSG_NOSIGNAL);
|
||||
|
|
Loading…
Reference in a new issue