ソースを参照

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.
Ali Mohammad Pur 3 年 前
コミット
d338d2b59b
1 ファイル変更16 行追加3 行削除
  1. 16 3
      Userland/Shell/Shell.cpp

+ 16 - 3
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()