您的位置:首页 > 运维架构 > Nginx

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

2017-04-19 16:44 381 查看


ngx_init_signals()函数

ngx_signal_t结构

signals数组

sigaction结构

ngx_signal_handler()函数

ngx_master_process_cycle()数

小结

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. 小结

再接再厉
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: