nginx做爲後端程序不可缺乏的中間件,憑藉其優異的性能和穩定,得到了大量的用戶nginx
其它目錄主要就是存放nginx功能的擴展了、nginx幾乎全部的功能都是經過擴展實現的git
src/core/nginx.c::main()github
在入口程序中,nginx主要是處理了命令行參數,若是沒有帶參數運行nginx,則啓動nginx服務器ngx_master_process_cycle(cycle
算法
核心調用以下後端
給啓用的nginx模塊進行編號服務器
ngx_max_module = 0;
for (i = 0; ngx_modules[i]; i++) {
ngx_modules[i]->index = ngx_max_module++;
}
複製代碼
kill()
ngx_int_t
ngx_os_signal_process(ngx_cycle_t *cycle, char *name, ngx_int_t pid)
{
ngx_signal_t *sig;
for (sig = signals; sig->signo != 0; sig++) {
if (ngx_strcmp(name, sig->name) == 0) {
if (kill(pid, sig->signo) != -1) {
return 0;
}
ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno,
"kill(%P, %d) failed", pid, sig->signo);
}
}
return 1;
}
複製代碼
nginx的模塊是經過在nginx運行的各個生命週期調用模塊的鉤子函數實現的 拿src/event/ngx_event.c:184舉例網絡
ngx_module_t ngx_event_core_module = {
NGX_MODULE_V1,
&ngx_event_core_module_ctx, /* module context */
ngx_event_core_commands, /* module directives */
NGX_EVENT_MODULE, /* module type */
NULL, /* init master */
ngx_event_module_init, /* init module */
ngx_event_process_init, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
複製代碼
能夠看到nginx爲每一個模塊都支持了7個鉤子函數數據結構
回調函數 | 做用 |
---|---|
init master | master進程建立時調用 |
init module | 初始化模塊時調用 |
init process | worker進程初始化時調用 |
init thread | 未使用 |
exit thread | 未使用 |
exit process | worker進程退出時調用 |
exit master | master進程退出時調用 |
nginx的事件驅動在src/event/ngx_event.c::ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf)函數中選擇,核心代碼以下數據結構和算法
static char * ngx_event_core_init_conf(ngx_cycle_t *cycle, void *conf) {
ngx_event_conf_t *ecf = conf;
...
#if (NGX_HAVE_EPOLL) && !(NGX_TEST_BUILD_EPOLL)
fd = epoll_create(100);
if (fd != -1) {
close(fd);
module = &ngx_epoll_module;
} else if (ngx_errno != NGX_ENOSYS) {
module = &ngx_epoll_module;
}
#endif
...
ngx_conf_init_uint_value(ecf->use, module->ctx_index);
...
}
複製代碼
能夠看到nginx默認會優先選擇epoll網絡事件模型進行驅動,日後纔是kqueue、select,而後把最後肯定使用的網絡驅動模塊的索引存到ecf->use這個指針中,後面就能夠經過這個use指針調用nginx使用的網絡庫了ide
在worker進程初始化時:src/event/ngx_event.c:ngx_event_process_init()
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_EVENT_MODULE) {
continue;
}
if (ngx_modules[m]->ctx_index != ecf->use) {
continue;
}
module = ngx_modules[m]->ctx;
if (module->actions.init(cycle, ngx_timer_resolution) != NGX_OK) {
/* fatal */
exit(2);
}
break;
}
複製代碼
遍歷全部模塊,找出目前系統選擇的網絡庫ngx_modules[m]->ctx_index != ecf->use
,而後調用初始化函數進行初始化module->actions.init(cycle, ngx_timer_resolution)
actions結構體在src/event/ngx_event.h:ngx_event_actions_t
typedef struct {
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 (*process_changes)(ngx_cycle_t *cycle, ngx_uint_t nowait);
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;
複製代碼
初始化在src/event/modules/ngx_epoll_module.c:ngx_event_module_t ngx_epoll_module_ctx
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 */
NULL, /* process the changes */
ngx_epoll_process_events, /* process the events */
ngx_epoll_init, /* init the events */
ngx_epoll_done, /* done the events */
}
};
複製代碼
init函數指針對應調用的就是ngx_epoll_init函數了
static ngx_int_t
ngx_epoll_init(ngx_cycle_t *cycle, ngx_msec_t timer)
...
ep = epoll_create(cycle->connection_n / 2);
...
}
複製代碼
能夠看到主要是調用epoll_create函數了,其他的網絡庫調用能夠經過ngx_event_actions_t、ngx_epoll_module_ctx找到了
本文基於nginx 1.2.0 寫成,源碼下載參考:nginx.org/download/