Annotation of embedaddon/nginx/src/os/unix/ngx_process.c, revision 1.1.1.1
1.1 misho 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:
29: int ngx_argc;
30: char **ngx_argv;
31: char **ngx_os_argv;
32:
33: ngx_int_t ngx_process_slot;
34: ngx_socket_t ngx_channel;
35: ngx_int_t ngx_last_process;
36: ngx_process_t ngx_processes[NGX_MAX_PROCESSES];
37:
38:
39: ngx_signal_t signals[] = {
40: { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
41: "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
42: "reload",
43: ngx_signal_handler },
44:
45: { ngx_signal_value(NGX_REOPEN_SIGNAL),
46: "SIG" ngx_value(NGX_REOPEN_SIGNAL),
47: "reopen",
48: ngx_signal_handler },
49:
50: { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
51: "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
52: "",
53: ngx_signal_handler },
54:
55: { ngx_signal_value(NGX_TERMINATE_SIGNAL),
56: "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
57: "stop",
58: ngx_signal_handler },
59:
60: { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
61: "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
62: "quit",
63: ngx_signal_handler },
64:
65: { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
66: "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
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:
86: ngx_pid_t
87: ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data,
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",
107: NGX_MAX_PROCESSES);
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: {
119: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
120: "socketpair() failed while spawning \"%s\"", name);
121: return NGX_INVALID_PID;
122: }
123:
124: ngx_log_debug2(NGX_LOG_DEBUG_CORE, cycle->log, 0,
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) {
130: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
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) {
138: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
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) {
147: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
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) {
154: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
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) {
161: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
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) {
169: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
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:
191: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
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:
221: case NGX_PROCESS_NORESPAWN:
222: ngx_processes[s].respawn = 0;
223: ngx_processes[s].just_spawn = 0;
224: ngx_processes[s].detached = 0;
225: break;
226:
227: case NGX_PROCESS_JUST_SPAWN:
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:
239: case NGX_PROCESS_JUST_RESPAWN:
240: ngx_processes[s].respawn = 1;
241: ngx_processes[s].just_spawn = 1;
242: ngx_processes[s].detached = 0;
243: break;
244:
245: case NGX_PROCESS_DETACHED:
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) {
253: ngx_last_process++;
254: }
255:
256: return pid;
257: }
258:
259:
260: ngx_pid_t
261: ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx)
262: {
263: return ngx_spawn_process(cycle, ngx_execute_proc, ctx, ctx->name,
264: NGX_PROCESS_DETACHED);
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) {
274: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
275: "execve() failed while executing %s \"%s\"",
276: ctx->name, ctx->path);
277: }
278:
279: exit(1);
280: }
281:
282:
283: ngx_int_t
284: ngx_init_signals(ngx_log_t *log)
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) {
294: ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
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:
322: ngx_time_sigsafe_update();
323:
324: action = "";
325:
326: switch (ngx_process) {
327:
328: case NGX_PROCESS_MASTER:
329: case NGX_PROCESS_SINGLE:
330: switch (signo) {
331:
332: case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
333: ngx_quit = 1;
334: action = ", shutting down";
335: break;
336:
337: case ngx_signal_value(NGX_TERMINATE_SIGNAL):
338: case SIGINT:
339: ngx_terminate = 1;
340: action = ", exiting";
341: break;
342:
343: case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
344: if (ngx_daemonized) {
345: ngx_noaccept = 1;
346: action = ", stop accepting connections";
347: }
348: break;
349:
350: case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
351: ngx_reconfigure = 1;
352: action = ", reconfiguring";
353: break;
354:
355: case ngx_signal_value(NGX_REOPEN_SIGNAL):
356: ngx_reopen = 1;
357: action = ", reopening logs";
358: break;
359:
360: case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
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:
398: case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
399: if (!ngx_daemonized) {
400: break;
401: }
402: ngx_debug_quit = 1;
403: case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
404: ngx_quit = 1;
405: action = ", shutting down";
406: break;
407:
408: case ngx_signal_value(NGX_TERMINATE_SIGNAL):
409: case SIGINT:
410: ngx_terminate = 1;
411: action = ", exiting";
412: break;
413:
414: case ngx_signal_value(NGX_REOPEN_SIGNAL):
415: ngx_reopen = 1;
416: action = ", reopening logs";
417: break;
418:
419: case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
420: case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
421: case SIGIO:
422: action = ", ignoring";
423: break;
424: }
425:
426: break;
427: }
428:
429: ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
430: "signal %d (%s) received%s", signo, sig->signame, action);
431:
432: if (ignore) {
433: ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0,
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) {
487: ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, err,
488: "waitpid() failed");
489: return;
490: }
491:
492: ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
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
512: ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
513: "%s %P exited on signal %d%s",
514: process, pid, WTERMSIG(status),
515: WCOREDUMP(status) ? " (core dumped)" : "");
516: #else
517: ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
518: "%s %P exited on signal %d",
519: process, pid, WTERMSIG(status));
520: #endif
521:
522: } else {
523: ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
524: "%s %P exited with code %d",
525: process, pid, WEXITSTATUS(status));
526: }
527:
528: if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) {
529: ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
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) {
555: (void) ngx_shmtx_force_unlock(&ngx_accept_mutex, pid);
556: }
557:
558: /*
559: * unlock shared memory mutexes if held by the abnormally exited
560: * process
561: */
562:
563: part = (ngx_list_part_t *) &ngx_cycle->shared_memory.part;
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)) {
580: ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
581: "shared memory zone \"%V\" was locked by %P",
582: &shm_zone[i].shm.name, pid);
583: }
584: }
585: }
586:
587:
588: void
589: ngx_debug_point(void)
590: {
591: ngx_core_conf_t *ccf;
592:
593: ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
594: ngx_core_module);
595:
596: switch (ccf->debug_points) {
597:
598: case NGX_DEBUG_POINTS_STOP:
599: raise(SIGSTOP);
600: break;
601:
602: case NGX_DEBUG_POINTS_ABORT:
603: ngx_abort();
604: }
605: }
606:
607:
608: ngx_int_t
609: ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_int_t pid)
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:
619: ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
620: "kill(%P, %d) failed", pid, sig->signo);
621: }
622: }
623:
624: return 1;
625: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>