When using posix_spawn or fork to launch a child process, the parent
needs to wait for the child, otherwise the dead child is left as a
zombie process. For this purpose one can install a signal handler for
SIGCHLD.

2019-05-19  Janne Blomqvist  <j...@gcc.gnu.org>

        PR libfortran/90038
        * intrinsics/execute_command_line (sigchld_handler): New function.
        (execute_command_line): Install handler for SIGCHLD.
        * configure.ac: Check for presence of sigaction and waitpid.
        * config.h.in: Regenerated.
        * configure: Regenerated.

Regtested on x86_64-pc-linux-gnu, Ok for trunk?
---
 libgfortran/configure.ac                      |  2 +-
 libgfortran/intrinsics/execute_command_line.c | 25 +++++++++++++++++++
 2 files changed, 26 insertions(+), 1 deletion(-)

diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac
index 8fd5a1a30a9..7cfce28ab69 100644
--- a/libgfortran/configure.ac
+++ b/libgfortran/configure.ac
@@ -314,7 +314,7 @@ if test "${hardwire_newlib:-0}" -eq 1; then
 else
    AC_CHECK_FUNCS_ONCE(getrusage times mkstemp strtof strtold snprintf \
    ftruncate chsize chdir getentropy getlogin gethostname kill link symlink \
-   sleep ttyname \
+   sleep ttyname sigaction waitpid \
    alarm access fork posix_spawn setmode fcntl writev \
    gettimeofday stat fstat lstat getpwuid vsnprintf dup \
    getcwd localtime_r gmtime_r getpwuid_r ttyname_r clock_gettime \
diff --git a/libgfortran/intrinsics/execute_command_line.c 
b/libgfortran/intrinsics/execute_command_line.c
index 2ef2324b243..1a471632172 100644
--- a/libgfortran/intrinsics/execute_command_line.c
+++ b/libgfortran/intrinsics/execute_command_line.c
@@ -36,6 +36,9 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If 
not, see
 #include <spawn.h>
 extern char **environ;
 #endif
+#if defined(HAVE_POSIX_SPAWN) || defined(HAVE_FORK)
+#include <signal.h>
+#endif
 
 enum { EXEC_SYNCHRONOUS = -2, EXEC_NOERROR = 0, EXEC_SYSTEMFAILED,
        EXEC_CHILDFAILED, EXEC_INVALIDCOMMAND };
@@ -62,6 +65,14 @@ set_cmdstat (int *cmdstat, int value)
 }
 
 
+#if defined(HAVE_WAITPID) && defined(HAVE_SIGACTION)
+static void
+sigchld_handler (int signum __attribute__((unused)))
+{
+  while (waitpid ((pid_t)(-1), NULL, WNOHANG) > 0) {}
+}
+#endif
+
 static void
 execute_command_line (const char *command, bool wait, int *exitstat,
                      int *cmdstat, char *cmdmsg,
@@ -82,6 +93,20 @@ execute_command_line (const char *command, bool wait, int 
*exitstat,
 
       set_cmdstat (cmdstat, EXEC_NOERROR);
 
+#if defined(HAVE_SIGACTION) && defined(HAVE_WAITPID)
+      static bool sig_init_saved;
+      bool sig_init = __atomic_load_n (&sig_init_saved, __ATOMIC_RELAXED);
+      if (!sig_init)
+       {
+         struct sigaction sa;
+         sa.sa_handler = &sigchld_handler;
+         sigemptyset(&sa.sa_mask);
+         sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
+         sigaction(SIGCHLD, &sa, 0);
+         __atomic_store_n (&sig_init_saved, true, __ATOMIC_RELAXED);
+       }
+#endif
+
 #ifdef HAVE_POSIX_SPAWN
       const char * const argv[] = {"sh", "-c", cmd, NULL};
       if (posix_spawn (&pid, "/bin/sh", NULL, NULL,
-- 
2.17.1

Reply via email to