Nginx进程启动分析

  worker子进程的执行循环的函数是ngx_worker_process_cycle (src/os/unix/ngx_process_cycle.c)。

  其中,捕获事件、分发事件的函数是ngx_process_events_and_timers(cycle);

static void
ngx_worker_process_cycle(ngx_cycle_t *cycle, void *data)
{
ngx_int_t worker = (intptr_t) data; ngx_uint_t i;
ngx_connection_t *c; ngx_process = NGX_PROCESS_WORKER;//将全局变量ngx_process设置为worker进程
ngx_worker_process_init(cycle, worker);//对worker进程进行初始化操作 ngx_setproctitle("worker process"); #if (NGX_THREADS)
{
ngx_int_t n;
ngx_err_t err;
ngx_core_conf_t *ccf; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (ngx_threads_n) {
if (ngx_init_threads(ngx_threads_n, ccf->thread_stack_size, cycle)
== NGX_ERROR)
{
/* fatal */
exit();
} err = ngx_thread_key_create(&ngx_core_tls_key);
if (err != ) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, err,
ngx_thread_key_create_n " failed");
/* fatal */
exit();
} for (n = ; n < ngx_threads_n; n++) { ngx_threads[n].cv = ngx_cond_init(cycle->log); if (ngx_threads[n].cv == NULL) {
/* fatal */
exit();
} if (ngx_create_thread((ngx_tid_t *) &ngx_threads[n].tid,
ngx_worker_thread_cycle,
(void *) &ngx_threads[n], cycle->log)
!= )
{
/* fatal */
exit();
}
}
}
}
#endif for ( ;; ) {
//ngx_exiting是在worker进程收到SIGQUIT信号后设置的
if (ngx_exiting) { c = cycle->connections;
//退出前,处理每个连接上的事件
for (i = ; i < cycle->connection_n; i++) { /* THREAD: lock */ if (c[i].fd != - && c[i].idle) {
c[i].close = ;
c[i].read->handler(c[i].read);
}
} if (ngx_event_timer_rbtree.root == ngx_event_timer_rbtree.sentinel)
{
ngx_log_error(NGX_LOG_NOTICE, cycle->log, , "exiting"); ngx_worker_process_exit(cycle);
}
} ngx_log_debug0(NGX_LOG_DEBUG_EVENT, cycle->log, , "worker cycle");
//处理各种事件,主要的处理函数!!!
ngx_process_events_and_timers(cycle);
//worker进程收到了SIGINT信号
if (ngx_terminate) {
ngx_log_error(NGX_LOG_NOTICE, cycle->log, , "exiting"); ngx_worker_process_exit(cycle);
}
//进程收到了SIGQUIT信号,ngx_exiting设置为1,同时关闭监听套接口
if (ngx_quit) {
ngx_quit = ;
ngx_log_error(NGX_LOG_NOTICE, cycle->log, ,
"gracefully shutting down");
ngx_setproctitle("worker process is shutting down"); if (!ngx_exiting) {
ngx_close_listening_sockets(cycle);
ngx_exiting = ;
}
}
//worker进程收到了SIGUSR1信号
if (ngx_reopen) {
ngx_reopen = ;
ngx_log_error(NGX_LOG_NOTICE, cycle->log, , "reopening logs");
ngx_reopen_files(cycle, -);
}
}
}

  其中初始化函数分析,如下:

static void
ngx_worker_process_init(ngx_cycle_t *cycle, ngx_int_t worker)
{
sigset_t set;
uint64_t cpu_affinity;
ngx_int_t n;
ngx_uint_t i;
struct rlimit rlmt;
ngx_core_conf_t *ccf;
ngx_listening_t *ls;
  //配置一些环境变量
if (ngx_set_environment(cycle, NULL) == NULL) {
/* fatal */
exit();
}
   //获取配置信息
ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (worker >= && ccf->priority != ) {
if (setpriority(PRIO_PROCESS, , ccf->priority) == -) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"setpriority(%d) failed", ccf->priority);
}
}
if (ccf->rlimit_nofile != NGX_CONF_UNSET) {
rlmt.rlim_cur = (rlim_t) ccf->rlimit_nofile;
rlmt.rlim_max = (rlim_t) ccf->rlimit_nofile; if (setrlimit(RLIMIT_NOFILE, &rlmt) == -) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"setrlimit(RLIMIT_NOFILE, %i) failed",
ccf->rlimit_nofile);
}
}
if (ccf->rlimit_core != NGX_CONF_UNSET) {
rlmt.rlim_cur = (rlim_t) ccf->rlimit_core;
rlmt.rlim_max = (rlim_t) ccf->rlimit_core;
if (setrlimit(RLIMIT_CORE, &rlmt) == -) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"setrlimit(RLIMIT_CORE, %O) failed",
ccf->rlimit_core);
}
}
#ifdef RLIMIT_SIGPENDING
if (ccf->rlimit_sigpending != NGX_CONF_UNSET) {
rlmt.rlim_cur = (rlim_t) ccf->rlimit_sigpending;
rlmt.rlim_max = (rlim_t) ccf->rlimit_sigpending; if (setrlimit(RLIMIT_SIGPENDING, &rlmt) == -) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"setrlimit(RLIMIT_SIGPENDING, %i) failed",
ccf->rlimit_sigpending);
}
}
#endif
//设置UID GROUPUID
if (geteuid() == ) {
if (setgid(ccf->group) == -) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
"setgid(%d) failed", ccf->group);
/* fatal */
exit();
}
if (initgroups(ccf->username, ccf->group) == -) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
"initgroups(%s, %d) failed",
ccf->username, ccf->group);
}
if (setuid(ccf->user) == -) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
"setuid(%d) failed", ccf->user);
/* fatal */
exit();
}
}
//设置CPU亲和性
if (worker >= ) {
cpu_affinity = ngx_get_cpu_affinity(worker); if (cpu_affinity) {
ngx_setaffinity(cpu_affinity, cycle->log);
}
}
#if (NGX_HAVE_PR_SET_DUMPABLE) /* allow coredump after setuid() in Linux 2.4.x */ if (prctl(PR_SET_DUMPABLE, , , , ) == -) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"prctl(PR_SET_DUMPABLE) failed");
}
#endif
//切换工作目录
if (ccf->working_directory.len) {
if (chdir((char *) ccf->working_directory.data) == -) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"chdir(\"%s\") failed", ccf->working_directory.data);
/* fatal */
exit();
}
}
sigemptyset(&set);
//清除所有信号
if (sigprocmask(SIG_SETMASK, &set, NULL) == -) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"sigprocmask() failed");
} /*
* disable deleting previous events for the listening sockets because
* in the worker processes there are no events at all at this point
*/
ls = cycle->listening.elts;
  //清除监听socket上以前的事件 
for (i = ; i < cycle->listening.nelts; i++) {
ls[i].previous = NULL;
}
  //对所有模块进行初始化
for (i = ; ngx_modules[i]; i++) {
if (ngx_modules[i]->init_process) {
if (ngx_modules[i]->init_process(cycle) == NGX_ERROR) {
/* fatal */
exit();
}
}
}
//将其他进程的channel[1]关闭,自己的channel[0]关闭
for (n = ; n < ngx_last_process; n++) {
if (ngx_processes[n].pid == -) {
continue;
}
if (n == ngx_process_slot) {
continue;
}
if (ngx_processes[n].channel[] == -) {
continue;
}
if (close(ngx_processes[n].channel[]) == -) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"close() channel failed");
}
} if (close(ngx_processes[ngx_process_slot].channel[]) == -) {
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"close() channel failed");
}
#if 0
ngx_last_process = ;
#endif
  //给ngx_channel注册一个读事件处理函数
if (ngx_add_channel_event(cycle, ngx_channel, NGX_READ_EVENT,
ngx_channel_handler)== NGX_ERROR){
/* fatal */
exit();
}
}

  

Nginx学习笔记(八) Nginx进程启动分析的更多相关文章

  1. nginx 学习笔记(2) nginx新手入门

    这篇手册简单介绍了nginx,并提供了一些可以操作的简单的工作.前提是nginx已经被安装到你的服务器上.如果没有安装,请阅读上篇:nginx 学习笔记(1) nginx安装.这篇手册主要内容:1. ...

  2. nginx 学习笔记(1) nginx安装

    1.nginx安装 根据操作系统的不同,nginx的安装方式也不相同. 1.1 对linux系统来说,nginx.org提供了nginx安装包.http://nginx.org/en/linux_pa ...

  3. Nginx学习笔记六Nginx的模块开发

    1.Nginx配置文件主要组成:main(全局配置)这部分的指令将影响其他所有部分.server(虚拟主机配置)这部分指令主要用于指定虚拟主机域名,IP和端口.upstream(主要为反向代理,负载均 ...

  4. nginx 学习笔记(5) nginx调试日志

    为启动一个调试日志,nginx需要在构建时配置城支持调试模式. ./configure --with-debug ... 而且调试级别应该使用err_log指令来设置: err_log /path/t ...

  5. nginx 学习笔记(3) nginx管理

    nginx可以通过向其发送信号来进行管理.默认情况下主进程的进程ID写到文件/usr/local/nginx/logs/nginx.pid中.当然也可以在配置文件中自定义该pid文件,自定义使用pid ...

  6. 七、Nginx学习笔记七Nginx的Web缓存服务

    user www; worker_processes 1; error_log /usr/local/nginx/logs/error.log crit; pid /usr/local/nginx/l ...

  7. nginx学习笔记(7)Nginx如何处理一个请求---转载

    如何防止处理未定义主机名的请求基于域名和IP混合的虚拟主机一个简单PHP站点配置 基于名字的虚拟主机 Nginx首先选定由哪一个虚拟主机来处理请求.让我们从一个简单的配置(其中全部3个虚拟主机都在端口 ...

  8. nginx 学习笔记(6) nginx配置文件中的度量单位

    容量大小可以用比特(byte),千比特(kilobyte,后缀k或者K)或者兆(megabytes,后缀m或者M),例如:“1024”,“8k”,“1m”. 时间间隔可以用毫秒(millisecond ...

  9. Nginx学习笔记4 源码分析

    Nginx学习笔记(四) 源码分析 源码分析 在茫茫的源码中,看到了几个好像挺熟悉的名字(socket/UDP/shmem).那就来看看这个文件吧!从简单的开始~~~ src/os/unix/Ngx_ ...

随机推荐

  1. jafka的zk数据

    查看topics: ls /brokers/topics [mytopic] 查看topic所在的broker,下面例子,mytopic在broker 0 中管理. ls /brokers/topic ...

  2. TortoiseSVN文件夹及文件状态图标不显示解决方法

    win8 64位系统,原本svn是好用的,安装了klive金山快盘后,svn图标都不显示了.最后通过修改注册表解决: win+R调出运行框,输入regedit,打开注册表编辑器. HKEY_LOCAL ...

  3. SQL SERVER连接、合并查询

    ----创建测试表MyStudentInfoCREATE table MyStudentInfo(  Id int not null primary key,  Name varchar(16),  ...

  4. 循序渐进Python3(六) -- 初识内置变量、反射、递归

    #python用下划线作为变量前缀和后缀指定特殊变量.稍后我们会发现,   #对于程序来说,其中的有些变量是非常有用的,而其他的则是未知或者无用的.   #我们总结一下Python中下划线的特殊用法  ...

  5. linux 的 samba 实现共享文件夹

    samba Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件,由服务器及客户端程序构成. service XXX start 失败多是权限不够,使用管理员权限尝试

  6. Linux 中write()函数的出错情况及处理

    write函数首先将进程需要发送的数据先放在进程缓冲区中,然后向socket的发送缓冲区进行拷贝,在此,可能出现这样情况,即当进程缓冲区中的数据量大于此时发送缓冲区中所能接受的数据量时,若此时处于阻塞 ...

  7. to_char 详解

    对TO_CHAR的讨论可以分为从两种类型的数据到字符的转换:DATE和NUMBER. TO_CHAR函数返回VARCHAR2数据类型的值. 1. NUMBER TO CHAR 语法: TO_CHAR( ...

  8. ffffffuzzzzzzzzzzzzing

    为了克服现有 Fuzzing 技术对目标程序缺乏理解.测试完全随机且盲目的缺点,提出了新方法:基于动态符号执行的智能测试技术. 先通过静态分析获得危险点,然后通过符号执行收集路径条件,最后利用约束求解 ...

  9. Selenium2+python自动化6-八种元素元素定位(Firebug和firepath)

    前言 自动化只要掌握四步操作:获取元素,操作元素,获取返回结果,断言(返回结果与期望结果是否一致),最后自动出测试报告.本篇主要讲如何用firefox辅助工具进行元素定位. 元素定位在这四个环节中是至 ...

  10. each处理json数据

    eg:给传进来的ID中当其对应的值为true时,即给对应的ID标签添加一个class 名为  focus,如: var obj = { id01:'true', id02:'flase', id03: ...