Shell: Ignore SIGCHLD after a few unsuccessful attempts at handling it

As noted by the comment, a stray SIGCHLD can make the shell go into an
infinite loop, pretend the signal doesn't exist after trying 10 times in
5ms.
This commit is contained in:
Ali Mohammad Pur 2022-06-24 12:02:19 +04:30 committed by Linus Groh
parent eb4ea45822
commit d338d2b59b

View file

@ -2082,13 +2082,26 @@ void Shell::notify_child_event()
// The child might still be alive (and even running) when this signal is dispatched to us
// so just...repeat until we find a suitable child.
// This, of course, will mean that someone can send us a SIGCHILD and we'd be spinning here
// until the next child event we can actually handle.
// until the next child event we can actually handle, so stop after spending a total of 5110us (~5ms) on it.
bool found_child = false;
do {
size_t const max_tries = 10;
size_t valid_attempts = max_tries;
useconds_t backoff_usec = 20;
int backoff_multiplier = 2;
for (;;) {
if (found_child || --valid_attempts == 0)
break;
// Ignore stray SIGCHLD when there are no jobs.
if (jobs.is_empty())
return;
if (valid_attempts < max_tries - 1) {
usleep(backoff_usec);
backoff_usec *= backoff_multiplier;
}
for (auto& it : jobs) {
auto job_id = it.key;
auto& job = *it.value;
@ -2141,7 +2154,7 @@ void Shell::notify_child_event()
for (auto job_id : disowned_jobs) {
jobs.remove(job_id);
}
} while (!found_child);
}
}
Shell::Shell()