New module 'wait-process'.
[gnulib.git] / lib / wait-process.c
1 /* Waiting for a subprocess to finish.
2    Copyright (C) 2001-2003 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 2, or (at your option)
8    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, write to the Free Software Foundation,
17    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 /* Specification.  */
25 #include "wait-process.h"
26
27 #include <errno.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <signal.h>
31
32 #include <sys/types.h>
33
34 #if defined _MSC_VER || defined __MINGW32__
35
36 /* Native Woe32 API.  */
37 #include <process.h>
38 #define waitpid(pid,statusp,options) _cwait (statusp, pid, WAIT_CHILD)
39 #define WAIT_T int
40 #define WTERMSIG(x) ((x) & 0xff) /* or: SIGABRT ?? */
41 #define WCOREDUMP(x) 0
42 #define WEXITSTATUS(x) (((x) >> 8) & 0xff) /* or: (x) ?? */
43 #define WIFSIGNALED(x) (WTERMSIG (x) != 0) /* or: ((x) == 3) ?? */
44 #define WIFEXITED(x) (WTERMSIG (x) == 0) /* or: ((x) != 3) ?? */
45 #define WIFSTOPPED(x) 0
46
47 #else
48
49 /* Unix API.  */
50 #include <sys/wait.h>
51 /* On Linux, WEXITSTATUS are bits 15..8 and WTERMSIG are bits 7..0, while
52    BeOS uses the contrary.  Therefore we use the abstract macros.  */
53 #if HAVE_UNION_WAIT
54 # define WAIT_T union wait
55 # ifndef WTERMSIG
56 #  define WTERMSIG(x) ((x).w_termsig)
57 # endif
58 # ifndef WCOREDUMP
59 #  define WCOREDUMP(x) ((x).w_coredump)
60 # endif
61 # ifndef WEXITSTATUS
62 #  define WEXITSTATUS(x) ((x).w_retcode)
63 # endif
64 #else
65 # define WAIT_T int
66 # ifndef WTERMSIG
67 #  define WTERMSIG(x) ((x) & 0x7f)
68 # endif
69 # ifndef WCOREDUMP
70 #  define WCOREDUMP(x) ((x) & 0x80)
71 # endif
72 # ifndef WEXITSTATUS
73 #  define WEXITSTATUS(x) (((x) >> 8) & 0xff)
74 # endif
75 #endif
76 /* For valid x, exactly one of WIFSIGNALED(x), WIFEXITED(x), WIFSTOPPED(x)
77    is true.  */
78 #ifndef WIFSIGNALED
79 # define WIFSIGNALED(x) (WTERMSIG (x) != 0 && WTERMSIG(x) != 0x7f)
80 #endif
81 #ifndef WIFEXITED
82 # define WIFEXITED(x) (WTERMSIG (x) == 0)
83 #endif
84 #ifndef WIFSTOPPED
85 # define WIFSTOPPED(x) (WTERMSIG (x) == 0x7f)
86 #endif
87 /* Note that portable applications may access
88    WTERMSIG(x) only if WIFSIGNALED(x) is true, and
89    WEXITSTATUS(x) only if WIFEXITED(x) is true.  */
90
91 #endif
92
93 #include "error.h"
94 #include "exit.h"
95 #include "fatal-signal.h"
96 #include "xalloc.h"
97 #include "gettext.h"
98
99 #define _(str) gettext (str)
100
101 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
102
103
104 /* Type of an entry in the slaves array.
105    The 'used' bit determines whether this entry is currently in use.
106    (If pid_t was an atomic type like sig_atomic_t, we could just set the
107    'child' field to 0 when unregistering a slave process, and wouldn't need
108    the 'used' field.)
109    The 'used' and 'child' fields are accessed from within the cleanup_slaves()
110    action, therefore we mark them as 'volatile'.  */
111 typedef struct
112 {
113   volatile sig_atomic_t used;
114   volatile pid_t child;
115 }
116 slaves_entry_t;
117
118 /* The registered slave subprocesses.  */
119 static slaves_entry_t static_slaves[32];
120 static slaves_entry_t * volatile slaves = static_slaves;
121 static sig_atomic_t volatile slaves_count = 0;
122 static size_t slaves_allocated = SIZEOF (static_slaves);
123
124 /* The termination signal for slave subprocesses.
125    2003-10-07:  Terminator becomes Governator.  */
126 #ifdef SIGHUP
127 # define TERMINATOR SIGHUP
128 #else
129 # define TERMINATOR SIGTERM
130 #endif
131
132 /* The cleanup action.  It gets called asynchronously.  */
133 static void
134 cleanup_slaves ()
135 {
136   for (;;)
137     {
138       /* Get the last registered slave.  */
139       size_t n = slaves_count;
140       if (n == 0)
141         break;
142       n--;
143       slaves_count = n;
144       /* Skip unused entries in the slaves array.  */
145       if (slaves[n].used)
146         {
147           pid_t slave = slaves[n].child;
148
149           /* Kill the slave.  */
150           kill (slave, TERMINATOR);
151         }
152     }
153 }
154
155 /* Register a subprocess as being a slave process.  This means that the
156    subprocess will be terminated when its creator receives a catchable fatal
157    signal or exits normally.  Registration ends when wait_subprocess()
158    notices that the subprocess has exited.  */
159 void
160 register_slave_subprocess (pid_t child)
161 {
162   static bool cleanup_slaves_registered = false;
163   if (!cleanup_slaves_registered)
164     {
165       atexit (cleanup_slaves);
166       at_fatal_signal (cleanup_slaves);
167       cleanup_slaves_registered = true;
168     }
169
170   /* Try to store the new slave in an unused entry of the slaves array.  */
171   {
172     slaves_entry_t *s = slaves;
173     slaves_entry_t *s_end = s + slaves_count;
174
175     for (; s < s_end; s++)
176       if (!s->used)
177         {
178           /* The two uses of 'volatile' in the slaves_entry_t type above
179              (and ISO C 99 section 5.1.2.3.(5)) ensure that we mark the
180              entry as used only after the child pid has been written to the
181              memory location s->child.  */
182           s->child = child;
183           s->used = 1;
184           return;
185         }
186   }
187
188   if (slaves_count == slaves_allocated)
189     {
190       /* Extend the slaves array.  Note that we cannot use xrealloc(),
191          because then the cleanup_slaves() function could access an already
192          deallocated array.  */
193       slaves_entry_t *old_slaves = slaves;
194       size_t new_slaves_allocated = 2 * slaves_allocated;
195       slaves_entry_t *new_slaves =
196         malloc (new_slaves_allocated * sizeof (slaves_entry_t));
197       if (new_slaves == NULL)
198         {
199           /* xalloc_die() will call exit() which will invoke cleanup_slaves().
200              Additionally we need to kill child, because it's not yet among
201              the slaves list.  */
202           kill (child, TERMINATOR);
203           xalloc_die ();
204         }
205       memcpy (new_slaves, old_slaves,
206               slaves_allocated * sizeof (slaves_entry_t));
207       slaves = new_slaves;
208       slaves_allocated = new_slaves_allocated;
209       /* Now we can free the old slaves array.  */
210       if (old_slaves != static_slaves)
211         free (old_slaves);
212     }
213   /* The three uses of 'volatile' in the types above (and ISO C 99 section
214      5.1.2.3.(5)) ensure that we increment the slaves_count only after the
215      new slave and its 'used' bit have been written to the memory locations
216      that make up slaves[slaves_count].  */
217   slaves[slaves_count].child = child;
218   slaves[slaves_count].used = 1;
219   slaves_count++;
220 }
221
222 /* Unregister a child from the list of slave subprocesses.  */
223 static inline void
224 unregister_slave_subprocess (pid_t child)
225 {
226   /* The easiest way to remove an entry from a list that can be used by
227      an asynchronous signal handler is just to mark it as unused.  For this,
228      we rely on sig_atomic_t.  */
229   slaves_entry_t *s = slaves;
230   slaves_entry_t *s_end = s + slaves_count;
231
232   for (; s < s_end; s++)
233     if (s->used && s->child == child)
234       s->used = 0;
235 }
236
237
238 /* Wait for a subprocess to finish.  Return its exit code.
239    If it didn't terminate correctly, exit if exit_on_error is true, otherwise
240    return 127.  */
241 int
242 wait_subprocess (pid_t child, const char *progname,
243                  bool null_stderr,
244                  bool slave_process, bool exit_on_error)
245 {
246   /* waitpid() is just as portable as wait() nowadays.  */
247   WAIT_T status;
248
249   *(int *) &status = 0;
250   for (;;)
251     {
252       int result = waitpid (child, &status, 0);
253
254       if (result != child)
255         {
256 #ifdef EINTR
257           if (errno == EINTR)
258             continue;
259 #endif
260 #if 0 /* defined ECHILD */
261           if (errno == ECHILD)
262             {
263               /* Child process nonexistent?! Assume it terminated
264                  successfully.  */
265               *(int *) &status = 0;
266               break;
267             }
268 #endif
269           if (exit_on_error || !null_stderr)
270             error (exit_on_error ? EXIT_FAILURE : 0, errno,
271                    _("%s subprocess"), progname);
272           return 127;
273         }
274
275       /* One of WIFSIGNALED (status), WIFEXITED (status), WIFSTOPPED (status)
276          must always be true.  Loop until the program terminates.  */
277       if (!WIFSTOPPED (status))
278         break;
279     }
280
281   /* The child process has exited or was signalled.  */
282
283   if (slave_process)
284     /* Unregister the child from the list of slave subprocesses, so that
285        later, when we exit, we don't kill a totally unrelated process which
286        may have acquired the same pid.  */
287     unregister_slave_subprocess (child);
288
289   if (WIFSIGNALED (status))
290     {
291       if (exit_on_error || !null_stderr)
292         error (exit_on_error ? EXIT_FAILURE : 0, 0,
293                _("%s subprocess got fatal signal %d"),
294                progname, (int) WTERMSIG (status));
295       return 127;
296     }
297   if (WEXITSTATUS (status) == 127)
298     {
299       if (exit_on_error || !null_stderr)
300         error (exit_on_error ? EXIT_FAILURE : 0, 0,
301                _("%s subprocess failed"), progname);
302       return 127;
303     }
304   return WEXITSTATUS (status);
305 }