nginx启动初始化代码执行流程
流程图
代码执行流程
ngx_event_process_init:遍历connections,初始化listenfd的回调函数,添加事件监听
static ngx_int_t
ngx_event_process_init(ngx_cycle_t *cycle)
{
...
cycle->connections=
ngx_alloc(sizeof(ngx_connection_t) * cycle->connection_n, cycle->log);
cycle->read_events=ngx_alloc(sizeof(ngx_event_t) * cycle->connection_n,
cycle->log);
...
ls=cycle->listening.elts;
for (i=0; i < cycle->listening.nelts; i++) {
c=ngx_get_connection(ls[i].fd, cycle->log);
c->listening=&ls[i];
rev=c->read;
}
...
rev->handler=ngx_event_accept;
ngx_add_event(rev, NGX_READ_EVENT, 0)
...
}
ngx_event_accept:调用ngx_listening_t的回调函数
void
ngx_event_accept(ngx_event_t *ev)
{
...
lc=ev->data;
ls=lc->listening;
...
s=accept(lc->fd, (struct sockaddr *) sa, &socklen);
c=ngx_get_connection(s, ev->log);
ngx_add_conn(c)
ls->handler(c);
...
}
找到ls->handler(c)的位置
static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
...
if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) !=NGX_OK) {
return NGX_CONF_ERROR;
}
...
}
static ngx_int_t
ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
ngx_array_t *ports)
{
...
if (ngx_http_init_listening(cf, &port[p]) !=NGX_OK) {
return NGX_ERROR;
}
...
}
static ngx_int_t
ngx_http_init_listening(ngx_conf_t *cf, ngx_http_conf_port_t *port)
{
...
ls=ngx_http_add_listening(cf, &addr[i]);
if (ls==NULL) {
return NGX_ERROR;
}
...
}
static ngx_listening_t *
ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)
{
...
ls->handler=ngx_http_init_connection;
...
}
第三方模块(输出):
server {
listen 0.0.0.0:70;
location / {
root /usr/local/nginx/html/bak/;
limit_req zone=req10k burst=5 nodelay;
shuchu "helloworld";
}
}
一个模块的三大核心
static ngx_command_t ngx_http_shuchu_commands[]={
{
ngx_string("shuchu"),
NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_http_shuchu,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_shuchu_loc_conf_t, content),
NULL,
},?
ngx_null_command,
};
static ngx_http_module_t? ngx_http_shuchu_ctx={
NULL,
ngx_http_shuchu_init,
NULL,
NULL,
NULL,
NULL,
ngx_http_shuchu_create_loc_conf,
ngx_http_shuchu_merge_loc_conf
};
ngx_module_t ngx_http_shuchu_module={
NGX_MODULE_V1,
&ngx_http_shuchu_ctx,?
ngx_http_shuchu_commands,?
NGX_HTTP_MODULE,
NULL,?
NULL,?
NULL,?
NULL,?
NULL,?
NULL,?
NULL,?
NGX_MODULE_V1_PADDING
};
ngx_conf_parse:解析配置
char *
ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename)
{
...
type=parse_file;
fd=ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
rc=ngx_conf_read_token(cf);
省略对rc和type组合的判定
rc=ngx_conf_handler(cf, rc);
...
}
ngx_conf_handler:对指令进行处理
static ngx_int_t
ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last)
{
...
for (i=0; ngx_modules[i]; i++) {
cmd=ngx_modules[i]->commands;
for ( ; cmd->name.len; cmd++) {
if (cmd->type & NGX_DIRECT_CONF) {
conf=((void **) cf->ctx)[ngx_modules[i]->index];
} else if (cmd->type & NGX_MAIN_CONF) {
conf=&(((void **) cf->ctx)[ngx_modules[i]->index]);
} else if (cf->ctx) {
confp=*(void **) ((char *) cf->ctx + cmd->conf);
if (confp) {
conf=confp[ngx_modules[i]->ctx_index];
}
}
rv=cmd->set(cf, cmd, conf);
}
}
...
}
ngx_http_block
static char *
ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
...
ctx->main_conf=ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
ctx->srv_conf=ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
ctx->loc_conf=ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
for (m=0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type !=NGX_HTTP_MODULE) {
continue;
}
module=ngx_modules[m]->ctx;
mi=ngx_modules[m]->ctx_index;
if (module->create_main_conf) {
ctx->main_conf[mi]=module->create_main_conf(cf);
if (ctx->main_conf[mi]==NULL) {
return NGX_CONF_ERROR;
}
}
if (module->create_srv_conf) {
ctx->srv_conf[mi]=module->create_srv_conf(cf);
if (ctx->srv_conf[mi]==NULL) {
return NGX_CONF_ERROR;
}
}
if (module->create_loc_conf) {
ctx->loc_conf[mi]=module->create_loc_conf(cf);
if (ctx->loc_conf[mi]==NULL) {
return NGX_CONF_ERROR;
}
}
}
pcf=*cf;
cf->ctx=ctx;
...
cf->module_type=NGX_HTTP_MODULE;
cf->cmd_type=NGX_HTTP_MAIN_CONF;
rv=ngx_conf_parse(cf, NULL);
...
}
ngx_http_core_server
static char *
ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
...
ctx=ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx==NULL) {
return NGX_CONF_ERROR;
}
http_ctx=cf->ctx;
ctx->main_conf=http_ctx->main_conf;
ctx->srv_conf=ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
ctx->loc_conf=ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
...
cscf=ctx->srv_conf[ngx_http_core_module.ctx_index];
cscf->ctx=ctx;
cmcf=ctx->main_conf[ngx_http_core_module.ctx_index];
cscfp=ngx_array_push(&cmcf->servers);
if (cscfp==NULL) {
return NGX_CONF_ERROR;
}
*cscfp=cscf;
pcf=*cf;
cf->ctx=ctx;
cf->cmd_type=NGX_HTTP_SRV_CONF;
rv=ngx_conf_parse(cf, NULL);
...
}
ngx_http_core_listen
static char *
ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
...
cscf->listen=1;
value=cf->args->elts;
ngx_memzero(&u, sizeof(ngx_url_t));
u.url=value[1];
ngx_parse_url(cf->pool, &u);
if (ngx_http_add_listen(cf, cscf, &lsopt)==NGX_OK) {
return NGX_CONF_OK;
}
...
}
ngx_http_add_listen
ngx_int_t
ngx_http_add_listen(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_listen_opt_t *lsopt)
{
...
cmcf=ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
if (cmcf->ports==NULL) {
cmcf->ports=ngx_array_create(cf->temp_pool, 2,
sizeof(ngx_http_conf_port_t));
if (cmcf->ports==NULL) {
return NGX_ERROR;
}
}
sin=&lsopt->u.sockaddr_in;
p=sin->sin_port;
port=ngx_array_push(cmcf->ports);
port->family=sa->sa_family;
port->port=p;
port->addrs.elts=NULL;
ngx_http_add_address(cf, cscf, port, lsopt);
...
}
ngx_http_add_address
static ngx_int_t
ngx_http_add_address(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_conf_port_t *port, ngx_http_listen_opt_t *lsopt)
{
...
addr=ngx_array_push(&port->addrs);
addr->opt=*lsopt;
addr->default_server=cscf;
...}
ngx_http_add_server
static ngx_int_t
ngx_http_add_server(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_conf_addr_t *addr)
{
...
server=ngx_array_push(&addr->servers);
*server=cscf;
...
}
到这里为止,整个配置的基本架构已经搞起来了,port(ngx_http_conf_port_t)下挂着多个监听的地址(ngx_http_conf_addr_t),每个地址后的opt目前都是配置里面读出来,存着监听器的信息,监听地址(ngx_http_conf_addr_t)后面还挂着这个监听地址所存在的server块(ngx_http_core_srv_conf_t),接下来就要最后在optmize一下,把opt里的东西搞一下,然后做hash:
ngx_http_optimize_servers
static ngx_int_t
ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
ngx_array_t *ports)
{
...
port=ports->elts;
for (p=0; p < ports->nelts; p++) {
addr=port[p].addrs.elts;
for (a=0; a < port[p].addrs.nelts; a++) {
if (ngx_http_server_names(cf, cmcf, &addr[a]) !=NGX_OK) {
return NGX_ERROR;
}
}
if (ngx_http_init_listening(cf, &port[p]) !=NGX_OK) {
return NGX_ERROR;
}
}
...
}
ngx_http_server_names:整理addr中的servers,将sn和对应的srv_conf对应起来
static ngx_int_t
ngx_http_optimize_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
ngx_array_t *ports)
{
...
ha.pool=cf->pool;
cscfp=addr->servers.elts;
for (s=0; s < addr->servers.nelts; s++) {
name=cscfp[s]->server_names.elts;
for (n=0; n < cscfp[s]->server_names.nelts; n++) {
rc=ngx_hash_add_key(&ha, &name[n].name, name[n].server,
NGX_HASH_WILDCARD_KEY);
}
...
hash.hash=&addr->hash;
ngx_hash_init(&hash, ha.keys.elts, ha.keys.nelts);
}
...
}
ngx_http_add_listening
static ngx_listening_t *
ngx_http_add_listening(ngx_conf_t *cf, ngx_http_conf_addr_t *addr)
{
...
ls=ngx_create_listening(cf, &addr->opt.u.sockaddr, addr->opt.socklen);
ls->handler=ngx_http_init_connection;
...
}
instance
每次get_connection都会将instance取反,s是accept获取的socket,是一个int,赋值给c->fd
ngx_connection_t *
ngx_get_connection(ngx_socket_t s, ngx_log_t *log)
{
...
c=ngx_cycle->free_connections;
ngx_cycle->free_connections=c->data;
ngx_cycle->free_connection_n--;
rev=c->read;
wev=c->write;
ngx_memzero(c, sizeof(ngx_connection_t));
c->read=rev;
c->write=wev;
c->fd=s;
rev->instance=!instance;
wev->instance=!instance;
rev->data=c;
wev->data=c;
return c;
...
}
而free的时候只移动链表,清空文件,将当前链表变成可用
void
ngx_free_connection(ngx_connection_t *c)
{
...
c->data=ngx_cycle->free_connections;
ngx_cycle->free_connections=c;
ngx_cycle->free_connection_n++;
if (ngx_cycle->files) {
ngx_cycle->files[c->fd]=NULL;
...
}
而无论是add_event还是add_connection,都是直接将epoll指向的直接与instance,在process_events的时候,拿出来事件指向的
static ngx_int_t
ngx_epoll_add_event(ngx_event_t *ev, ngx_int_t event, ngx_uint_t flags)
{
...
ee.data.ptr=(void *) ((uintptr_t) c | ev->instance);
...
}
static ngx_int_t
ngx_epoll_process_events(ngx_cycle_t *cycle, ngx_msec_t timer, ngx_uint_t flags)
{
...
c=event_list[i].data.ptr;
instance=(uintptr_t) c & 1;
if (c->fd==-1 || rev->instance !=instance) {
...
}