NGX 信号处理流程

子车新立
2023-12-01

int ngx_cdecl
main(int argc, char *const *argv)
{
    ....
#if !(NGX_WIN32)

    if (ngx_init_signals(cycle->log) != NGX_OK) { // 服务器启动时进行初始化信号处理
        return 1;
    }

    if (!ngx_inherited && ccf->daemon) {
        if (ngx_daemon(cycle->log) != NGX_OK) {
            return 1;
        }

        ngx_daemonized = 1;
    }

    if (ngx_inherited) {
        ngx_daemonized = 1;
    }

#endif
    ......
    
    // 单进程服务器
    if (ngx_process == NGX_PROCESS_SINGLE) {
        ngx_single_process_cycle(cycle);

    } else {
        ngx_master_process_cycle(cycle);
    }

    return 0;
}
下来再看看ngx_init_signals函数实现之前先看看结构
typedef struct {
    int     signo;       		// 信号值
    char   *signame;	// 信号名字
    char   *name;		// 服务器响应信号操作的名字
    void  (*handler)(int signo);// 信号处理函数
} ngx_signal_t;
再看看全局变量ngx_signal_t  signals[] 所有的信号及其处理函数
ngx_signal_t  signals[] = {
    { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
      "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
      "reload",
      ngx_signal_handler },


    { ngx_signal_value(NGX_REOPEN_SIGNAL),
      "SIG" ngx_value(NGX_REOPEN_SIGNAL),
      "reopen",
      ngx_signal_handler },


    { ngx_signal_value(NGX_NOACCEPT_SIGNAL),
      "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
      "",
      ngx_signal_handler },


    { ngx_signal_value(NGX_TERMINATE_SIGNAL),
      "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
      "stop",
      ngx_signal_handler },


    { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
      "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
      "quit",
      ngx_signal_handler },


    { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),
      "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
      "",
      ngx_signal_handler },


    { SIGALRM, "SIGALRM", "", ngx_signal_handler },


    { SIGINT, "SIGINT", "", ngx_signal_handler },


    { SIGIO, "SIGIO", "", ngx_signal_handler },


    { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },


    { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN },


    { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN },


    { 0, NULL, "", NULL }
};
ngx_init_signals函数是将上面初始化的信号注册到系统中去

ngx_int_t
ngx_init_signals(ngx_log_t *log)
{
    ngx_signal_t      *sig;
    struct sigaction   sa;

    // 将所有信号注册到系统中
    for (sig = signals; sig->signo != 0; sig++) {
        ngx_memzero(&sa, sizeof(struct sigaction));
	// 信号处理函数
        sa.sa_handler = sig->handler;
	//sa_mask 用来设置在处理该信号时暂时将sa_mask 指定的信号搁置
        sigemptyset(&sa.sa_mask);
        if (sigaction(sig->signo, &sa, NULL) == -1) {
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                          "sigaction(%s) failed", sig->signame);
            return NGX_ERROR;
        }
    }


    return NGX_OK;
}

下面看看重头函数ngx_signal_handler实现这里解释一个信号处理,其他类似

void
ngx_signal_handler(int signo)
{
    char            *action;
    ngx_int_t        ignore;
    ngx_err_t        err;
    ngx_signal_t    *sig;


    ignore = 0;


    err = ngx_errno;

    // 检查信号值是否是注册信号
    for (sig = signals; sig->signo != 0; sig++) {
        if (sig->signo == signo) {
	    // 确认找到
            break;
        }
    }


    ngx_time_sigsafe_update();


    action = "";

    // 进程类型
    switch (ngx_process) {

    // 主进程或单进程
    case NGX_PROCESS_MASTER:
    case NGX_PROCESS_SINGLE:
        switch (signo) {


        case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
            ngx_quit = 1;
            action = ", shutting down";
            break;

        case ngx_signal_value(NGX_TERMINATE_SIGNAL):
        case SIGINT:// 系统受到 SIGINT,系统调用此信号处理函数,设置全局变量ngx_terminate值置1 下面的分支类似
            ngx_terminate = 1;
                  action = ", exiting";
            break;


        case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
            if (ngx_daemonized) {
                ngx_noaccept = 1;
                action = ", stop accepting connections";
            }
            break;


        case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
            ngx_reconfigure = 1;
            action = ", reconfiguring";
            break;


        case ngx_signal_value(NGX_REOPEN_SIGNAL):
            ngx_reopen = 1;
            action = ", reopening logs";
            break;


        case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
            if (getppid() > 1 || ngx_new_binary > 0) {


                /*
                 * Ignore the signal in the new binary if its parent is
                 * not the init process, i.e. the old binary's process
                 * is still running.  Or ignore the signal in the old binary's
                 * process if the new binary's process is already running.
                 */


                action = ", ignoring";
                ignore = 1;
                break;
            }


            ngx_change_binary = 1;
            action = ", changing binary";
            break;


        case SIGALRM:
            ngx_sigalrm = 1;
            break;


        case SIGIO:
            ngx_sigio = 1;
            break;


        case SIGCHLD:
            ngx_reap = 1;
            break;
        }


        break;

// 工作进程...
    case NGX_PROCESS_WORKER:
    case NGX_PROCESS_HELPER:
        switch (signo) {


        case ngx_signal_value(NGX_NOACCEPT_SIGNAL):
            if (!ngx_daemonized) {
                break;
            }
            ngx_debug_quit = 1;
        case ngx_signal_value(NGX_SHUTDOWN_SIGNAL):
            ngx_quit = 1;
            action = ", shutting down";
            break;


        case ngx_signal_value(NGX_TERMINATE_SIGNAL):
        case SIGINT:
            ngx_terminate = 1;
            action = ", exiting";
            break;


        case ngx_signal_value(NGX_REOPEN_SIGNAL):
            ngx_reopen = 1;
            action = ", reopening logs";
            break;


        case ngx_signal_value(NGX_RECONFIGURE_SIGNAL):
        case ngx_signal_value(NGX_CHANGEBIN_SIGNAL):
        case SIGIO:
            action = ", ignoring";
            break;
        }


        break;
    }


    ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,
                  "signal %d (%s) received%s", signo, sig->signame, action);


    if (ignore) {
        ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0,
                      "the changing binary signal is ignored: "
                      "you should shutdown or terminate "
                      "before either old or new binary's process");
    }


    if (signo == SIGCHLD) {
        ngx_process_get_status();
    }


    ngx_set_errno(err);
}

这里处理完毕了吗,还没有以服务器模式为NGX_PROCESS_MASTER为例,ngx_master_process_cycle函数中
创建完工作进程和管理进程后,主进程进入循环,并停滞在
        // 等待信号唤醒
        sigsuspend(&set);// 注意set是一个空信号集
进程收到信号并处理信号函数后,此函数返回,
程序进入下面执行ngx_terminate在信号处理函数中被置1
        if (ngx_terminate) {
            if (delay == 0) {
                delay = 50;
            }


            if (sigio) {
                sigio--;
                continue;
            }


            sigio = ccf->worker_processes + 2 /* cache processes */;


            if (delay > 1000) {
                ngx_signal_worker_processes(cycle, SIGKILL);
            } else {
		// 向工作线程发送NGX_TERMINATE_SIGNAL信号

                ngx_signal_worker_processes(cycle,
                                       ngx_signal_value(NGX_TERMINATE_SIGNAL));
            }


            continue;
        }
这就是信号处理流程,那么有一个问题,信号如何被发送的?



 类似资料: