diff --git a/Userland/Shell/Shell.cpp b/Userland/Shell/Shell.cpp index e169847dc9..41907f5227 100644 --- a/Userland/Shell/Shell.cpp +++ b/Userland/Shell/Shell.cpp @@ -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()