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

10.Nginx启动流程之ngx_os_init

2017-10-26 18:43 274 查看
Nginx在启动流程中会调用ngx_os_init来初始化一些与操作系统有关的全局变量,不同操作系统下ngx_os_init的实现不同,在os/unix下我们看到Nginx为linux、freebsd、solaris等操作系统实现了对应的ngx_os_init函数。下面以linux操作系统进行讲解:

/* os/unix/ngx_posix.c */

ngx_int_t ngx_ncpu;
ngx_int_t ngx_max_sockets; // 用于记录可持有的最大套接字描述符数量
ngx_int_t ngx_inherited_nonblocking;
struct rlimit rlmt;

void ngx_signal_handler(int signo);

typedef struct {
int signo;
char *signame;
void (*handler)(int signo);
} ngx_signal_t;

ngx_signal_t signals[] = {
{ ngx_signal_value(NGX_RECONFIGURE_SIGNAL),
"SIG" ngx_value(NGX_RECONFIGURE_SIGNAL),
ngx_signal_handler },

{ ngx_signal_value(NGX_REOPEN_SIGNAL),
"SIG" ngx_value(NGX_REOPEN_SIGNAL),
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),
ngx_signal_handler },

{ ngx_signal_value(NGX_SHUTDOWN_SIGNAL),
"SIG" ngx_value(NGX_SHUTDOWN_SIGNAL),
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 },

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

{ 0, NULL, NULL }
};

/* Posix下进行系统相关初始化工作 */
ngx_int_t ngx_posix_init(ngx_log_t *log)
{
ngx_signal_t *sig;
struct sigaction sa;

// 调用unistd.h中getpagesize函数来获取内存分页大小, 单位为Byte
ngx_pagesize = getpagesize();

// ngx_ncpu简单置为1
if (ngx_ncpu == 0) {
ngx_ncpu = 1;
}

for (sig = signals; sig->signo != 0; sig++) {
// 遍历感兴趣的信号列表, 然后依次调用sigaction来为它们设置信号处理函数,
// 从上面可见大部分的信号都使用的ngx_signal_handler处理函数, 只有SIGPIPE是SIG_IGN, 也就是忽略此信号
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;
}
}

// 调用getrlimit来获取进程可以打开的最大文件数
// 我们可以使用ulimit -n命令来获取内核的默认值
if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) {
ngx_log_error(NGX_LOG_ALERT, log, errno,
"getrlimit(RLIMIT_NOFILE) failed)");
return NGX_ERROR;
}

ngx_max_sockets = rlmt.rlim_cur;

#if (HAVE_INHERITED_NONBLOCK)
ngx_inherited_nonblocking = 1;
#else
ngx_inherited_nonblocking = 0;
#endif

return NGX_OK;
}

/* os/unix/ngx_linux_init.c */

char ngx_linux_kern_ostype[50]; // 用于存放操作系统类型的字符数组全局变量
char ngx_linux_kern_osrelease[20]; // 用于存放内核版本的字符数组全局变量

int ngx_linux_rtsig_max; //

/* Linux下进行系统相关初始化工作 */
ngx_int_t ngx_os_init(ngx_log_t *log)
{
int name[2], len;

// 调用sysctl来获取操作系统类型
// 我在进行测试时, 如果ngx_linux_kern_ostype作为函数的局部变量, 那么调用会返回-1,
// 出错代码errno:14, 也就是"bad address"; 但是全局变量就不会, 很奇怪, 下面的获取内核版本也是这样
name[0] = CTL_KERN;
name[1] = KERN_OSTYPE;
len = sizeof(ngx_linux_kern_ostype);
if (sysctl(name, sizeof(name), ngx_linux_kern_ostype, &len, NULL, 0)
== -1) {
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
"sysctl(KERN_OSTYPE) failed");
return NGX_ERROR;
}

// 调用sysctl来获取内核版本
name[0] = CTL_KERN;
name[1] = KERN_OSRELEASE;
len = sizeof(ngx_linux_kern_osrelease);
if (sysctl(name, sizeof(name), ngx_linux_kern_osrelease, &len, NULL, 0)
== -1) {
ngx_log_error(NGX_LOG_ALERT, log, ngx_errno,
"sysctl(KERN_OSRELEASE) failed");
return NGX_ERROR;
}

// 调用sysctl来获取最大可排队的实时信号数量
// 在Linux下测试时会报错errno:20, "Not a
a7eb
directory",
// 不过这里出错后, 不像上面2个会返回NGX_ERROR, 而是直接置ngx_linux_rtsig_max为0
name[0] = CTL_KERN;
name[1] = KERN_RTSIGMAX;
len = sizeof(ngx_linux_rtsig_max);
if (sysctl(name, sizeof(name), &ngx_linux_rtsig_max, &len, NULL, 0) == -1) {
ngx_log_error(NGX_LOG_INFO, log, ngx_errno,
"sysctl(KERN_RTSIGMAX) failed");
ngx_linux_rtsig_max = 0;

}

// 调用Posix下系统相关初始化函数
return ngx_posix_init(log);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: