nginx源码分析—信号初始化和使用

本文分析了Nginx中的信号处理机制,包括信号初始化、处理函数及关键变量的作用。通过对ngx_init_signals()函数和signals数组的解析,揭示了Nginx如何通过不同信号控制其启动、停止和升级过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. ngx_init_signals()函数
    1. ngx_signal_t结构
    2. signals数组
    3. sigaction结构
  2. ngx_signal_handler()函数
  3. ngx_master_process_cycle()数
  4. 小结

1序

本文主要分析nginx信号初始化及其处理,信号处理用于master进程的接收reload,stop等操作。

2.1 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;
        sigemptyset(&sa.sa_mask);//清空此信号集
        if (sigaction(sig->signo, &sa, NULL) == -1) {//设置相关singl的action
            //signaction,则可以设置比较多的消息。尤其是在信号处理函数过程中接受信号,进行何种处理
            //替代signal 来设计的较稳定的信号处理
#if (NGX_VALGRIND)
            ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
                          "sigaction(%s) failed, ignored", sig->signame);
#else
            ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
                          "sigaction(%s) failed", sig->signame);
            return NGX_ERROR;
#endif
        }
    }

    return NGX_OK;
}

2.2 ngx_signal_t结构

//Nginx服务器的启动、停止和升级都是通过信号控制的
typedef struct {
    int     signo;//信号的编号
    char   *signame;//信号的字符串表现形式,如"SIGIO"。
    char   *name;//信号的名称,如"stop"。
    void  (*handler)(int signo);//信号处理函数。
} ngx_signal_t;

当收到信号会先调用handler函数。

2.3 signals数组

ngx_signal_t  signals[] = {
    { ngx_signal_value(NGX_RECONFIGURE_SIGNAL),//RECONFIGURE信号,重新读取配置信息
      "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),//SIGHUP信号
      "reload",
      ngx_signal_handler },

    { ngx_signal_value(NGX_REOPEN_SIGNAL),
      "SIG" ngx_value(NGX_REOPEN_SIGNAL),//SIGHUP信号
      "reopen",
      ngx_signal_handler },

    { ngx_signal_value(NGX_NOACCEPT_SIGNAL),//NOACCEPT信号,工作进程不接受事件
      "SIG" ngx_value(NGX_NOACCEPT_SIGNAL),
      "",
      ngx_signal_handler },

    { ngx_signal_value(NGX_TERMINATE_SIGNAL),//TERMINATE信号,工作进程终止
      "SIG" ngx_value(NGX_TERMINATE_SIGNAL),
      "stop",
      ngx_signal_handler },

    { ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
      "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),//SHUTDOWN信号,结束网络通信
      "quit",
      ngx_signal_handler },

    { ngx_signal_value(NGX_CHANGEBIN_SIGNAL),//CHANGEBIN信号,热升级Nginx运行程序
      "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL),
      "",
      ngx_signal_handler },

    //以下是常见的系统信号
    { SIGALRM, "SIGALRM", "", ngx_signal_handler },

    { SIGINT, "SIGINT", "", ngx_signal_handler },//来自键盘的中断信号 ( ctrl + c )

    { SIGIO, "SIGIO", "", ngx_signal_handler },//表示 Io 有数据可供读取

    { SIGCHLD, "SIGCHLD", "", ngx_signal_handler },//标识子进程停止或结束的信号

    { SIGSYS, "SIGSYS, SIG_IGN", "", SIG_IGN },
//在linux下写socket的程序的时候,如果尝试send到一个disconnected socket上,就会让底层抛出一个SIGPIPE信号。
//这个信号的缺省处理方法是退出进程
    { SIGPIPE, "SIGPIPE, SIG_IGN", "", SIG_IGN },//无效系统调用

    { 0, NULL, "", NULL }
};

3. ngx_signal_handler()函数

主要是赋值ngx_quit 、ngx_terminate 、ngx_noaccept 等变量在ngx_master_process_cycle()中做判断

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:
            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:

4. ngx_master_process_cycle()数

sigprocmask(SIG_BLOCK, &set, NULL) //将SIGINT信号阻塞
sigsuspend()//等待信号,知道有信号才苏醒,在ngx_signal_handler响应处理之后

void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
    char              *title;
    u_char            *p;
    size_t             size;
    ngx_int_t          i;
    ngx_uint_t         n, sigio;
    sigset_t           set;
    struct itimerval   itv;
    ngx_uint_t         live;
    ngx_msec_t         delay;
    ngx_listening_t   *ls;
    ngx_core_conf_t   *ccf;

    sigemptyset(&set);
    sigaddset(&set, SIGCHLD);
    sigaddset(&set, SIGALRM);
    sigaddset(&set, SIGIO);
    sigaddset(&set, SIGINT);
    sigaddset(&set, ngx_signal_value(NGX_RECONFIGURE_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_REOPEN_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_NOACCEPT_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_TERMINATE_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_SHUTDOWN_SIGNAL));
    sigaddset(&set, ngx_signal_value(NGX_CHANGEBIN_SIGNAL));

    //将SIGINT信号阻塞,同时保存当前信号集
    //记住是屏蔽,不是消除,就是来了信号,如果当前是block,则先不传递给当前进程,但是一旦unblock,则信号会重新到达
    if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed");
    }

    sigemptyset(&set);
    ........
    ........
    for ( ;; ) {

        sigsuspend(&set); //用于在接收到某个信号之前,临时用mask替换进程的信号掩码,并暂停进程执行,直到收到信号为止

        ngx_time_update();

       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_signal_worker_processes(cycle,
                                       ngx_signal_value(NGX_TERMINATE_SIGNAL));
            }

            continue;
        }

        if (ngx_quit) {
            ngx_signal_worker_processes(cycle,
                                        ngx_signal_value(NGX_SHUTDOWN_SIGNAL));

            ls = cycle->listening.elts;
            for (n = 0; n < cycle->listening.nelts; n++) {
                if (ngx_close_socket(ls[n].fd) == -1) {
                    ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_socket_errno,
                                  ngx_close_socket_n " %V failed",
                                  &ls[n].addr_text);
                }
            }
            cycle->listening.nelts = 0;

            continue;
        }

5. 小结

再接再厉
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值