Nginx的主要函数调用关系分析
感觉上次写的:
http://blog.csdn.net/houjixin/article/details/59658022
这篇总结没把Nginx最主要的函数调用关系说清楚,因此,这次又重新组织了一下,以更简单的方式描述Nginx中如何从main函数开始,到创建各个进程,然后当有客户端连入进来时如何进行消息读取,这篇总结还未涉及到对业务流程的处理,例如对http请求的处理等。
Nginx支持epoll、select、kqueue等不同操作系统下的各种IO多路复用方式,本文以epoll为例分析Nginx是如何实现在一套处理流程中同时兼容各种不同的IO多路复用方式?关于IO多路复用相关的描述可参考:http://blog.csdn.net/houjixin/article/details/27662489。
几乎所有的服务器程序的工作模式都是:
l 初始化一些参数;
l 开启监听socket;
l 在主线程的死循环(一般都是死循环)中对监听socket和业务socket进行IO状态监控(IO多路复用),并对IO进行处理;
Nginx也不例外,它的主要工作模式是多进程模式,那么它的工作方式也是类似的。只不过是它的死循环被分散到了各个工作进程中。这里将按照一般服务器程序的工作顺序从main函数切入,逐步深入,并对各个流程进行分析。
mian函数入口的主流程调用关系如下图所示:
主流程的函数执行顺序
各函数的执行顺序说明:
(1)Main函数在文件:src\core\nginx.c中;
(2)核心数据结构 ngx_cycle_t(ngx_cycle_s)存储了Nginx的核心数据结构,包括内存池、日志等信息,nginx几乎所有的操作都围绕该数据结构进行;
(3)打开监听socket
函数调用关系
main=> ngx_init_cycle=>ngx_open_listening_sockets
(4)创建工作进程
在main函数的最后,调用了主循环处函数:ngx_master_process_cycle或ngx_single_process_cycle中,
(5)主处理流程:ngx_master_process_cycle,在该函数中又调用了ngx_start_worker_processes函数来创建并启动工作进程;
(6)在ngx_start_worker_processes中,在该函数中调用了ngx_spawn_process创建工作进程,工作进程所执行的代码为处理函数ngx_worker_process_cycle;
(7)工作进程主处理函数:ngx_worker_process_cycle,在该函数中死循环调用:ngx_process_events_and_timers进行事件处理;
(8)在函数ngx_process_events_and_timers中,调用了宏ngx_process_events对事件进行处理,需要特别注意该宏, nginx通过它实现了对不同操作系统下各种IO复用方式进行统一处理,这一过程将会在下面详细描述。
(9)宏ngx_process_events被定义为:ngx_event_actions.process_events;其中全局变量ngx_event_actions里保存了处理事件的所有函数指针,ngx_event_action在文件ngx_event.c中被定义为ngx_event_actions_t类型。
(10)ngx_event_actions的类型为:ngx_event_actions_t的全局变量,定义在文件ngx_event.c中,类型ngx_event_actions_t定义形式为:
typedefstruct {
ngx_int_t (*add)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
ngx_int_t (*del)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
ngx_int_t (*enable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
ngx_int_t (*disable)(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags);
ngx_int_t (*add_conn)(ngx_connection_t *c);
ngx_int_t (*del_conn)(ngx_connection_t *c, ngx_uint_t flags);
ngx_int_t (*notify)(ngx_event_handler_pt handler);
ngx_int_t (*process_events)(ngx_cycle_t *cycle, ngx_msec_t timer,
ngx_uint_t flags);
ngx_int_t (*init)(ngx_cycle_t *cycle, ngx_msec_t timer);
void (*done)(ngx_cycle_t *cycle);
} ngx_event_actions_t;
这样在Nginx中,全局变量ngx_event_actions里保存了抽象出来的add、del、enable等事件操作函数。
(3)对于Nginx所支持的每种IO复用类型,例如:epoll、poll、kqueue等,它们都会定义自己的处理函数;各IO复用模式的操作函数指针被放在结构体类型ngx_event_module_t中,其定义为:
typedefstruct {
ngx_str_t *name;
void *(*create_conf)(ngx_cycle_t*cycle);
char *(*init_conf)(ngx_cycle_t*cycle, void *conf);
ngx_event_actions_t actions;
}ngx_event_module_t;
(4)对于epoll,它在文件ngx_epoll_module.c定义了自己的结构体变量:
ngx_event_module_t ngx_epoll_module_ctx
在定义的同时,也给成员ngx_event_actions_tactions赋值了全部的事件操作函数指针,如下图所示:
ngx_event_module_t ngx_epoll_module_ctx = {
&epoll_name,
ngx_epoll_create_conf, /* create configuration */
ngx_epoll_init_conf, /* init configuration */
{
ngx_epoll_add_event, /* add an event */
ngx_epoll_del_event, /* delete an event */
ngx_epoll_add_event, /* enable an event */
ngx_epoll_del_event, /* disable an event */
ngx_epoll_add_connection, /* add an connection */
ngx_epoll_del_connection, /* delete an connection */
#if(NGX_HAVE_EVENTFD)
ngx_epoll_notify, /* trigger a notify */
#else
NULL, /* trigger a notify */
#endif
ngx_epoll_process_events, /* process the events */
ngx_epoll_init, /* init the events */
ngx_epoll_done, /* done the events */
}
};
可以看到诸如处理事件的函数指针ngx_epoll_process_events等等一系列的事件操作函数指针;
(5)在epoll的ngx_epoll_init函数中将所定义epoll的全部处理函数指针ngx_epoll_module_ctx.actions赋值给该全局变量ngx_event_actions,如下所示:
ngx_event_actions= ngx_epoll_module_ctx.actions;
从而,我们前面重点关注的宏ngx_process_events也就被赋予了操作epoll的具体函数指针。
(6)以事件处理函数指针ngx_epoll_process_events为例,可以看到,在该函数中:
l 调用epoll_wait等待epoll的读事件的到来;
l Epoll_wait返回之后,通过一个for循环处理所有就绪的socket;
l 如果socket有数据要读,则执行:rev->handler(rev)进行数据读取;如果有socket有数据要写,则执行:wev->handler(wev)进行数据写入;
Nginx的主要函数调用关系分析相关推荐
- Apache Spark源码走读之3 -- Task运行期之函数调用关系分析
概要 本篇主要阐述在TaskRunner中执行的task其业务逻辑是如何被调用到的,另外试图讲清楚运行着的task其输入的数据从哪获取,处理的结果返回到哪里,如何返回. 准备 spark已经安装完毕 ...
- python函数调用关系分析
在Pycharm的专业版中,提供了一个分析项目性能的工具run->Profile,可以将工程运行时各函数的调用次数和所用时间记录下来,提供静态数据和关系图表两种表达方式. 只需轻轻一点,统计数据 ...
- 输出nginx执行过程中函数调用关系
添加源文件 首先在src/core/目录下添加两个文件,分别是my_debug.h和my_debug.c. #ifndef MY_DEBUG_LENKY_H #define MY_DEBUG_LENK ...
- c语言调用graphviz_c语言分析函数调用关系图(call graph)的几种方法
一.基于 Doxygen或 lxr 的API形式的文档系统. 二.基于CodeViz, CodeViz是<Understanding The Linux Virtual Memory Manag ...
- [授权发表]源码分析:静态分析 C 程序函数调用关系
故事缘由 工欲善其事,必先利其器.今天我们来玩转一个小工具,叫 Callgraph,它可以把 C 语言的函数调用树(或者说流程图)画出来. 传统的命令行工具 Cscope,Ctags 可以结合vim ...
- 静态分析C语言生成函数调用关系的利器——cflow
除了<静态分析C语言生成函数调用关系的利器--calltree>一文中介绍的calltree,我们还可以借助cflow辅助我们阅读理解代码.(转载请指明出于breaksoftware的cs ...
- 函数调用关系python_追踪python函数调用关系
在我们执行拥有复杂函数调用关系的一段python程序时,我们希望能够清楚的知道他们之间的调用关系以及在调用过程中传入的参数信息和返回值,这些信息对于我们分析程序的行为和bug会很有帮助. 我希望能实现 ...
- GNU cflow实现调用关系分析
GNU cflow是一个GNU的开源项目,有关网站(官网)如下: 官网-GNU cflow 下载-http://ftp.gnu.org/gnu/cflow/ 手册-GNU cflow manual c ...
- 函数调用关系/结构图Callgraph
文章目录 代码结构图 Callgraph安装 使用方法简介 运行结果 代码结构图 源码分析是程序员离不开的话题,无论是研究开源项目,还是平时做各类移植.开发,都避免不了对源码的深入解读.对于一个功 ...
最新文章
- RDIFramework.NET V2.9版本 WinFom部分新增与修正的功能
- 用Tableau画幂函数柱状图
- react(87)--批量删除进行置空操作
- c++语言用文件输入数值,C++ 基本的输入输出
- mysql 5.7.16 忘记root 密码 如何修改root密码
- lingo入门教程之三 --- 文件数据处理
- ca盘显示无证书_ca证书提示没有正确的安装驱动程序
- 初级、中级、高级程序员的区别在哪里?
- EOJ 2月月赛补题
- Android模拟器的判定
- 更新至OSX 10.10后MBA外接网卡无法使用的解决
- android 蓝牙sco开发
- 如何用cmd链接linux,如何在Windows cmd 下使用linux的命令
- 验房师去哪找靠谱,验房项目以及验房整改建议,精装房验房项目、毛坯房验房项目
- LeetCode-数据库题(二) (52-125题 到1565)
- python 队列实现_python中实现队列的queue模块
- OpenCV笔记11:利用HSV颜色空间进行目标检测和目标跟踪
- java上传文件到七牛_java 上传文件到七牛云
- 测试行业2018年报告总结
- 14 目录文件夹和根目录
热门文章
- Python官方文档学习心得(第一章)
- 2_less中的数值运算
- java restful项目打包_66-JT项目04(项目打包发布/JSON/项目业务)
- python取模1e9+7_G题取1E9+7wa,取1E9+9等一些其他的值ac
- Java练习02 打印三角形
- mysql 存储过程 模糊查询_mysql 分页创建存储过程并实现模糊查询
- 华为鸿蒙5g售价,华为首款5G手机售价公布,余承东透露鸿蒙将用于连接家庭设备...
- 使用openocd调试Linux内核,OpenOCD-JTAG调试
- linux成功mysql数据直接拷贝_mysql数据库数据从一个linux系统移植到另一个linux系统的方法...
- 火狐中怎么把xml转换为html,创建兼容IE、火狐、chrome、oprea浏览器的xmlDom对象方法...