#启动流程
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
加上了长度的字段。
typedef struct {
size_t len;
u_char *data;
} ngx_str_t;
定义时,调用一下宏。
#define ngx_string(str) {sizeof(str) - 1, (u_char *) str }
##ngx_queue_t
双向链表。
typedef struct ngx_queue_s ngx_queue_t;
struct ngx_queue_s {
ngx_queue_t *prev;
ngx_queue_t *next;
};
ngx_queue_t只保存指针,那么数据呢?看一下数据获取的方法:
#define ngx_queue_data(q, type, link) (type *) ((u_char *) q - offsetof(type, link))
##ngx_array_t
数组定义。
typedef struct {
void *elts;
ngx_uint_t nelts;
size_t size;
ngx_uint_t nalloc;
ngx_pool_t *pool;
} ngx_array_t;
可见数组是结合内存池使用的,看下数组如何创建:
ngx_array_t *ngx_array_create(ngx_pool_t *p, ngx_uint_t n, size_t size) {
ngx_array_t *a;
a = ngx_palloc(p, sizeof(ngx_array_t));
if (a == NULL) {
return NULL;
}
if (ngx_array_init(a, p, n, size) != NGX_OK) {
return NULL;
}
return a;
}
##ngx_list_t
数组加链表的结合体。
typedef struct ngx_list_part_s ngx_list_part_t;
struct ngx_list_part_s {
void *elts;
ngx_uint_t nelts;
ngx_list_part_t *next;
};
typedef struct {
ngx_list_part_t *last;
ngx_list_part_t part;
size_t size;
ngx_uint_t nalloc;
ngx_pool_t *pool;
} ngx_list_t;
##ngx_table_elt_t
hash表的一个元素。
typedef struct {
void *value;
u_short len;
u_char name[1];
} ngx_hash_elt_t;
顺便提一句,nginx用的是开放地址法,会往右查找空闲的bucket。因为它其实假设了hash表不会占用太多的数据和空间。
##ngx_rbtree_t
典型的红黑树。
typedef struct ngx_rbtree_node_s ngx_rbtree_node_t;
struct ngx_rbtree_node_s {
ngx_rbtree_key_t key;
ngx_rbtree_node_t *left;
ngx_rbtree_node_t *right;
ngx_rbtree_node_t *parent;
u_char color;
u_char data;
};
typedef struct ngx_rbtree_s ngx_rbtree_t;
typedef void (*ngx_rbtree_insert_pt) (ngx_rbtree_node_t *root, ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
struct ngx_rbtree_s {
ngx_rbtree_node_t *root;
ngx_rbtree_node_t *sentinel;
ngx_rbtree_insert_pt insert;
};
#内存管理
内存的申请最终调用的是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()处理管道信号
- 处理相关信号