nginx源码目录结构及初始化过程

2014-12-26 00:30:18   最后更新: 2014-12-26 19:29:08   访问数量:1555




众所周知,每一个C语言程序都是从main函数开始调用的,nginx当然也不例外

nginx 的所有代码都在 src 目录下,这个目录下有下图6个目录:

 

  • core -- 核心源码目录,包括常用结构体的定义和实现
  • event -- 事件系统的封装
  • http -- http 服务器实现源码
  • mail -- 邮件服务器实现源码
  • misc -- google perftools
  • os -- nginx 对各个系统下不同函数的统一封装

 

main 函数就在 core 目录下的 nginx.c 文件中

// 主进程 {{{ // // ngx_cdecl: 一个未实现的宏,可选为 stdcall 或 cdecl,用来支持跨平台 // 区别:stdcall 是被调用者清理栈空间,cdecl 是调用者清理栈空间 // 未显式指定则按编译器默认值 int ngx_cdecl main(int argc, char *const *argv) { ngx_int_t i; ngx_log_t *log; ngx_cycle_t *cycle, init_cycle; ngx_core_conf_t *ccf; ngx_debug_init(); if (ngx_strerror_init() != NGX_OK) { return 1; } // 获取调用参数, 修改全局变量 if (ngx_get_options(argc, argv) != NGX_OK) { return 1; } if (ngx_show_version) { ngx_write_stderr("nginx version: " NGINX_VER_BUILD NGX_LINEFEED); // NGX_LINEFEED: \x0A // NGX_PREFIX: 默认运行目录 if (ngx_show_help) { ngx_write_stderr( "Usage: nginx [-?hvVtq] [-s signal] [-c filename] " "[-p prefix] [-g directives]" NGX_LINEFEED NGX_LINEFEED "Options:" NGX_LINEFEED " -?,-h : this help" NGX_LINEFEED " -v : show version and exit" NGX_LINEFEED " -V : show version and configure options then exit" NGX_LINEFEED " -t : test configuration and exit" NGX_LINEFEED " -q : suppress non-error messages " "during configuration testing" NGX_LINEFEED " -s signal : send signal to a master process: " "stop, quit, reopen, reload" NGX_LINEFEED #ifdef NGX_PREFIX " -p prefix : set prefix path (default: " NGX_PREFIX ")" NGX_LINEFEED #else " -p prefix : set prefix path (default: NONE)" NGX_LINEFEED #endif " -c filename : set configuration file (default: " NGX_CONF_PATH ")" NGX_LINEFEED " -g directives : set global directives out of configuration " "file" NGX_LINEFEED NGX_LINEFEED ); } if (ngx_show_configure) { ngx_write_stderr( #ifdef NGX_COMPILER "built by " NGX_COMPILER NGX_LINEFEED #endif #if (NGX_SSL) #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME "TLS SNI support enabled" NGX_LINEFEED #else "TLS SNI support disabled" NGX_LINEFEED #endif #endif "configure arguments:" NGX_CONFIGURE NGX_LINEFEED); } if (!ngx_test_config) { return 0; } } /* TODO */ ngx_max_sockets = -1; ngx_time_init(); #if (NGX_PCRE) ngx_regex_init(); #endif ngx_pid = ngx_getpid(); // 初始化log // 初始化 ngx_log 结构,创建 errlog 文件 log = ngx_log_init(ngx_prefix); if (log == NULL) { return 1; } /* STUB */ #if (NGX_OPENSSL) ngx_ssl_init(log); #endif /* * init_cycle->log is required for signal handlers and * ngx_process_options() */ ngx_memzero(&init_cycle, sizeof(ngx_cycle_t)); init_cycle.log = log; ngx_cycle = &init_cycle; // 创建内存池 // 1KB init_cycle.pool = ngx_create_pool(1024, log); if (init_cycle.pool == NULL) { return 1; } // 保存调用参数到全局变量,init_cycle 只用于提供 log 参数 if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) { return 1; } // 保存配置文件路径、程序运行路径、调用参数到 init_cycle if (ngx_process_options(&init_cycle) != NGX_OK) { return 1; } // 获取操作系统信息、CPU信息、最大连接数、是否支持非阻塞连接等 if (ngx_os_init(log) != NGX_OK) { return 1; } /* * ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init() */ // 对齐校验表 if (ngx_crc32_table_init() != NGX_OK) { return 1; } // 获取所有继承连接fd的相关信息 if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) { return 1; } ngx_max_module = 0; // objs/ngx_modules.c // ngx_module_t *ngx_modules[] = { {{{ // &ngx_core_module, // &ngx_errlog_module, // &ngx_conf_module, // &ngx_events_module, // &ngx_event_core_module, // &ngx_epoll_module, // &ngx_regex_module, // &ngx_http_module, // &ngx_http_core_module, // &ngx_http_log_module, // &ngx_http_upstream_module, // &ngx_http_static_module, // &ngx_http_autoindex_module, // &ngx_http_index_module, // &ngx_http_auth_basic_module, // &ngx_http_access_module, // &ngx_http_limit_conn_module, // &ngx_http_limit_req_module, // &ngx_http_geo_module, // &ngx_http_map_module, // &ngx_http_split_clients_module, // &ngx_http_referer_module, // &ngx_http_rewrite_module, // &ngx_http_proxy_module, // &ngx_http_fastcgi_module, // &ngx_http_uwsgi_module, // &ngx_http_scgi_module, // &ngx_http_memcached_module, // &ngx_http_empty_gif_module, // &ngx_http_browser_module, // &ngx_http_upstream_hash_module, // &ngx_http_upstream_ip_hash_module, // &ngx_http_upstream_least_conn_module, // &ngx_http_upstream_keepalive_module, // &ngx_http_write_filter_module, // &ngx_http_header_filter_module, // &ngx_http_chunked_filter_module, // &ngx_http_range_header_filter_module, // &ngx_http_gzip_filter_module, // &ngx_http_postpone_filter_module, // &ngx_http_ssi_filter_module, // &ngx_http_charset_filter_module, // &ngx_http_userid_filter_module, // &ngx_http_headers_filter_module, // &ngx_http_copy_filter_module, // &ngx_http_range_body_filter_module, // &ngx_http_not_modified_filter_module, // NULL // }; }}} // 对模块进行编号 for (i = 0; ngx_modules[i]; i++) { ngx_modules[i]->index = ngx_max_module++; } // 全部初始化工作,包括时间、内存池、配置文件、共享内存 // 、监听连接数组、所有模块的初始化, // 以及配置及log文件创建、连接开启监听 cycle = ngx_init_cycle(&init_cycle); if (cycle == NULL) { if (ngx_test_config) { ngx_log_stderr(0, "configuration file %s test failed", init_cycle.conf_file.data); } return 1; } if (ngx_test_config) { if (!ngx_quiet_mode) { ngx_log_stderr(0, "configuration file %s test is successful", cycle->conf_file.data); } return 0; } if (ngx_signal) { return ngx_signal_process(cycle, ngx_signal); } ngx_os_status(cycle->log); ngx_cycle = cycle; ccf = (ngx_core_conf_t *) ngx_get_conf(cycle->conf_ctx, ngx_core_module); if (ccf->master && ngx_process == NGX_PROCESS_SINGLE) { ngx_process = NGX_PROCESS_MASTER; } #if !(NGX_WIN32) if (ngx_init_signals(cycle->log) != NGX_OK) { return 1; } if (!ngx_inherited && ccf->daemon) { if (ngx_daemon(cycle->log) != NGX_OK) { return 1; } ngx_daemonized = 1; } if (ngx_inherited) { ngx_daemonized = 1; } #endif if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) { return 1; } if (ngx_log_redirect_stderr(cycle) != NGX_OK) { return 1; } if (log->file->fd != ngx_stderr) { if (ngx_close_file(log->file->fd) == NGX_FILE_ERROR) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, ngx_close_file_n " built-in log failed"); } } ngx_use_stderr = 0; if (ngx_process == NGX_PROCESS_SINGLE) { ngx_single_process_cycle(cycle); } else { ngx_master_process_cycle(cycle); } return 0; } // }}}

 

 

这里 main 函数是这么写的:

int ngx_cdecl main(int argc, char *const *argv)

 

ngx_cdecl 是什么呢?

他定义在 core/ngx_config.h 中:

#define ngx_cdecl

 

一个空的宏,这究竟是用来做什么的呢?

 

众所周知,汇编中函数有两种调用方式,分别是 stdcall 和 cdecl

区别在于 stdcall 是被调用者清理栈空间,cdecl 是调用者清理栈空间

这里使用这个宏用来兼容不同的平台

 

所有的启动流程都在上面的主进程中进行,主要围绕 ngx_cycle_t 结构的初始化展开,nginx 服务的生命周期中用到的核心组件都在这个 cycle 变量中

结构十分清晰

  1. ngx_strerror_init() -- 初始化错误类型存储区,保存所有系统错误
  2. ngx_get_options(argc, argv) -- 获取调用参数
  3. ngx_time_init() -- 初始化几个时间变量
  4. ngx_regex_init() -- 正则表达式初始化
  5. ngx_log_init(ngx_prefix) -- 初始化日志结构,创建并打开日志文件
  6. ngx_ssl_init(log) -- https 相关的初始化
  7. ngx_create_pool(1024, log) -- 创建1KB内存池
  8. ngx_save_argv(&init_cycle, argc, argv) -- 保存调用参数到 init_cycle
  9. ngx_process_options(&init_cycle) -- 保存配置文件路径、程序运行路径、环境变量到 init_cycle
  10. ngx_os_init(log) -- 获取操作系统信息、CPU信息、最大连接数、是否支持非阻塞连接等
  11. ngx_crc32_table_init() -- 对齐冗余校验表
  12. ngx_add_inherited_sockets(&init_cycle) -- 获取所有继承得到的连接 fd
  13. ngx_init_cycle(&init_cycle) -- 初始化工作最核心的部分,全部初始化工作,包括时间、内存池、配置文件、共享内存、监听连接数组、所有模块的初始化,以及配置及log文件创建,events、http模块加载,连接开启监听
  14. ngx_signal_process(cycle, ngx_signal) -- 根据配置文件中配置的pid发送信号
  15. ngx_os_status(cycle->log) -- 对具体操作系统进行特殊处理
  16. ngx_init_signals(cycle->log) -- 初始化信号
  17. ngx_daemon(cycle->log) -- 成为服务器守护进程
  18. ngx_create_pidfile(&ccf->pid, cycle->log) -- 创建pid文件
  19. ngx_master_process_cycle(cycle)/ngx_single_process_cycle(cycle) -- fork slaver进程或单独执行

 

嗯,初步来说,在启动过程中,nginx 做了这么多事情,那么具体每一个函数中又做了什么呢?每一个结构体又具有怎样的含义呢?以及这之后,nginx 又是怎样承担起一个服务器的重任的呢?

敬请期待后续介绍

 

转载请注明出处:龙潭斋

 






技术帖      目录结构      龙潭书斋      nginx      源码      opensource      init      main      cycle     


京ICP备15018585号