reaper.c 3.96 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/* reaper.c
 *
 * Handle child processes.
 *
 * $Id$
 */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Mller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "reaper.h"

#include "alist.h"
#include "werror.h"
#include "xalloc.h"

#include <assert.h>
#include <string.h>

#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

41
42
43
44
45
46
#define CLASS_DEFINE
#include "reaper.h.x"
#undef CLASS_DEFINE

#include "reaper.c.x"

47
48
49
50
51
52
53
54
55
static sig_atomic_t halloween;

static void child_handler(int signum)
{
  assert(signum == SIGCHLD);

  halloween = 1;
}

56
57
58
59
60
61
62
63
64
65
/* CLASS:
   (class
     (name reaper)
     (super reap)
     (vars
       ; Mapping of from pids to exit-callbacks. 
       ; NOTE: This assumes that a pid_t fits in an int. 
       (children object alist)))
*/

66
67
68
static void do_reap(struct reap *c,
		    pid_t pid, struct exit_callback *callback)
{
69
  CAST(reaper, closure, c);
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115

  assert(!ALIST_GET(closure->children, pid));

  ALIST_SET(closure->children, pid, callback);
}
  
static void reap(struct reaper *r)
{
  pid_t pid;
  int status;

  /* We must reset this flag before reaping the zoombies. */
  halloween = 0;
  
  while( (pid = waitpid(-1, &status, WNOHANG)) )
    {
      if (pid > 0)
	{
	  int signaled;
	  int value;
	  int core;
	  struct exit_callback *callback;
	  
	  if (WIFEXITED(status))
	    {
	      verbose("Child %d died with exit code %d.\n",
		      pid, WEXITSTATUS(status));
	      signaled = 0;
	      core = 0;
	      value = WEXITSTATUS(status);
	    }
	  else if (WIFSIGNALED(status))
	    {
	      verbose("Child %d killed by signal %d.\n",
		      pid, WTERMSIG(status));
	      signaled = 1;
	      core = !!WCOREDUMP(status);
	      value = WTERMSIG(status);
	    }
	  else
	    fatal("Child died, but neither WIFEXITED or WIFSIGNALED is true.\n");

	  callback = ALIST_GET(r->children, pid);
	  
	  if (callback)
	    {
Niels Möller's avatar
Niels Möller committed
116
	      ALIST_SET(r->children, pid, NULL);
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
	      EXIT_CALLBACK(callback, signaled, core, value);
	    }
	  else
	    {
	      if (WIFSIGNALED(status))
		werror("Unregistered child %d killed by signal %d.\n",
		       pid, value);
	      else
		werror("Unregistered child %d died with exit status %d.\n",
		       pid, value);
	    }
	}
      else switch(errno)
	{
	case EINTR:
132
	  wwrite("reaper.c: waitpid() returned EINTR.\n");
133
134
135
136
137
138
139
140
141
142
143
	  break;
	case ECHILD:
	  /* No more child processes */
	  return;
	default:
	  fatal("reaper.c: waitpid failed (errno = %d), %s\n",
		errno, strerror(errno));
	}
    }
}

Niels Möller's avatar
Niels Möller committed
144
struct reap *make_reaper(void)
145
{
146
  NEW(reaper, closure);
147
148
149
150

  closure->super.reap = do_reap;
  closure->children = make_linked_alist(0, -1);

Niels Möller's avatar
Niels Möller committed
151
  return &closure->super;
152
153
}

Niels Möller's avatar
Niels Möller committed
154
/* FIXME: Perhaps this function should return a suitable exit code? */
Niels Möller's avatar
Niels Möller committed
155
void reaper_run(struct reap *r, struct io_backend *b)
156
{
157
  CAST(reaper, self, r);
Niels Möller's avatar
Niels Möller committed
158
  
159
160
  struct sigaction pipe;
  struct sigaction chld;
161
162
163
  
  memset(&pipe, 0, sizeof(pipe));
  memset(&chld, 0, sizeof(chld));
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

  pipe.sa_handler = SIG_IGN;
  sigemptyset(&pipe.sa_mask);
  pipe.sa_flags = 0;

  chld.sa_handler = child_handler;
  sigemptyset(&chld.sa_mask);
  chld.sa_flags = SA_NOCLDSTOP;
  
  if (sigaction(SIGPIPE, &pipe, NULL) < 0)
    fatal("Failed to ignore SIGPIPE.\n");
  if (sigaction(SIGCHLD, &chld, NULL) < 0)
    fatal("Failed to install handler for SIGCHLD.\n");

  halloween = 0;
  while(io_iter(b))
    if (halloween)
Niels Möller's avatar
Niels Möller committed
181
      reap(self);
182
}