vaynedu / nginx-1.16.0

学习nginx架构设计与实现,翻译nginx的源码,写nginx的测试代码, 在issue中记录nginx的精妙设计及其常见问题https://github.com/vaynedu/nginx-1.16.0/issues 。 myexercise内存池、哈希表、链表、md5、crc测试代码,mymodule中有hello自定义模块代码。通过nginx将自己整个知识体系连接起来
https://github.com/vaynedu/nginx-1.16.0/issues
BSD 2-Clause "Simplified" License
12 stars 2 forks source link

nginx创建子进程的过程中,被信号打断了,此时master会如何处理,nginx会不会有异常? #49

Open vaynedu opened 5 years ago

vaynedu commented 5 years ago

信号还有好几个问题待整理 todo

比如,刚fork出worker,worker因为异常推出,master收到SIGCHLD信号,如果执行信号处理函数会导致master的进程管理结构错误初始化。

nginx创建子进程的过程分为: 1)fork出子进程。 2)初始化子进程控制结构。

1.通过sigprocmask先阻塞设置的信号,然后置空set,后面取消阻塞的时候会用到。

void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
    ...
    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));

    if (sigprocmask(SIG_BLOCK, &set, NULL) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed");
    }

    sigemptyset(&set);

    ...

2.“临界区”执行fork,设置全局初始化,防止信号中断导致出错。这里主要是在ngx_worker_process_init中执行的。

void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
    ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module);

    ngx_start_worker_processes(cycle, ccf->worker_processes,
                               NGX_PROCESS_RESPAWN);
    ngx_start_cache_manager_processes(cycle, 0);

}

static void
ngx_start_worker_processes(ngx_cycle_t *cycle, ngx_int_t n, ngx_int_t type)
{

    for (i = 0; i < n; i++) {
        ngx_spawn_process(cycle, ngx_worker_process_cycle,
                          (void *) (intptr_t) i, "worker process", type);
    }
}

static void
ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
{
   ngx_worker_process_init(cycle, worker);
}

非常重要: nginx的worker进程初始化已经完成,直接结束信号阻塞,表示可以接受信号了
static void
ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
{
   ...
    sigemptyset(&set);

    if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) {
        ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
                      "sigprocmask() failed");
    }

   ...
}

3.通过sigsuspend取消阻塞信号,等到信号到来


void
ngx_master_process_cycle(ngx_cycle_t *cycle)
{
   sigsuspend(&set);
}