reaper.c 3.92 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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
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
/* 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>

static sig_atomic_t halloween;

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

  halloween = 1;
}

struct reaper
{
  struct reap super;

  /* Mapping of from pids to exit-callbacks. */
  /* NOTE: This assumes that a pid_t fits in an int. */
  struct alist *children;
};

static void do_reap(struct reap *c,
		    pid_t pid, struct exit_callback *callback)
{
  struct reaper *closure = (struct reaper *) c;

  MDEBUG(closure);

  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
111
	      ALIST_SET(r->children, pid, NULL);
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
	      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:
	  werror("reaper.c: waitpid() returned EINTR.\n");
	  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
139
struct reap *make_reaper(void)
140
141
142
143
144
145
146
{
  struct reaper *closure;

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

Niels Möller's avatar
Niels Möller committed
147
  return &closure->super;
148
149
150
}

/* FIXME: Prehaps this function should return a suitable exit code? */
Niels Möller's avatar
Niels Möller committed
151
void reaper_run(struct reap *r, struct io_backend *b)
152
{
Niels Möller's avatar
Niels Möller committed
153
154
  struct reaper *self  = (struct reaper *) r;
  
155
156
157
  struct sigaction pipe;
  struct sigaction chld;

Niels Möller's avatar
Niels Möller committed
158
159
  MDEBUG(self);
  
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
  pipe.sa_handler = SIG_IGN;
  sigemptyset(&pipe.sa_mask);
  pipe.sa_flags = 0;
  pipe.sa_restorer = NULL;

  chld.sa_handler = child_handler;
  sigemptyset(&chld.sa_mask);
  chld.sa_flags = SA_NOCLDSTOP;
  chld.sa_restorer = NULL;
  
  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
178
      reap(self);
179
}