Postfix3.3.1
master_spawn.c
[詳解]
1 /*++
2 /* NAME
3 /* master_spawn 3
4 /* SUMMARY
5 /* Postfix master - child process birth and death
6 /* SYNOPSIS
7 /* #include "master.h"
8 /*
9 /* void master_spawn(serv)
10 /* MASTER_SERV *serv;
11 /*
12 /* void master_reap_child()
13 /*
14 /* void master_delete_children(serv)
15 /* MASTER_SERV *serv;
16 /* DESCRIPTION
17 /* This module creates and cleans up child processes, and applies
18 /* a process creation throttle in case of serious trouble.
19 /* This module is the working horse for the master_avail(3) process
20 /* creation policy module.
21 /*
22 /* master_spawn() spawns off a child process for the specified service,
23 /* making the child process available for servicing connection requests.
24 /* It is an error to call this function then the specified service is
25 /* throttled.
26 /*
27 /* master_reap_child() cleans up all dead child processes. One typically
28 /* runs this function at a convenient moment after receiving a SIGCHLD
29 /* signal. When a child process terminates abnormally after being used
30 /* for the first time, process creation for that service is throttled
31 /* for a configurable amount of time.
32 /*
33 /* master_delete_children() deletes all child processes that provide
34 /* the named service. Upon exit, the process creation throttle for that
35 /* service is released.
36 /* DIAGNOSTICS
37 /* Panic: interface violations, internal inconsistencies.
38 /* Fatal errors: out of memory. Warnings: throttle on/off.
39 /* BUGS
40 /* SEE ALSO
41 /* master_avail(3), process creation policy.
42 /* LICENSE
43 /* .ad
44 /* .fi
45 /* The Secure Mailer license must be distributed with this software.
46 /* AUTHOR(S)
47 /* Wietse Venema
48 /* IBM T.J. Watson Research
49 /* P.O. Box 704
50 /* Yorktown Heights, NY 10598, USA
51 /*--*/
52 
53 /* System libraries. */
54 
55 #include <sys_defs.h>
56 #include <sys/wait.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <syslog.h> /* closelog() */
60 #include <signal.h>
61 #include <stdarg.h>
62 #include <syslog.h>
63 
64 /* Utility libraries. */
65 
66 #include <msg.h>
67 #include <binhash.h>
68 #include <mymalloc.h>
69 #include <events.h>
70 #include <vstring.h>
71 #include <argv.h>
72 
73 /* Global library. */
74 
75 #include <mail_conf.h>
76 
77 /* Application-specific. */
78 
79 #include "master_proto.h"
80 #include "master.h"
81 
83 static void master_unthrottle(MASTER_SERV *serv);
84 
85 /* master_unthrottle_wrapper - in case (char *) != (struct *) */
86 
87 static void master_unthrottle_wrapper(int unused_event, void *ptr)
88 {
89  MASTER_SERV *serv = (MASTER_SERV *) ptr;
90 
91  /*
92  * This routine runs after expiry of the timer set in master_throttle(),
93  * which gets called when it appears that the world is falling apart.
94  */
95  master_unthrottle(serv);
96 }
97 
98 /* master_unthrottle - enable process creation */
99 
100 static void master_unthrottle(MASTER_SERV *serv)
101 {
102 
103  /*
104  * Enable process creation within this class. Disable the "unthrottle"
105  * timer just in case we're being called directly from the cleanup
106  * routine, instead of from the event manager.
107  */
108  if ((serv->flags & MASTER_FLAG_THROTTLE) != 0) {
109  serv->flags &= ~MASTER_FLAG_THROTTLE;
110  event_cancel_timer(master_unthrottle_wrapper, (void *) serv);
111  if (msg_verbose)
112  msg_info("throttle released for command %s", serv->path);
113  master_avail_listen(serv);
114  }
115 }
116 
117 /* master_throttle - suspend process creation */
118 
119 static void master_throttle(MASTER_SERV *serv)
120 {
121 
122  /*
123  * Perhaps the command to be run is defective, perhaps some configuration
124  * is wrong, or perhaps the system is out of resources. Disable further
125  * process creation attempts for a while.
126  */
127  if ((serv->flags & MASTER_FLAG_THROTTLE) == 0) {
128  serv->flags |= MASTER_FLAG_THROTTLE;
129  event_request_timer(master_unthrottle_wrapper, (void *) serv,
130  serv->throttle_delay);
131  if (msg_verbose)
132  msg_info("throttling command %s", serv->path);
133  master_avail_listen(serv);
134  }
135 }
136 
137 /* master_spawn - spawn off new child process if we can */
138 
140 {
141  const char *myname = "master_spawn";
142  MASTER_PROC *proc;
143  MASTER_PID pid;
144  int n;
145  static unsigned master_generation = 0;
146  static VSTRING *env_gen = 0;
147 
148  if (master_child_table == 0)
149  master_child_table = binhash_create(0);
150  if (env_gen == 0)
151  env_gen = vstring_alloc(100);
152 
153  /*
154  * Sanity checks. The master_avail module is supposed to know what it is
155  * doing.
156  */
157  if (!MASTER_LIMIT_OK(serv->max_proc, serv->total_proc))
158  msg_panic("%s: at process limit %d", myname, serv->total_proc);
159  if (serv->avail_proc > 0)
160  msg_panic("%s: processes available: %d", myname, serv->avail_proc);
161  if (serv->flags & MASTER_FLAG_THROTTLE)
162  msg_panic("%s: throttled service: %s", myname, serv->path);
163 
164  /*
165  * Create a child process and connect parent and child via the status
166  * pipe.
167  */
168  master_generation += 1;
169  switch (pid = fork()) {
170 
171  /*
172  * Error. We're out of some essential resource. Best recourse is to
173  * try again later.
174  */
175  case -1:
176  msg_warn("%s: fork: %m -- throttling", myname);
177  master_throttle(serv);
178  return;
179 
180  /*
181  * Child process. Redirect child stdin/stdout to the parent-child
182  * connection and run the requested command. Leave child stderr
183  * alone. Disable exit handlers: they should be executed by the
184  * parent only.
185  *
186  * When we reach the process limit on a public internet service, we
187  * create stress-mode processes until the process count stays below
188  * the limit for some amount of time. See master_avail_listen().
189  */
190  case 0:
191  msg_cleanup((void (*) (void)) 0); /* disable exit handler */
192  closelog(); /* avoid filedes leak */
193 
195  msg_fatal("%s: flow pipe read descriptor <= %d",
196  myname, MASTER_FLOW_READ);
198  msg_fatal("%s: dup2: %m", myname);
199  if (close(master_flow_pipe[0]) < 0)
200  msg_fatal("close %d: %m", master_flow_pipe[0]);
201 
203  msg_fatal("%s: flow pipe read descriptor <= %d",
204  myname, MASTER_FLOW_WRITE);
206  msg_fatal("%s: dup2: %m", myname);
207  if (close(master_flow_pipe[1]) < 0)
208  msg_fatal("close %d: %m", master_flow_pipe[1]);
209 
210  close(serv->status_fd[0]); /* status channel */
211  if (serv->status_fd[1] <= MASTER_STATUS_FD)
212  msg_fatal("%s: status file descriptor collision", myname);
213  if (DUP2(serv->status_fd[1], MASTER_STATUS_FD) < 0)
214  msg_fatal("%s: dup2 status_fd: %m", myname);
215  (void) close(serv->status_fd[1]);
216 
217  for (n = 0; n < serv->listen_fd_count; n++) {
218  if (serv->listen_fd[n] <= MASTER_LISTEN_FD + n)
219  msg_fatal("%s: listen file descriptor collision", myname);
220  if (DUP2(serv->listen_fd[n], MASTER_LISTEN_FD + n) < 0)
221  msg_fatal("%s: dup2 listen_fd %d: %m",
222  myname, serv->listen_fd[n]);
223  (void) close(serv->listen_fd[n]);
224  }
225  vstring_sprintf(env_gen, "%s=%o", MASTER_GEN_NAME, master_generation);
226  if (putenv(vstring_str(env_gen)) < 0)
227  msg_fatal("%s: putenv: %m", myname);
228  if (serv->stress_param_val && serv->stress_expire_time > event_time())
229  serv->stress_param_val[0] = CONFIG_BOOL_YES[0];
230 
231  execvp(serv->path, serv->args->argv);
232  msg_fatal("%s: exec %s: %m", myname, serv->path);
233  /* NOTREACHED */
234 
235  /*
236  * Parent. Fill in a process member data structure and set up links
237  * between child and process. Say this process has become available.
238  * If this service has a wakeup timer that is turned on only when the
239  * service is actually used, turn on the wakeup timer.
240  */
241  default:
242  if (msg_verbose)
243  msg_info("spawn command %s; pid %d", serv->path, pid);
244  proc = (MASTER_PROC *) mymalloc(sizeof(MASTER_PROC));
245  proc->serv = serv;
246  proc->pid = pid;
247  proc->gen = master_generation;
248  proc->use_count = 0;
249  proc->avail = 0;
250  binhash_enter(master_child_table, (void *) &pid,
251  sizeof(pid), (void *) proc);
252  serv->total_proc++;
253  master_avail_more(serv, proc);
254  if (serv->flags & MASTER_FLAG_CONDWAKE) {
255  serv->flags &= ~MASTER_FLAG_CONDWAKE;
256  master_wakeup_init(serv);
257  if (msg_verbose)
258  msg_info("start conditional timer for %s", serv->name);
259  }
260  return;
261  }
262 }
263 
264 /* master_delete_child - destroy child process info */
265 
266 static void master_delete_child(MASTER_PROC *proc)
267 {
268  MASTER_SERV *serv;
269 
270  /*
271  * Undo the things that master_spawn did. Stop the process if it still
272  * exists, and remove it from the lookup tables. Update the number of
273  * available processes.
274  */
275  serv = proc->serv;
276  serv->total_proc--;
277  if (proc->avail == MASTER_STAT_AVAIL)
278  master_avail_less(serv, proc);
279  else
280  master_avail_listen(serv);
281  binhash_delete(master_child_table, (void *) &proc->pid,
282  sizeof(proc->pid), (void (*) (void *)) 0);
283  myfree((void *) proc);
284 }
285 
286 /* master_reap_child - reap dead children */
287 
289 {
290  MASTER_SERV *serv;
291  MASTER_PROC *proc;
292  MASTER_PID pid;
293  WAIT_STATUS_T status;
294 
295  /*
296  * Pick up termination status of all dead children. When a process failed
297  * on its first job, assume we see the symptom of a structural problem
298  * (configuration problem, system running out of resources) and back off.
299  */
300  while ((pid = waitpid((pid_t) - 1, &status, WNOHANG)) > 0) {
301  if (msg_verbose)
302  msg_info("master_reap_child: pid %d", pid);
303  if ((proc = (MASTER_PROC *) binhash_find(master_child_table,
304  (void *) &pid, sizeof(pid))) == 0)
305  msg_panic("master_reap: unknown pid: %d", pid);
306  serv = proc->serv;
307 
308 #define MASTER_KILL_SIGNAL SIGTERM
309 #define MASTER_SENT_SIGNAL(serv, status) \
310  (MASTER_MARKED_FOR_DELETION(serv) \
311  && WTERMSIG(status) == MASTER_KILL_SIGNAL)
312 
313  /*
314  * XXX The code for WIFSTOPPED() is here in case some buggy kernel
315  * reports WIFSTOPPED() events to a Postfix daemon's parent process
316  * (the master(8) daemon) instead of the tracing process (e.g., gdb).
317  *
318  * The WIFSTOPPED() test prevents master(8) from deleting its record of
319  * a child process that is stopped. That would cause a master(8)
320  * panic (unknown child) when the child terminates.
321  */
322  if (!NORMAL_EXIT_STATUS(status)) {
323  if (WIFSTOPPED(status)) {
324  msg_warn("process %s pid %d stopped by signal %d",
325  serv->path, pid, WSTOPSIG(status));
326  continue;
327  }
328  if (WIFEXITED(status))
329  msg_warn("process %s pid %d exit status %d",
330  serv->path, pid, WEXITSTATUS(status));
331  if (WIFSIGNALED(status) && !MASTER_SENT_SIGNAL(serv, status))
332  msg_warn("process %s pid %d killed by signal %d",
333  serv->path, pid, WTERMSIG(status));
334  /* master_delete_children() throttles first, then kills. */
335  if (proc->use_count == 0
336  && (serv->flags & MASTER_FLAG_THROTTLE) == 0) {
337  msg_warn("%s: bad command startup -- throttling", serv->path);
338  master_throttle(serv);
339  }
340  }
341  master_delete_child(proc);
342  }
343 }
344 
345 /* master_delete_children - delete all child processes of service */
346 
348 {
349  BINHASH_INFO **list;
350  BINHASH_INFO **info;
351  MASTER_PROC *proc;
352 
353  /*
354  * XXX turn on the throttle so that master_reap_child() doesn't. Someone
355  * has to turn off the throttle in order to stop the associated timer
356  * request, so we might just as well do it at the end.
357  */
358  master_throttle(serv);
359  for (info = list = binhash_list(master_child_table); *info; info++) {
360  proc = (MASTER_PROC *) info[0]->value;
361  if (proc->serv == serv)
362  (void) kill(proc->pid, MASTER_KILL_SIGNAL);
363  }
364  while (serv->total_proc > 0)
366  myfree((void *) list);
367  master_unthrottle(serv);
368 }
int msg_verbose
Definition: msg.c:177
#define MASTER_LIMIT_OK(limit, count)
Definition: master.h:73
void myfree(void *ptr)
Definition: mymalloc.c:207
int listen_fd_count
Definition: master.h:35
int use_count
Definition: master.h:100
#define MASTER_KILL_SIGNAL
void master_reap_child(void)
Definition: master_spawn.c:288
NORETURN msg_panic(const char *fmt,...)
Definition: msg.c:295
#define vstring_str(vp)
Definition: vstring.h:71
#define MASTER_FLOW_WRITE
Definition: master_proto.h:44
int status_fd[2]
Definition: master.h:52
int master_flow_pipe[2]
Definition: master_flow.c:17
BINHASH * binhash_create(ssize_t size)
Definition: binhash.c:175
#define MASTER_STATUS_FD
Definition: master_proto.h:56
BINHASH * master_child_table
Definition: master_spawn.c:82
char ** argv
Definition: argv.h:20
#define MASTER_LISTEN_FD
Definition: master_proto.h:57
BINHASH_INFO * binhash_enter(BINHASH *table, const void *key, ssize_t key_len, void *value)
Definition: binhash.c:207
void master_avail_less(MASTER_SERV *, MASTER_PROC *)
Definition: master_avail.c:230
#define MASTER_FLAG_THROTTLE
Definition: master.h:62
#define MASTER_FLOW_READ
Definition: master_proto.h:43
void master_avail_more(MASTER_SERV *, MASTER_PROC *)
Definition: master_avail.c:205
#define MASTER_STAT_AVAIL
Definition: master_proto.h:34
int total_proc
Definition: master.h:50
BINHASH_INFO ** binhash_list(BINHASH *table)
Definition: binhash.c:319
char * name
Definition: master.h:30
char * stress_param_val
Definition: master.h:47
int avail_proc
Definition: master.h:49
MASTER_SERV * serv
Definition: master.h:99
int flags
Definition: master.h:28
char * path
Definition: master.h:45
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
#define MASTER_SENT_SIGNAL(serv, status)
void master_spawn(MASTER_SERV *serv)
Definition: master_spawn.c:139
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
Definition: vstring.c:602
time_t stress_expire_time
Definition: master.h:48
NORETURN msg_fatal(const char *fmt,...)
Definition: msg.c:249
#define CONFIG_BOOL_YES
Definition: mail_conf.h:30
unsigned gen
Definition: master.h:97
time_t event_time(void)
Definition: events.c:647
int max_proc
Definition: master.h:44
MASTER_PID pid
Definition: master.h:96
time_t event_request_timer(EVENT_NOTIFY_TIME_FN callback, void *context, int delay)
Definition: events.c:894
void master_wakeup_init(MASTER_SERV *)
struct ARGV * args
Definition: master.h:46
int MASTER_PID
Definition: master.h:93
int * listen_fd
Definition: master.h:34
#define MASTER_GEN_NAME
Definition: master_proto.h:31
void master_avail_listen(MASTER_SERV *)
Definition: master_avail.c:124
int avail
Definition: master.h:98
int WAIT_STATUS_T
Definition: sys_defs.h:1436
int event_cancel_timer(EVENT_NOTIFY_TIME_FN callback, void *context)
Definition: events.c:965
MSG_CLEANUP_FN msg_cleanup(MSG_CLEANUP_FN cleanup_fn)
Definition: msg.c:317
#define NORMAL_EXIT_STATUS(status)
Definition: sys_defs.h:1438
#define DUP2
Definition: sys_defs.h:1307
int throttle_delay
Definition: master.h:51
void * binhash_find(BINHASH *table, const void *key, ssize_t key_len)
Definition: binhash.c:223
#define MASTER_FLAG_CONDWAKE
Definition: master.h:64
void master_delete_children(MASTER_SERV *serv)
Definition: master_spawn.c:347
void binhash_delete(BINHASH *table, const void *key, ssize_t key_len, void(*free_fn)(void *))
Definition: binhash.c:251
void * mymalloc(ssize_t len)
Definition: mymalloc.c:150
void msg_info(const char *fmt,...)
Definition: msg.c:199