Commit 9067cc47719 for nodejs

commit 9067cc47719232c044bfe22c8f206aa5c0f1a48d
Author: Matteo Collina <hello@matteocollina.com>
Date:   Sat Oct 3 13:03:14 2026 +0200

    tools: wait for test processes instead of polling

    RunProcess polled the child with an exponential backoff that capped at
    100 ms, so every test longer than roughly 300 ms paid 30-75 ms of
    latency after it had already exited. Across the parallel suite that
    adds up to about 160 thread-seconds.

    Block in wait() instead and let a timer thread deliver the kill when
    the timeout is crossed. Set the shutdown flag from the SIGINT handler
    so a worker whose child died from the same ctrl-c does not report it
    as a failure before the main thread aborts the run.

    Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
    Claude-Session: https://claude.ai/code/session_01UH48w8TCtYmHd4P2UE6HEY
    Signed-off-by: Matteo Collina <hello@matteocollina.com>
    PR-URL: https://github.com/nodejs/node/pull/66432
    Reviewed-By: James M Snell <jasnell@gmail.com>
    Reviewed-By: Filip Skokan <panva.ip@gmail.com>
    Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
    Reviewed-By: Moshe Atlow <moshe@atlow.co.il>

diff --git a/tools/test.py b/tools/test.py
index 90df2cfb2fa..fee5172b41b 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -151,6 +151,12 @@ class ProgressIndicator(object):
   def Run(self, tasks) -> Dict:
     self.Starting()
     threads = []
+    # Flag the shutdown from the signal handler itself so that workers whose
+    # child died from the same ctrl-c do not report it as a failure first.
+    def on_sigint(signum, frame):
+      self.shutdown_event.set()
+      raise KeyboardInterrupt
+    previous_handler = signal.signal(signal.SIGINT, on_sigint)
     # Spawn N-1 threads and then use this thread as the last one.
     # That way -j1 avoids threading altogether which is a nice fallback
     # in case of threading problems.
@@ -172,6 +178,8 @@ class ProgressIndicator(object):
       self.shutdown_event.set()
       # ...and then reraise the exception to bail out
       raise
+    finally:
+      signal.signal(signal.SIGINT, previous_handler)
     self.Done()
     return {
       'allPassed': not self.failed and not self.shutdown_event.is_set(),
@@ -680,10 +688,6 @@ def KillProcessWithID(pid, signal_to_send=signal.SIGTERM):
     os.kill(pid, signal_to_send)


-MAX_SLEEP_TIME = 0.1
-INITIAL_SLEEP_TIME = 0.0001
-SLEEP_TIME_FACTOR = 1.25
-
 SEM_INVALID_VALUE = -1
 SEM_NOGPFAULTERRORBOX = 0x0002 # Microsoft Platform SDK WinBase.h

@@ -726,29 +730,28 @@ def RunProcess(context, timeout, args, **rest):
   )
   if utils.IsWindows() and context.suppress_dialogs and prev_error_mode != SEM_INVALID_VALUE:
     Win32SetErrorMode(prev_error_mode)
-  # Compute the end time - if the process crosses this limit we
-  # consider it timed out.
-  if timeout is None: end_time = None
-  else: end_time = time.time() + timeout
+  # Block in wait() instead of polling: a timer thread delivers the kill if
+  # the process crosses the timeout, and wait() then returns the exit code.
   timed_out = False
-  # Repeatedly check the exit code from the process in a
-  # loop and keep track of whether or not it times out.
-  exit_code = None
-  sleep_time = INITIAL_SLEEP_TIME
-
-  while exit_code is None:
-    if (not end_time is None) and (time.time() >= end_time):
-      # Kill the process and wait for it to exit.
-      KillTimedOutProcess(context, process.pid)
-      exit_code = process.wait()
+  if timeout is None:
+    exit_code = process.wait()
+  else:
+    def on_timeout():
+      nonlocal timed_out
+      if process.returncode is not None:
+        return
       timed_out = True
-    else:
-      exit_code = process.poll()
-      if exit_code is None:
-        time.sleep(sleep_time)
-        sleep_time = sleep_time * SLEEP_TIME_FACTOR
-        if sleep_time > MAX_SLEEP_TIME:
-          sleep_time = MAX_SLEEP_TIME
+      try:
+        KillTimedOutProcess(context, process.pid)
+      except OSError:
+        pass
+    timer = threading.Timer(timeout, on_timeout)
+    timer.daemon = True
+    timer.start()
+    try:
+      exit_code = process.wait()
+    finally:
+      timer.cancel()
   return (process, exit_code, timed_out)