]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
timeout: use the more efficient posix_spawn to invoke the command
authorCollin Funk <collin.funk1@gmail.com>
Sun, 26 Oct 2025 22:33:24 +0000 (15:33 -0700)
committerCollin Funk <collin.funk1@gmail.com>
Mon, 27 Oct 2025 23:54:45 +0000 (16:54 -0700)
* NEWS: Mention the improvement. Consolidate the posix_spawn
improvements into one item.
* bootstrap.conf (gnulib_modules): Add posix_spawnattr_setsigmask.
* src/timeout.c: Include spawn.h.
(main): Setup signals using a posix_spawnattr_t object. Use posix_spawn
instead of fork and execvp.

NEWS
bootstrap.conf
src/timeout.c

diff --git a/NEWS b/NEWS
index 21106f6910d07019e4a7dcf68049a0044c356260..96b54e108b5875b6b9ddda861194c296711f5a41 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -51,7 +51,8 @@ GNU coreutils NEWS                                    -*- outline -*-
   'fmt', 'nl', and 'pr' will now exit promptly upon receiving a write error,
   which is significant when reading large / unbounded inputs.
 
-  'install' now uses posix_spawn() to invoke the strip program more efficiently.
+  install, sort, split, and timeout now use posix_spawn() to invoke child
+  programs more efficiently and more independently from their own memory usage.
 
   'numfmt':
    - parses numbers with a non-breaking space character before a unit
@@ -59,12 +60,6 @@ GNU coreutils NEWS                                    -*- outline -*-
    - supports a multi-byte --delimiter character
    - no longer processes input indefinitely in the presence of write errors
 
-  'sort' now uses posix_spawn() to invoke --compress-program more efficiently
-  and more independently from sort's memory usage.
-
-  'split' now uses posix_spawn() to invoke the shell command specified by
-  --filter more efficiently.
-
   wc -l now operates 10% faster on hosts that support AVX512 instructions.
 
 ** Build-related
index 4d401d2eb55cb1d5952e79a09c47016b2afe8581..6654f61ef40e2e30a0605d0a58eda03589703fb3 100644 (file)
@@ -218,6 +218,7 @@ gnulib_modules="
   posix_spawnattr_init
   posix_spawnattr_setflags
   posix_spawnattr_setsigdefault
+  posix_spawnattr_setsigmask
   posix_spawn_file_actions_addclose
   posix_spawn_file_actions_adddup2
   posix_spawn_file_actions_destroy
index cc3b1b0849674fb12c9ce153de02bc669dbc948d..15af87c95884c31f69243ca9b950379a89164635 100644 (file)
@@ -49,6 +49,7 @@
 #include <stdio.h>
 #include <sys/types.h>
 #include <signal.h>
+#include <spawn.h>
 #if HAVE_PRCTL
 # include <sys/prctl.h>
 #endif
@@ -547,30 +548,35 @@ main (int argc, char **argv)
   sigset_t orig_set;
   block_cleanup_and_chld (term_signal, &orig_set);
 
-  monitored_pid = fork ();
-  if (monitored_pid == -1)
+  /* posix_spawn doesn't reset SIG_IGN -> SIG_DFL.  */
+  sigset_t default_set;
+  sigemptyset (&default_set);
+  sigaddset (&default_set, SIGTTIN);
+  sigaddset (&default_set, SIGTTOU);
+
+  int result;
+  posix_spawnattr_t attr;
+
+  if ((result = posix_spawnattr_init (&attr))
+      || (result = posix_spawnattr_setflags (&attr,
+                                             (POSIX_SPAWN_USEVFORK
+                                              | POSIX_SPAWN_SETSIGDEF
+                                              | POSIX_SPAWN_SETSIGMASK)))
+      || (result = posix_spawnattr_setsigdefault (&attr, &default_set))
+      || (result = posix_spawnattr_setsigmask (&attr, &orig_set)))
     {
-      error (0, errno, _("fork system call failed"));
+      error (0, result, _("posix_spawn initialization failed"));
       return EXIT_CANCELED;
     }
-  else if (monitored_pid == 0)  /* child */
-    {
-      /* Restore signal mask for child.  */
-      if (sigprocmask (SIG_SETMASK, &orig_set, nullptr) != 0)
-        {
-          error (0, errno, _("child failed to reset signal mask"));
-          return EXIT_CANCELED;
-        }
 
-      /* exec doesn't reset SIG_IGN -> SIG_DFL.  */
-      signal (SIGTTIN, SIG_DFL);
-      signal (SIGTTOU, SIG_DFL);
-
-      execvp (argv[0], argv);
+  result = posix_spawnp (&monitored_pid, argv[0], nullptr, &attr, argv,
+                         environ);
 
+  if (result)
+    {
       /* exit like sh, env, nohup, ...  */
-      int exit_status = errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
-      error (0, errno, _("failed to run command %s"), quote (command));
+      int exit_status = result == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE;
+      error (0, result, _("failed to run command %s"), quote (command));
       return exit_status;
     }
   else