Annotation of embedaddon/nginx/src/os/unix/ngx_process.c, revision 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>