ngx_pid_t
ngx_execute( ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx )
{
return ngx_spawn_process( cycle, ngx_execute_proc, ctx, ctx->name,
NGX_PROCESS_DETACHED );
}
// execve 执行对应的exe文件
static void
ngx_execute_proc( ngx_cycle_t *cycle, void *data )
{
ngx_exec_ctx_t *ctx = data;
if ( execve( ctx->path, ctx->argv, ctx->envp ) == -1 )
{
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"execve() failed while executing %s \"%s\"",
ctx->name, ctx->path);
}
exit(1);
}
//根据信号和对应的处理函数的数组中设定的内容,来设定每个信号的处理函数
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 )
{
ngx_log_error( NGX_LOG_EMERG, log, ngx_errno,
"sigaction(%s) failed", sig->signame );
return NGX_ERROR;
}
}
return NGX_OK;
}
// 通用信号的处理函数, 更新全局变量的值,例如提醒woker进程和slave进程退出等
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_update( 0, 0 );
action = "";
// ngx_process 指定了当前是master 还是slave
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):
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):
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 ) // 是子进程退出的信号,则waitpid回收之
{
ngx_process_get_status();
}
ngx_set_errno(err);
}
static void
ngx_process_get_status(void)
{
int status;
char *process;
ngx_pid_t pid;
ngx_err_t err;
ngx_int_t i;
ngx_uint_t one;
one = 0;
// 无限循环,轮询等待所有的子进程
for ( ; ; )
{
pid = waitpid( -1, &status, WNOHANG ); // 不卡死,没有就返回
if ( pid == 0 ) // 没有等到
{
return;
}
if ( pid == -1 ) // 系统错误,如果是中断就接着循环
{
err = ngx_errno;
if ( err == NGX_EINTR )
{
continue;
}
// NGX_ECHILD ECHILD 错误表示 No children, 没有子进程,则直接返回
if ( err == NGX_ECHILD && one )
{
return;
}
// 其他错误,直接返回
#if (NGX_SOLARIS || NGX_FREEBSD)
/*
* Solaris always calls the signal handler for each exited process
* despite waitpid() may be already called for this process.
*
* When several processes exit at the same time FreeBSD may
* erroneously call the signal handler for exited process
* despite waitpid() may be already called for this process.
*/
if (err == NGX_ECHILD) {
ngx_log_error(NGX_LOG_INFO, ngx_cycle->log, errno,
"waitpid() failed");
return;
}
#endif
ngx_log_error( NGX_LOG_ALERT, ngx_cycle->log, errno,
"waitpid() failed" );
return;
}
// pid != -1
if ( ngx_accept_mutex_ptr )
{
/*
* unlock the accept mutex if the abnormally exited process
* held it 如果有 ngx_accept_mutex_ptr,则设置为0
*/
ngx_atomic_cmp_set( ngx_accept_mutex_ptr, pid, 0 );
}
one = 1;
process = "unknown process";
// 在子进程数组中找到该pid,更新该pid的状态
for ( i = 0; i < ngx_last_process; i++ )
{
if ( ngx_processes[i].pid == pid )
{
ngx_processes[i].status = status;
ngx_processes[i].exited = 1;
process = ngx_processes[i].name;
break;
}
}
// WTERMSIG(status ) 获得 使子进程终止的信号编号
if ( WTERMSIG( status ) )
{
#ifdef WCOREDUMP
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
"%s %P exited on signal %d%s",
process, pid, WTERMSIG(status),
WCOREDUMP(status) ? " (core dumped)" : "");
#else
ngx_log_error( NGX_LOG_ALERT, ngx_cycle->log, 0,
"%s %P exited on signal %d",
process, pid, WTERMSIG(status) );
#endif
}
else
{
ngx_log_error( NGX_LOG_NOTICE, ngx_cycle->log, 0,
"%s %P exited with code %d",
process, pid, WEXITSTATUS(status));
}
/*
1,在程序中,用exit来设置进程的退出值时,虽然该函数的参数类型为int型,
但再父进程中只能取到其值的低8位.所以用exit返回值时,高于255的值是没有意义的.
2,对于system函数,返回值是由两部分组成的,低8位值表示所执行的脚本在执行过程中所接收到的信号值,
其余的位表示的脚本exit退出时所设置的值,
即脚本内exit退出是的值的低8位,在system返回值的低9-16位.
如果子进程退出值为2,则打印下日志
*/
if ( WEXITSTATUS( status ) == 2 && ngx_processes[i].respawn )
{
ngx_log_error( NGX_LOG_ALERT, ngx_cycle->log, 0,
"%s %P exited with fatal code %d "
"and can not be respawn",
process, pid, WEXITSTATUS(status) );
ngx_processes[i].respawn = 0;
}
}
}
void
ngx_debug_point(void)
{
ngx_core_conf_t *ccf;
ccf = (ngx_core_conf_t *) ngx_get_conf(ngx_cycle->conf_ctx,
ngx_core_module);
switch (ccf->debug_points)
{
case NGX_DEBUG_POINTS_STOP:
raise(SIGSTOP);
break;
case NGX_DEBUG_POINTS_ABORT:
ngx_abort();
}
}
//在signals数组中找到参数name对应的信号整数,向参数pid发信号
ngx_int_t
ngx_os_signal_process( ngx_cycle_t *cycle, char *name, ngx_int_t pid )
{
ngx_signal_t *sig;
for ( sig = signals; sig->signo != 0; sig++ )
{
if ( ngx_strcmp( name, sig->name ) == 0 )
{
if ( kill( pid, sig->signo ) != -1 )
{
return 0;
}
ngx_log_error( NGX_LOG_ALERT, cycle->log, ngx_errno,
"kill(%P, %d) failed", pid, sig->signo );
}
}
return 1;
}