* NEWS: Mention the improvement.
* 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           |  3 +++
 bootstrap.conf |  1 +
 src/timeout.c  | 42 ++++++++++++++++++++++++------------------
 3 files changed, 28 insertions(+), 18 deletions(-)

diff --git a/NEWS b/NEWS
index 402585be3..9ebedb3a1 100644
--- a/NEWS
+++ b/NEWS
@@ -65,6 +65,9 @@ GNU coreutils NEWS                                    -*- 
outline -*-
   'split' now uses posix_spawn() to invoke the shell command specified by
   --filter more efficiently.
 
+  'timeout' now uses posix_spawn() to invoke the specified command more
+  efficiently.
+
   wc -l now operates 10% faster on hosts that support AVX512 instructions.
 
 
diff --git a/bootstrap.conf b/bootstrap.conf
index 4d401d2eb..6654f61ef 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -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
diff --git a/src/timeout.c b/src/timeout.c
index cc3b1b084..15af87c95 100644
--- a/src/timeout.c
+++ b/src/timeout.c
@@ -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
-- 
2.51.0


Reply via email to