Nginx源码阅读
启动流程
main函数执行过程:
- ngx_get_options()解析命令参数
- ngx_time_init()初始化时间,ngx_cached_time也在这里
- ngx_log_init()初始化日志
- 清零ngx_cycle,并为ngx_cycle.pool创建1024B的内存池
- ngx_save_argv()保存命令行参数至全局变量ngx_os_argv、ngx_argc、ngx_argv中
- ngx_process_options()初始化字段
- ngx_os_init()初始化系统相关变量
- ngx_crc32_table_init()初始化CRC表(后续的CRC校验通过查表进行,效率高)
- ngx_add_inherited_sockets()继承sockets
- 初始化每个module的index,并计算ngx_max_module
- ngx_init_cycle()进行初始化
- 若有信号,进入ngx_signal_process()处理,调用ngx_init_signals()初始化信号;若无信号,继承sockets,设置守护进程标识,ngx_daemon()创建守护进程
- ngx_create_pidfile()创建进程记录文件
- 进入程序主循环:若为NGX_PROCESS_SINGLE=1模式,则调用ngx_single_process_cycle()进入进程循环;否则为master-worker模式,调用ngx_master_process_cycle()
ngx_pool_s
Nginx的内存池。每个工作线程都会有一个。内存池的分配原理看ngx_palloc方法。
ngx_cycle_s
每个工作进程都会维护一个。
数据结构
ngx_str_t
加上了长度的字段。
|
|
定义时,调用一下宏。
|
ngx_queue_t
双向链表。
|
|
ngx_queue_t只保存指针,那么数据呢?看一下数据获取的方法:
|
ngx_array_t
数组定义。
|
|
可见数组是结合内存池使用的,看下数组如何创建:
|
|
ngx_list_t
数组加链表的结合体。
|
|
ngx_table_elt_t
hash表的一个元素。
|
|
顺便提一句,nginx用的是开放地址法,会往右查找空闲的bucket。因为它其实假设了hash表不会占用太多的数据和空间。
ngx_rbtree_t
典型的红黑树。
|
|
内存管理
内存的申请最终调用的是malloc函数,ngx_calloc在调用ngx_alloc后,用memset来填0。
自己开发模块时,不要直接使用ngx_malloc/ngx_calloc,否则要自己管理内存的释放,可以使用ngx_palloc。
master进程
在ngx_master_process_cycle()函数中。
启动过程:
- 阻塞信号
- 设置进程名称
- 启动工作进程
- 启动cache管理进程
- 进入循环处理信号
master工作过程:
- 设置worker退出等待时间
- 挂起,等待新的信号
- 更新时间
- 如果有worker因为SIGCHLD退出,则重启worker
- master退出
- 处理SIGTERM
- 处理SIGQUIT,关闭socket
- 处理SIGHUP
- 处理重启
- 处理SIGUSR1,重新打开所有文件
- 处理SIGUSR2,热代码替换,执行新程序
- 处理SIGWINCH
worker进程
- ngx_start_worker_processes()
- 进程相关结构初始化
- fork子进程
- 设置ngx_processes[s]相关属性
- ngx_pass_open_channel(cycle, &ch)通知子进程新进程创建完毕
- ngx_worker_process_init()初始化
- ngx_channel_handler()处理管道信号
- 处理相关信号