Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix deadlocked nix-daemon zombies on darwin #3294 #6052

Merged
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 43 additions & 12 deletions src/libutil/util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1561,7 +1561,22 @@ std::pair<unsigned short, unsigned short> getWindowSize()
}


static Sync<std::list<std::function<void()>>> _interruptCallbacks;
/* We keep track of interrupt callbacks using integer tokens, so we can iterate
safely without having to lock the data structure while executing arbitrary
functions.
*/
struct InterruptCallbacks {
typedef int64_t Token;

/* We use unique tokens so that we can't accidentally delete the wrong
handler because of an erroneous double delete. */
Token nextToken = 0;

/* Used as a list, see InterruptCallbacks comment. */
std::map<Token, std::function<void()>> callbacks;
};

static Sync<InterruptCallbacks> _interruptCallbacks;

static void signalHandlerThread(sigset_t set)
{
Expand All @@ -1583,14 +1598,29 @@ void triggerInterrupt()
_isInterrupted = true;

{
auto interruptCallbacks(_interruptCallbacks.lock());
for (auto & callback : *interruptCallbacks) {
try {
callback();
} catch (...) {
ignoreException();
InterruptCallbacks::Token i = 0;
std::function<void()> callback;
do {
{
auto interruptCallbacks(_interruptCallbacks.lock());
auto lb = interruptCallbacks->callbacks.lower_bound(i);
if (lb != interruptCallbacks->callbacks.end()) {
callback = lb->second;
i = lb->first + 1;
} else {
callback = nullptr;
}
roberth marked this conversation as resolved.
Show resolved Hide resolved
}

if (callback) {
try {
callback();
} catch (...) {
ignoreException();
}
}
}
while (callback);
}
}

Expand Down Expand Up @@ -1694,21 +1724,22 @@ void restoreProcessContext(bool restoreMounts)
/* RAII helper to automatically deregister a callback. */
struct InterruptCallbackImpl : InterruptCallback
{
std::list<std::function<void()>>::iterator it;
InterruptCallbacks::Token token;
~InterruptCallbackImpl() override
{
_interruptCallbacks.lock()->erase(it);
auto interruptCallbacks(_interruptCallbacks.lock());
interruptCallbacks->callbacks.erase(token);
}
};

std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()> callback)
{
auto interruptCallbacks(_interruptCallbacks.lock());
interruptCallbacks->push_back(callback);
auto token = interruptCallbacks->nextToken++;
interruptCallbacks->callbacks.emplace(token, callback);

auto res = std::make_unique<InterruptCallbackImpl>();
res->it = interruptCallbacks->end();
res->it--;
res->token = token;

return std::unique_ptr<InterruptCallback>(res.release());
}
Expand Down