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>