forked from lix-project/lix
Merge pull request #6052 from hercules-ci/issue-3294-fix-interruptCallback-deadlock
Fix deadlocked nix-daemon zombies on darwin #3294
This commit is contained in:
commit
e2422c4582
|
@ -1565,7 +1565,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)
|
static void signalHandlerThread(sigset_t set)
|
||||||
{
|
{
|
||||||
|
@ -1586,9 +1601,20 @@ void triggerInterrupt()
|
||||||
{
|
{
|
||||||
_isInterrupted = true;
|
_isInterrupted = true;
|
||||||
|
|
||||||
|
{
|
||||||
|
InterruptCallbacks::Token i = 0;
|
||||||
|
while (true) {
|
||||||
|
std::function<void()> callback;
|
||||||
{
|
{
|
||||||
auto interruptCallbacks(_interruptCallbacks.lock());
|
auto interruptCallbacks(_interruptCallbacks.lock());
|
||||||
for (auto & callback : *interruptCallbacks) {
|
auto lb = interruptCallbacks->callbacks.lower_bound(i);
|
||||||
|
if (lb == interruptCallbacks->callbacks.end())
|
||||||
|
break;
|
||||||
|
|
||||||
|
callback = lb->second;
|
||||||
|
i = lb->first + 1;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
callback();
|
callback();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
@ -1698,21 +1724,22 @@ void restoreProcessContext(bool restoreMounts)
|
||||||
/* RAII helper to automatically deregister a callback. */
|
/* RAII helper to automatically deregister a callback. */
|
||||||
struct InterruptCallbackImpl : InterruptCallback
|
struct InterruptCallbackImpl : InterruptCallback
|
||||||
{
|
{
|
||||||
std::list<std::function<void()>>::iterator it;
|
InterruptCallbacks::Token token;
|
||||||
~InterruptCallbackImpl() override
|
~InterruptCallbackImpl() override
|
||||||
{
|
{
|
||||||
_interruptCallbacks.lock()->erase(it);
|
auto interruptCallbacks(_interruptCallbacks.lock());
|
||||||
|
interruptCallbacks->callbacks.erase(token);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()> callback)
|
std::unique_ptr<InterruptCallback> createInterruptCallback(std::function<void()> callback)
|
||||||
{
|
{
|
||||||
auto interruptCallbacks(_interruptCallbacks.lock());
|
auto interruptCallbacks(_interruptCallbacks.lock());
|
||||||
interruptCallbacks->push_back(callback);
|
auto token = interruptCallbacks->nextToken++;
|
||||||
|
interruptCallbacks->callbacks.emplace(token, callback);
|
||||||
|
|
||||||
auto res = std::make_unique<InterruptCallbackImpl>();
|
auto res = std::make_unique<InterruptCallbackImpl>();
|
||||||
res->it = interruptCallbacks->end();
|
res->token = token;
|
||||||
res->it--;
|
|
||||||
|
|
||||||
return std::unique_ptr<InterruptCallback>(res.release());
|
return std::unique_ptr<InterruptCallback>(res.release());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue