root/maint/gnulib/lib/wait-process.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cleanup_slaves
  2. cleanup_slaves_action
  3. register_slave_subprocess
  4. unregister_slave_subprocess
  5. wait_subprocess

   1 /* Waiting for a subprocess to finish.
   2    Copyright (C) 2001-2003, 2005-2021 Free Software Foundation, Inc.
   3    Written by Bruno Haible <haible@clisp.cons.org>, 2001.
   4 
   5    This program is free software: you can redistribute it and/or modify
   6    it under the terms of the GNU General Public License as published by
   7    the Free Software Foundation; either version 3 of the License, or
   8    (at your option) any later version.
   9 
  10    This program is distributed in the hope that it will be useful,
  11    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13    GNU General Public License for more details.
  14 
  15    You should have received a copy of the GNU General Public License
  16    along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
  17 
  18 
  19 #include <config.h>
  20 
  21 /* Specification.  */
  22 #include "wait-process.h"
  23 
  24 #include <errno.h>
  25 #include <stdlib.h>
  26 #include <string.h>
  27 #include <signal.h>
  28 
  29 #include <sys/types.h>
  30 #include <sys/wait.h>
  31 
  32 #include "error.h"
  33 #include "fatal-signal.h"
  34 #include "xalloc.h"
  35 #include "gettext.h"
  36 
  37 #define _(str) gettext (str)
  38 
  39 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
  40 
  41 
  42 #if defined _WIN32 && ! defined __CYGWIN__
  43 
  44 # define WIN32_LEAN_AND_MEAN
  45 # include <windows.h>
  46 
  47 /* The return value of _spawnvp() is really a process handle as returned
  48    by CreateProcess().  Therefore we can kill it using TerminateProcess.  */
  49 # define kill(pid,sig) TerminateProcess ((HANDLE) (pid), sig)
  50 
  51 #endif
  52 
  53 
  54 /* Type of an entry in the slaves array.
  55    The 'used' bit determines whether this entry is currently in use.
  56    (If pid_t was an atomic type like sig_atomic_t, we could just set the
  57    'child' field to 0 when unregistering a slave process, and wouldn't need
  58    the 'used' field.)
  59    The 'used' and 'child' fields are accessed from within the cleanup_slaves()
  60    action, therefore we mark them as 'volatile'.  */
  61 typedef struct
  62 {
  63   volatile sig_atomic_t used;
  64   volatile pid_t child;
  65 }
  66 slaves_entry_t;
  67 
  68 /* The registered slave subprocesses.  */
  69 static slaves_entry_t static_slaves[32];
  70 static slaves_entry_t * volatile slaves = static_slaves;
  71 static sig_atomic_t volatile slaves_count = 0;
  72 static size_t slaves_allocated = SIZEOF (static_slaves);
  73 
  74 /* The termination signal for slave subprocesses.
  75    2003-10-07:  Terminator becomes Governator.  */
  76 #ifdef SIGHUP
  77 # define TERMINATOR SIGHUP
  78 #else
  79 # define TERMINATOR SIGTERM
  80 #endif
  81 
  82 /* The cleanup action.  It gets called asynchronously.  */
  83 static _GL_ASYNC_SAFE void
  84 cleanup_slaves (void)
     /* [previous][next][first][last][top][bottom][index][help] */
  85 {
  86   for (;;)
  87     {
  88       /* Get the last registered slave.  */
  89       size_t n = slaves_count;
  90       if (n == 0)
  91         break;
  92       n--;
  93       slaves_count = n;
  94       /* Skip unused entries in the slaves array.  */
  95       if (slaves[n].used)
  96         {
  97           pid_t slave = slaves[n].child;
  98 
  99           /* Kill the slave.  */
 100           kill (slave, TERMINATOR);
 101         }
 102     }
 103 }
 104 
 105 /* The cleanup action, taking a signal argument.
 106    It gets called asynchronously.  */
 107 static _GL_ASYNC_SAFE void
 108 cleanup_slaves_action (_GL_UNUSED int sig)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110   cleanup_slaves ();
 111 }
 112 
 113 /* Register a subprocess as being a slave process.  This means that the
 114    subprocess will be terminated when its creator receives a catchable fatal
 115    signal or exits normally.  Registration ends when wait_subprocess()
 116    notices that the subprocess has exited.  */
 117 void
 118 register_slave_subprocess (pid_t child)
     /* [previous][next][first][last][top][bottom][index][help] */
 119 {
 120   static bool cleanup_slaves_registered = false;
 121   if (!cleanup_slaves_registered)
 122     {
 123       atexit (cleanup_slaves);
 124       if (at_fatal_signal (cleanup_slaves_action) < 0)
 125         xalloc_die ();
 126       cleanup_slaves_registered = true;
 127     }
 128 
 129   /* Try to store the new slave in an unused entry of the slaves array.  */
 130   {
 131     slaves_entry_t *s = slaves;
 132     slaves_entry_t *s_end = s + slaves_count;
 133 
 134     for (; s < s_end; s++)
 135       if (!s->used)
 136         {
 137           /* The two uses of 'volatile' in the slaves_entry_t type above
 138              (and ISO C 99 section 5.1.2.3.(5)) ensure that we mark the
 139              entry as used only after the child pid has been written to the
 140              memory location s->child.  */
 141           s->child = child;
 142           s->used = 1;
 143           return;
 144         }
 145   }
 146 
 147   if (slaves_count == slaves_allocated)
 148     {
 149       /* Extend the slaves array.  Note that we cannot use xrealloc(),
 150          because then the cleanup_slaves() function could access an already
 151          deallocated array.  */
 152       slaves_entry_t *old_slaves = slaves;
 153       size_t new_slaves_allocated = 2 * slaves_allocated;
 154       slaves_entry_t *new_slaves =
 155         (slaves_entry_t *)
 156         malloc (new_slaves_allocated * sizeof (slaves_entry_t));
 157       if (new_slaves == NULL)
 158         {
 159           /* xalloc_die() will call exit() which will invoke cleanup_slaves().
 160              Additionally we need to kill child, because it's not yet among
 161              the slaves list.  */
 162           kill (child, TERMINATOR);
 163           xalloc_die ();
 164         }
 165       memcpy (new_slaves, old_slaves,
 166               slaves_allocated * sizeof (slaves_entry_t));
 167       slaves = new_slaves;
 168       slaves_allocated = new_slaves_allocated;
 169       /* Now we can free the old slaves array.  */
 170       if (old_slaves != static_slaves)
 171         free (old_slaves);
 172     }
 173   /* The three uses of 'volatile' in the types above (and ISO C 99 section
 174      5.1.2.3.(5)) ensure that we increment the slaves_count only after the
 175      new slave and its 'used' bit have been written to the memory locations
 176      that make up slaves[slaves_count].  */
 177   slaves[slaves_count].child = child;
 178   slaves[slaves_count].used = 1;
 179   slaves_count++;
 180 }
 181 
 182 /* Unregister a child from the list of slave subprocesses.  */
 183 static void
 184 unregister_slave_subprocess (pid_t child)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186   /* The easiest way to remove an entry from a list that can be used by
 187      an asynchronous signal handler is just to mark it as unused.  For this,
 188      we rely on sig_atomic_t.  */
 189   slaves_entry_t *s = slaves;
 190   slaves_entry_t *s_end = s + slaves_count;
 191 
 192   for (; s < s_end; s++)
 193     if (s->used && s->child == child)
 194       s->used = 0;
 195 }
 196 
 197 
 198 /* Wait for a subprocess to finish.  Return its exit code.
 199    If it didn't terminate correctly, exit if exit_on_error is true, otherwise
 200    return 127.  */
 201 int
 202 wait_subprocess (pid_t child, const char *progname,
     /* [previous][next][first][last][top][bottom][index][help] */
 203                  bool ignore_sigpipe, bool null_stderr,
 204                  bool slave_process, bool exit_on_error,
 205                  int *termsigp)
 206 {
 207 #if HAVE_WAITID && defined WNOWAIT && 0
 208   /* Commented out because waitid() without WEXITED and with WNOWAIT doesn't
 209      work: On Solaris 7 and OSF/1 4.0, it returns -1 and sets errno = ECHILD,
 210      and on HP-UX 10.20 it just hangs.  */
 211   /* Use of waitid() with WNOWAIT avoids a race condition: If slave_process is
 212      true, and this process sleeps a very long time between the return from
 213      waitpid() and the execution of unregister_slave_subprocess(), and
 214      meanwhile another process acquires the same PID as child, and then - still
 215      before unregister_slave_subprocess() - this process gets a fatal signal,
 216      it would kill the other totally unrelated process.  */
 217   siginfo_t info;
 218 
 219   if (termsigp != NULL)
 220     *termsigp = 0;
 221   for (;;)
 222     {
 223       if (waitid (P_PID, child, &info, WEXITED | (slave_process ? WNOWAIT : 0))
 224           < 0)
 225         {
 226 # ifdef EINTR
 227           if (errno == EINTR)
 228             continue;
 229 # endif
 230           if (exit_on_error || !null_stderr)
 231             error (exit_on_error ? EXIT_FAILURE : 0, errno,
 232                    _("%s subprocess"), progname);
 233           return 127;
 234         }
 235 
 236       /* info.si_code is set to one of CLD_EXITED, CLD_KILLED, CLD_DUMPED,
 237          CLD_TRAPPED, CLD_STOPPED, CLD_CONTINUED.  Loop until the program
 238          terminates.  */
 239       if (info.si_code == CLD_EXITED
 240           || info.si_code == CLD_KILLED || info.si_code == CLD_DUMPED)
 241         break;
 242     }
 243 
 244   /* The child process has exited or was signalled.  */
 245 
 246   if (slave_process)
 247     {
 248       /* Unregister the child from the list of slave subprocesses, so that
 249          later, when we exit, we don't kill a totally unrelated process which
 250          may have acquired the same pid.  */
 251       unregister_slave_subprocess (child);
 252 
 253       /* Now remove the zombie from the process list.  */
 254       for (;;)
 255         {
 256           if (waitid (P_PID, child, &info, WEXITED) < 0)
 257             {
 258 # ifdef EINTR
 259               if (errno == EINTR)
 260                 continue;
 261 # endif
 262               if (exit_on_error || !null_stderr)
 263                 error (exit_on_error ? EXIT_FAILURE : 0, errno,
 264                        _("%s subprocess"), progname);
 265               return 127;
 266             }
 267           break;
 268         }
 269     }
 270 
 271   switch (info.si_code)
 272     {
 273     case CLD_KILLED:
 274     case CLD_DUMPED:
 275       if (termsigp != NULL)
 276         *termsigp = info.si_status; /* TODO: or info.si_signo? */
 277 # ifdef SIGPIPE
 278       if (info.si_status == SIGPIPE && ignore_sigpipe)
 279         return 0;
 280 # endif
 281       if (exit_on_error || (!null_stderr && termsigp == NULL))
 282         error (exit_on_error ? EXIT_FAILURE : 0, 0,
 283                _("%s subprocess got fatal signal %d"),
 284                progname, info.si_status);
 285       return 127;
 286     case CLD_EXITED:
 287       if (info.si_status == 127)
 288         {
 289           if (exit_on_error || !null_stderr)
 290             error (exit_on_error ? EXIT_FAILURE : 0, 0,
 291                    _("%s subprocess failed"), progname);
 292           return 127;
 293         }
 294       return info.si_status;
 295     default:
 296       abort ();
 297     }
 298 #else
 299   /* waitpid() is just as portable as wait() nowadays.  */
 300   int status;
 301 
 302   if (termsigp != NULL)
 303     *termsigp = 0;
 304   status = 0;
 305   for (;;)
 306     {
 307       int result = waitpid (child, &status, 0);
 308 
 309       if (result != child)
 310         {
 311 # ifdef EINTR
 312           if (errno == EINTR)
 313             continue;
 314 # endif
 315 # if 0 /* defined ECHILD */
 316           if (errno == ECHILD)
 317             {
 318               /* Child process nonexistent?! Assume it terminated
 319                  successfully.  */
 320               status = 0;
 321               break;
 322             }
 323 # endif
 324           if (exit_on_error || !null_stderr)
 325             error (exit_on_error ? EXIT_FAILURE : 0, errno,
 326                    _("%s subprocess"), progname);
 327           return 127;
 328         }
 329 
 330       /* One of WIFSIGNALED (status), WIFEXITED (status), WIFSTOPPED (status)
 331          must always be true, since we did not specify WCONTINUED in the
 332          waitpid() call.  Loop until the program terminates.  */
 333       if (!WIFSTOPPED (status))
 334         break;
 335     }
 336 
 337   /* The child process has exited or was signalled.  */
 338 
 339   if (slave_process)
 340     /* Unregister the child from the list of slave subprocesses, so that
 341        later, when we exit, we don't kill a totally unrelated process which
 342        may have acquired the same pid.  */
 343     unregister_slave_subprocess (child);
 344 
 345   if (WIFSIGNALED (status))
 346     {
 347       if (termsigp != NULL)
 348         *termsigp = WTERMSIG (status);
 349 # ifdef SIGPIPE
 350       if (WTERMSIG (status) == SIGPIPE && ignore_sigpipe)
 351         return 0;
 352 # endif
 353       if (exit_on_error || (!null_stderr && termsigp == NULL))
 354         error (exit_on_error ? EXIT_FAILURE : 0, 0,
 355                _("%s subprocess got fatal signal %d"),
 356                progname, (int) WTERMSIG (status));
 357       return 127;
 358     }
 359   if (!WIFEXITED (status))
 360     abort ();
 361   if (WEXITSTATUS (status) == 127)
 362     {
 363       if (exit_on_error || !null_stderr)
 364         error (exit_on_error ? EXIT_FAILURE : 0, 0,
 365                _("%s subprocess failed"), progname);
 366       return 127;
 367     }
 368   return WEXITSTATUS (status);
 369 #endif
 370 }

/* [previous][next][first][last][top][bottom][index][help] */