Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_process.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11 #include <ngx_channel.h>
12 
13 
14 typedef struct {
15  int signo;
16  char *signame;
17  char *name;
18  void (*handler)(int signo);
19 } ngx_signal_t;
20 
21 
22 
23 static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
24 static void ngx_signal_handler(int signo);
25 static void ngx_process_get_status(void);
26 static void ngx_unlock_mutexes(ngx_pid_t pid);
27 
28 
30 char **ngx_argv;
31 char **ngx_os_argv;
32 
37 
38 
42  "reload",
43  ngx_signal_handler },
44 
47  "reopen",
48  ngx_signal_handler },
49 
52  "",
53  ngx_signal_handler },
54 
57  "stop",
58  ngx_signal_handler },
59 
62  "quit",
63  ngx_signal_handler },
64 
67  "",
68  ngx_signal_handler },
69 
70  { SIGALRM, "SIGALRM", "", ngx_signal_handler },
71 
72  { SIGINT, "SIGINT", "", ngx_signal_handler },
73 
74  { SIGIO, "SIGIO", "", ngx_signal_handler },
75 
76  { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },
77 
78  { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN },
79 
80  { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN },
81 
82  { 0, NULL, "", NULL }
83 };
84 
85 
88  char *name, ngx_int_t respawn)
89 {
90  u_long on;
91  ngx_pid_t pid;
92  ngx_int_t s;
93 
94  if (respawn >= 0) {
95  s = respawn;
96 
97  } else {
98  for (s = 0; s < ngx_last_process; s++) {
99  if (ngx_processes[s].pid == -1) {
100  break;
101  }
102  }
103 
104  if (s == NGX_MAX_PROCESSES) {
105  ngx_log_error(NGX_LOG_ALERT, cycle->log, 0,
106  "no more than %d processes can be spawned",
108  return NGX_INVALID_PID;
109  }
110  }
111 
112 
113  if (respawn != NGX_PROCESS_DETACHED) {
114 
115  /* Solaris 9 still has no AF_LOCAL */
116 
117  if (socketpair(AF_UNIX, SOCK_STREAM, 0, ngx_processes[s].channel) == -1)
118  {
120  "socketpair() failed while spawning \"%s\"", name);
121  return NGX_INVALID_PID;
122  }
123 
125  "channel %d:%d",
126  ngx_processes[s].channel[0],
127  ngx_processes[s].channel[1]);
128 
129  if (ngx_nonblocking(ngx_processes[s].channel[0]) == -1) {
131  ngx_nonblocking_n " failed while spawning \"%s\"",
132  name);
133  ngx_close_channel(ngx_processes[s].channel, cycle->log);
134  return NGX_INVALID_PID;
135  }
136 
137  if (ngx_nonblocking(ngx_processes[s].channel[1]) == -1) {
139  ngx_nonblocking_n " failed while spawning \"%s\"",
140  name);
141  ngx_close_channel(ngx_processes[s].channel, cycle->log);
142  return NGX_INVALID_PID;
143  }
144 
145  on = 1;
146  if (ioctl(ngx_processes[s].channel[0], FIOASYNC, &on) == -1) {
148  "ioctl(FIOASYNC) failed while spawning \"%s\"", name);
149  ngx_close_channel(ngx_processes[s].channel, cycle->log);
150  return NGX_INVALID_PID;
151  }
152 
153  if (fcntl(ngx_processes[s].channel[0], F_SETOWN, ngx_pid) == -1) {
155  "fcntl(F_SETOWN) failed while spawning \"%s\"", name);
156  ngx_close_channel(ngx_processes[s].channel, cycle->log);
157  return NGX_INVALID_PID;
158  }
159 
160  if (fcntl(ngx_processes[s].channel[0], F_SETFD, FD_CLOEXEC) == -1) {
162  "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
163  name);
164  ngx_close_channel(ngx_processes[s].channel, cycle->log);
165  return NGX_INVALID_PID;
166  }
167 
168  if (fcntl(ngx_processes[s].channel[1], F_SETFD, FD_CLOEXEC) == -1) {
170  "fcntl(FD_CLOEXEC) failed while spawning \"%s\"",
171  name);
172  ngx_close_channel(ngx_processes[s].channel, cycle->log);
173  return NGX_INVALID_PID;
174  }
175 
176  ngx_channel = ngx_processes[s].channel[1];
177 
178  } else {
179  ngx_processes[s].channel[0] = -1;
180  ngx_processes[s].channel[1] = -1;
181  }
182 
183  ngx_process_slot = s;
184 
185 
186  pid = fork();
187 
188  switch (pid) {
189 
190  case -1:
192  "fork() failed while spawning \"%s\"", name);
193  ngx_close_channel(ngx_processes[s].channel, cycle->log);
194  return NGX_INVALID_PID;
195 
196  case 0:
197  ngx_pid = ngx_getpid();
198  proc(cycle, data);
199  break;
200 
201  default:
202  break;
203  }
204 
205  ngx_log_error(NGX_LOG_NOTICE, cycle->log, 0, "start %s %P", name, pid);
206 
207  ngx_processes[s].pid = pid;
208  ngx_processes[s].exited = 0;
209 
210  if (respawn >= 0) {
211  return pid;
212  }
213 
214  ngx_processes[s].proc = proc;
215  ngx_processes[s].data = data;
216  ngx_processes[s].name = name;
217  ngx_processes[s].exiting = 0;
218 
219  switch (respawn) {
220 
222  ngx_processes[s].respawn = 0;
223  ngx_processes[s].just_spawn = 0;
224  ngx_processes[s].detached = 0;
225  break;
226 
228  ngx_processes[s].respawn = 0;
229  ngx_processes[s].just_spawn = 1;
230  ngx_processes[s].detached = 0;
231  break;
232 
233  case NGX_PROCESS_RESPAWN:
234  ngx_processes[s].respawn = 1;
235  ngx_processes[s].just_spawn = 0;
236  ngx_processes[s].detached = 0;
237  break;
238 
240  ngx_processes[s].respawn = 1;
241  ngx_processes[s].just_spawn = 1;
242  ngx_processes[s].detached = 0;
243  break;
244 
246  ngx_processes[s].respawn = 0;
247  ngx_processes[s].just_spawn = 0;
248  ngx_processes[s].detached = 1;
249  break;
250  }
251 
252  if (s == ngx_last_process) {
254  }
255 
256  return pid;
257 }
258 
259 
260 ngx_pid_t
262 {
263  return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name,
265 }
266 
267 
268 static void
269 ngx_execute_proc(ngx_cycle_t *cycle, void *data)
270 {
271  ngx_exec_ctx_t *ctx = data;
272 
273  if (execve(ctx->path, ctx->argv, ctx->envp) == -1) {
275  "execve() failed while executing %s \"%s\"",
276  ctx->name, ctx->path);
277  }
278 
279  exit(1);
280 }
281 
282 
283 ngx_int_t
285 {
286  ngx_signal_t *sig;
287  struct sigaction sa;
288 
289  for (sig = signals; sig->signo != 0; sig++) {
290  ngx_memzero(&sa, sizeof(struct sigaction));
291  sa.sa_handler = sig->handler;
292  sigemptyset(&sa.sa_mask);
293  if (sigaction(sig->signo, &sa, NULL) == -1) {
295  "sigaction(%s) failed", sig->signame);
296  return NGX_ERROR;
297  }
298  }
299 
300  return NGX_OK;
301 }
302 
303 
304 void
305 ngx_signal_handler(int signo)
306 {
307  char *action;
308  ngx_int_t ignore;
309  ngx_err_t err;
310  ngx_signal_t *sig;
311 
312  ignore = 0;
313 
314  err = ngx_errno;
315 
316  for (sig = signals; sig->signo != 0; sig++) {
317  if (sig->signo == signo) {
318  break;
319  }
320  }
321 
323 
324  action = "";
325 
326  switch (ngx_process) {
327 
328  case NGX_PROCESS_MASTER:
329  case NGX_PROCESS_SINGLE:
330  switch (signo) {
331 
333  ngx_quit = 1;
334  action = ", shutting down";
335  break;
336 
338  case SIGINT:
339  ngx_terminate = 1;
340  action = ", exiting";
341  break;
342 
344  if (ngx_daemonized) {
345  ngx_noaccept = 1;
346  action = ", stop accepting connections";
347  }
348  break;
349 
351  ngx_reconfigure = 1;
352  action = ", reconfiguring";
353  break;
354 
356  ngx_reopen = 1;
357  action = ", reopening logs";
358  break;
359 
361  if (getppid() > 1 || ngx_new_binary > 0) {
362 
363  /*
364  * Ignore the signal in the new binary if its parent is
365  * not the init process, i.e. the old binary's process
366  * is still running. Or ignore the signal in the old binary's
367  * process if the new binary's process is already running.
368  */
369 
370  action = ", ignoring";
371  ignore = 1;
372  break;
373  }
374 
375  ngx_change_binary = 1;
376  action = ", changing binary";
377  break;
378 
379  case SIGALRM:
380  ngx_sigalrm = 1;
381  break;
382 
383  case SIGIO:
384  ngx_sigio = 1;
385  break;
386 
387  case SIGCHLD:
388  ngx_reap = 1;
389  break;
390  }
391 
392  break;
393 
394  case NGX_PROCESS_WORKER:
395  case NGX_PROCESS_HELPER:
396  switch (signo) {
397 
399  if (!ngx_daemonized) {
400  break;
401  }
402  ngx_debug_quit = 1;
404  ngx_quit = 1;
405  action = ", shutting down";
406  break;
407 
409  case SIGINT:
410  ngx_terminate = 1;
411  action = ", exiting";
412  break;
413 
415  ngx_reopen = 1;
416  action = ", reopening logs";
417  break;
418 
421  case SIGIO:
422  action = ", ignoring";
423  break;
424  }
425 
426  break;
427  }
428 
430  "signal %d (%s) received%s", signo, sig->signame, action);
431 
432  if (ignore) {
434  "the changing binary signal is ignored: "
435  "you should shutdown or terminate "
436  "before either old or new binary's process");
437  }
438 
439  if (signo == SIGCHLD) {
440  ngx_process_get_status();
441  }
442 
443  ngx_set_errno(err);
444 }
445 
446 
447 static void
448 ngx_process_get_status(void)
449 {
450  int status;
451  char *process;
452  ngx_pid_t pid;
453  ngx_err_t err;
454  ngx_int_t i;
455  ngx_uint_t one;
456 
457  one = 0;
458 
459  for ( ;; ) {
460  pid = waitpid(-1, &status, WNOHANG);
461 
462  if (pid == 0) {
463  return;
464  }
465 
466  if (pid == -1) {
467  err = ngx_errno;
468 
469  if (err == NGX_EINTR) {
470  continue;
471  }
472 
473  if (err == NGX_ECHILD && one) {
474  return;
475  }
476 
477  /*
478  * Solaris always calls the signal handler for each exited process
479  * despite waitpid() may be already called for this process.
480  *
481  * When several processes exit at the same time FreeBSD may
482  * erroneously call the signal handler for exited process
483  * despite waitpid() may be already called for this process.
484  */
485 
486  if (err == NGX_ECHILD) {
488  "waitpid() failed");
489  return;
490  }
491 
493  "waitpid() failed");
494  return;
495  }
496 
497 
498  one = 1;
499  process = "unknown process";
500 
501  for (i = 0; i < ngx_last_process; i++) {
502  if (ngx_processes[i].pid == pid) {
503  ngx_processes[i].status = status;
504  ngx_processes[i].exited = 1;
505  process = ngx_processes[i].name;
506  break;
507  }
508  }
509 
510  if (WTERMSIG(status)) {
511 #ifdef WCOREDUMP
513  "%s %P exited on signal %d%s",
514  process, pid, WTERMSIG(status),
515  WCOREDUMP(status) ? " (core dumped)" : "");
516 #else
518  "%s %P exited on signal %d",
519  process, pid, WTERMSIG(status));
520 #endif
521 
522  } else {
524  "%s %P exited with code %d",
525  process, pid, WEXITSTATUS(status));
526  }
527 
528  if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) {
530  "%s %P exited with fatal code %d "
531  "and cannot be respawned",
532  process, pid, WEXITSTATUS(status));
533  ngx_processes[i].respawn = 0;
534  }
535 
536  ngx_unlock_mutexes(pid);
537  }
538 }
539 
540 
541 static void
542 ngx_unlock_mutexes(ngx_pid_t pid)
543 {
544  ngx_uint_t i;
545  ngx_shm_zone_t *shm_zone;
546  ngx_list_part_t *part;
547  ngx_slab_pool_t *sp;
548 
549  /*
550  * unlock the accept mutex if the abnormally exited process
551  * held it
552  */
553 
554  if (ngx_accept_mutex_ptr) {
556  }
557 
558  /*
559  * unlock shared memory mutexes if held by the abnormally exited
560  * process
561  */
562 
564  shm_zone = part->elts;
565 
566  for (i = 0; /* void */ ; i++) {
567 
568  if (i >= part->nelts) {
569  if (part->next == NULL) {
570  break;
571  }
572  part = part->next;
573  shm_zone = part->elts;
574  i = 0;
575  }
576 
577  sp = (ngx_slab_pool_t *) shm_zone[i].shm.addr;
578 
579  if (ngx_shmtx_force_unlock(&sp->mutex, pid)) {
581  "shared memory zone \"%V\" was locked by %P",
582  &shm_zone[i].shm.name, pid);
583  }
584  }
585 }
586 
587 
588 void
590 {
591  ngx_core_conf_t *ccf;
592 
595 
596  switch (ccf->debug_points) {
597 
599  raise(SIGSTOP);
600  break;
601 
603  ngx_abort();
604  }
605 }
606 
607 
608 ngx_int_t
610 {
611  ngx_signal_t *sig;
612 
613  for (sig = signals; sig->signo != 0; sig++) {
614  if (ngx_strcmp(name, sig->name) == 0) {
615  if (kill(pid, sig->signo) != -1) {
616  return 0;
617  }
618 
620  "kill(%P, %d) failed", pid, sig->signo);
621  }
622  }
623 
624  return 1;
625 }