X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fwait-process.c;h=0af9a183325bf1a050debaa246c6ea36d9c01679;hb=0df2580e13bb5523b7f5569e9bec1fda9c812677;hp=138f25c64762100d6d74df5c9f534949e8a795c7;hpb=5150a50d0d55e76e32295080dac53cb4324bce00;p=gnulib.git diff --git a/lib/wait-process.c b/lib/wait-process.c index 138f25c64..0af9a1833 100644 --- a/lib/wait-process.c +++ b/lib/wait-process.c @@ -101,6 +101,18 @@ #define SIZEOF(a) (sizeof(a) / sizeof(a[0])) +#if defined _MSC_VER || defined __MINGW32__ + +#define WIN32_LEAN_AND_MEAN +#include + +/* The return value of spawnvp() is really a process handle as returned + by CreateProcess(). Therefore we can kill it using TerminateProcess. */ +#define kill(pid,sig) TerminateProcess ((HANDLE) (pid), sig) + +#endif + + /* Type of an entry in the slaves array. The 'used' bit determines whether this entry is currently in use. (If pid_t was an atomic type like sig_atomic_t, we could just set the @@ -131,7 +143,7 @@ static size_t slaves_allocated = SIZEOF (static_slaves); /* The cleanup action. It gets called asynchronously. */ static void -cleanup_slaves () +cleanup_slaves (void) { for (;;) { @@ -240,9 +252,95 @@ unregister_slave_subprocess (pid_t child) return 127. */ int wait_subprocess (pid_t child, const char *progname, - bool null_stderr, + bool ignore_sigpipe, bool null_stderr, bool slave_process, bool exit_on_error) { +#if HAVE_WAITID && defined WNOWAIT && 0 + /* Commented out because waitid() with WNOWAIT doesn't work: On Solaris 7 + and OSF/1 4.0, it returns -1 and sets errno = ECHILD, and on HP-UX 10.20 + it just hangs. */ + /* Use of waitid() with WNOWAIT avoids a race condition: If slave_process is + true, and this process sleeps a very long time between the return from + waitpid() and the execution of unregister_slave_subprocess(), and + meanwhile another process acquires the same PID as child, and then - still + before unregister_slave_subprocess() - this process gets a fatal signal, + it would kill the other totally unrelated process. */ + siginfo_t info; + for (;;) + { + if (waitid (P_PID, child, &info, slave_process ? WNOWAIT : 0) < 0) + { +# ifdef EINTR + if (errno == EINTR) + continue; +# endif + if (exit_on_error || !null_stderr) + error (exit_on_error ? EXIT_FAILURE : 0, errno, + _("%s subprocess"), progname); + return 127; + } + + /* info.si_code is set to one of CLD_EXITED, CLD_KILLED, CLD_DUMPED, + CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED. Loop until the program + terminates. */ + if (info.si_code == CLD_EXITED + || info.si_code == CLD_KILLED || info.si_code == CLD_DUMPED) + break; + } + + /* The child process has exited or was signalled. */ + + if (slave_process) + { + /* Unregister the child from the list of slave subprocesses, so that + later, when we exit, we don't kill a totally unrelated process which + may have acquired the same pid. */ + unregister_slave_subprocess (child); + + /* Now remove the zombie from the process list. */ + for (;;) + { + if (waitid (P_PID, child, &info, 0) < 0) + { +# ifdef EINTR + if (errno == EINTR) + continue; +# endif + if (exit_on_error || !null_stderr) + error (exit_on_error ? EXIT_FAILURE : 0, errno, + _("%s subprocess"), progname); + return 127; + } + break; + } + } + + switch (info.si_code) + { + case CLD_KILLED: + case CLD_DUMPED: +# ifdef SIGPIPE + if (info.si_status == SIGPIPE && ignore_sigpipe) + return 0; +# endif + if (exit_on_error || !null_stderr) + error (exit_on_error ? EXIT_FAILURE : 0, 0, + _("%s subprocess got fatal signal %d"), + progname, info.si_status); + return 127; + case CLD_EXITED: + if (info.si_status == 127) + { + if (exit_on_error || !null_stderr) + error (exit_on_error ? EXIT_FAILURE : 0, 0, + _("%s subprocess failed"), progname); + return 127; + } + return info.si_status; + default: + abort (); + } +#else /* waitpid() is just as portable as wait() nowadays. */ WAIT_T status; @@ -253,11 +351,11 @@ wait_subprocess (pid_t child, const char *progname, if (result != child) { -#ifdef EINTR +# ifdef EINTR if (errno == EINTR) continue; -#endif -#if 0 /* defined ECHILD */ +# endif +# if 0 /* defined ECHILD */ if (errno == ECHILD) { /* Child process nonexistent?! Assume it terminated @@ -265,7 +363,7 @@ wait_subprocess (pid_t child, const char *progname, *(int *) &status = 0; break; } -#endif +# endif if (exit_on_error || !null_stderr) error (exit_on_error ? EXIT_FAILURE : 0, errno, _("%s subprocess"), progname); @@ -288,6 +386,10 @@ wait_subprocess (pid_t child, const char *progname, if (WIFSIGNALED (status)) { +# ifdef SIGPIPE + if (WTERMSIG (status) == SIGPIPE && ignore_sigpipe) + return 0; +# endif if (exit_on_error || !null_stderr) error (exit_on_error ? EXIT_FAILURE : 0, 0, _("%s subprocess got fatal signal %d"), @@ -302,4 +404,5 @@ wait_subprocess (pid_t child, const char *progname, return 127; } return WEXITSTATUS (status); +#endif }