From 577ef6e47833d5ff9fc978e631e73a75868ea8b9 Mon Sep 17 00:00:00 2001 From: Puck Meerburg Date: Sun, 9 Jun 2024 13:20:20 +0000 Subject: [PATCH] Use our own Thread struct instead of std::thread We'd highly prefer using std::thread here; but this won't let us configure the stack size. macOS uses 512KiB size stacks for non-main threads, and musl defaults to 128k. While Nix configures a 64MiB size for the main thread, this doesn't propagate to the threads we launch here. It turns out, running the evaluator under an anemic stack of 0.5MiB has it overflow way too quickly. Hence, we have our own custom Thread struct. --- src/nix-eval-jobs.cc | 47 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/src/nix-eval-jobs.cc b/src/nix-eval-jobs.cc index e2b204b..cf31c1e 100644 --- a/src/nix-eval-jobs.cc +++ b/src/nix-eval-jobs.cc @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -24,7 +25,6 @@ #include #include #include -#include #include #include #include @@ -99,6 +99,47 @@ struct Proc { ~Proc() {} }; +// We'd highly prefer using std::thread here; but this won't let us configure the stack +// size. macOS uses 512KiB size stacks for non-main threads, and musl defaults to 128k. +// While Nix configures a 64MiB size for the main thread, this doesn't propagate to the +// threads we launch here. It turns out, running the evaluator under an anemic stack of +// 0.5MiB has it overflow way too quickly. Hence, we have our own custom Thread struct. +struct Thread { + std::function func; + pthread_t thread; + + Thread(std::function f) : func(f) { + int s; + pthread_attr_t attr; + + if ((s = pthread_attr_init(&attr)) != 0) { + throw SysError(s, "calling pthread_attr_init"); + } + if ((s = pthread_attr_setstacksize(&attr, 64 * 1024 * 1024)) != 0) { + throw SysError(s, "calling pthread_attr_setstacksize"); + } + if ((s = pthread_create(&thread, &attr, Thread::init, static_cast(this))) != 0) { + throw SysError(s, "calling pthread_launch"); + } + if ((s = pthread_attr_destroy(&attr)) != 0) { + throw SysError(s, "calling pthread_attr_destroy"); + } + } + void join() { + int s; + s = pthread_join(thread, nullptr); + if (s != 0) { + throw SysError(s, "calling pthread_join"); + } + } +private: + static void *init(void *ptr) { + Thread *thread = static_cast(ptr); + thread->func(); + return 0; + } +}; + struct State { std::set todo = json::array({json::array()}); std::set active; @@ -332,10 +373,10 @@ int main(int argc, char **argv) { Sync state_; /* Start a collector thread per worker process. */ - std::vector threads; + std::vector threads; std::condition_variable wakeup; for (size_t i = 0; i < myArgs.nrWorkers; i++) { - threads.emplace_back(collector, std::ref(state_), std::ref(wakeup)); + threads.emplace_back(std::bind(collector, std::ref(state_), std::ref(wakeup))); } for (auto &thread : threads)