沈阳工程学院毕业论文 第3章 Apache体系结构
case 'E':
temp_error_log = apr_pstrdup(process->pool, optarg); break; -E file选项用于将服务器的启动过程中的出错信息发送到file。 case 'X':
new = (char **)apr_array_push(ap_server_config_defines);
*new = \ break;
-X选项指定当前Apache以调式模式运行,在此模式下,Apache进启动一个工作进程,并且服务器不与控制台脱离。
case 'f':
confname = optarg; break;
-f config选项在启动中使用config作为配置文件。如果config不以“/”开头,则它是相对于ServerRoot的路径。默认值为conf/httpd.conf。 case 'v':
printf(\ printf(\ %s\\n\ destroy_and_exit_process(process, 0);
-v选项只是简单的显示httpd的版本,然后退出。 case 'V':
show_compile_settings();
destroy_and_exit_process(process, 0);
-V选项用于显示httpd和APR/APR-Util的版本和编译参数,然后退出。 case 'l':
ap_show_modules();
destroy_and_exit_process(process, 0);
-I选项用于输出一个静态编译在服务器中的模块列表。它不会列出使用LoadModule指令动态的模块。
case 'L':
ap_show_directives();
destroy_and_exit_process(process, 0);
-L选项输出一个指令列表,并包含了各指令有效参数和使用区域。 case 't':
configtestonly = 1; break;
-t选项意味着仅对配置文件执行语法检查。 case ?S?:
configtestonly = 1;
new = (char **)apr_array_push(ap_server_config_defines); *new = “DUMP_VHOSTS”; break;
-S显示从配置文件中读取并解析的设置结果。 case ?M?:
configtestonly = 1;
- 15 -
沈阳工程学院毕业论文 第3章 Apache体系结构
new = (char **)apr_array_push(ap_server_config_defines); *new = “DUMP_MODULES”; break;
-M输出一个已经启用模块列表,包括静态编译在服务器中的模块和作为DSO动态加载的模块。
case 'h':
case '?':
usage(process);
-h和-?输出一个可用的命令行选项的简要说明。 } }
主程序对于Windows所需要的-K、-n及-w选项并没有处理,这些选项由于只有MPM才会使用到,因此它们在MPM中被处理,处理由rewrite_args挂钩触法。
/* bad cmdline option? then we die */
if (rv != APR_EOF || opt->ind < opt->argc) { usage(process);}
apr_pool_create(&plog, pglobal); apr_pool_tag(plog, \
apr_pool_create(&ptemp, pconf); apr_pool_tag(ptemp, \
Apache中使用的所有内存资源都是基于内存池的概念分配的,所有的内存池之间形成内存池树的概念。层次越深的内存池它的生存周期就越短,反之,距离根节点越近,它的生存周期就越长。所有节点的根节点是全局内存池pglobal,在启动的时候被分配。除此之外,在启动的时候还需要一个临时内存池——ptemp。
ap_server_root = def_server_root; if (temp_error_log) {
ap_replace_stderr_log(process->pool, temp_error_log); }
一般情况下,如果没有指定日志输出文件,就是用标准的输出设备stderr。。如果在启动Apache的时候通过-E选项指定了日志文件,那么,此时必须使用ap_replace_stderr_log进行输出日志文件替换。
if (ap_run_pre_config(pconf, plog, ptemp) != OK) { destroy_and_exit_process(process, 1);}
rv = ap_process_config_tree(server_conf, ap_conftree, process->pconf,
ptemp);
if(rv = = OK){
ap_fixup_virtual_hosts(pconf, server_conf); ap_fini_vhost_config(pconf, server_conf); apr_hook_sort_all(); if (configtestonly) {
- 16 -
沈阳工程学院毕业论文 第3章 Apache体系结构
ap_run_test_config(pconf, server_conf);
ap_log_error(APLOG_MARK, APLOG_STARTUP, 0, NULL, \
destroy_and_exit_process(process, 0);} }
在main.c中,配置文件在Apache启动或重启时的时候总是被读取两次,一次是在主循环执行之前被读取,正如上面代码中所读取的一样,另外一次是在主循环中被读取。之所以要读取两次,主要基于以下两个目的:
(1)预检查配置文件中可能出现的语法错误,确保在真正处理的时候配置文件是完整无误的。
(2)第一次读取文件会生成第二次读取文件时所需要的字段。
代码如下:
signal_server = APR_RETRIEVE_OPTIONAL_FN(ap_signal_server); if (signal_server) { int exit_status;
if (signal_server(&exit_status, pconf) != 0) {
destroy_and_exit_process(process, exit_status); } }
if(rv ! = OK) {
destroy_and_exit_process(process, exit_status); apr_pool_clear(plog);
apr_pool_clear(plog);
if ( ap_run_open_logs(pconf, plog, ptemp, server_conf) != OK) { destroy_and_exit_process(process, 1);}
if ( ap_run_post_config(pconf, plog, ptemp, server_conf) != OK) { destroy_and_exit_process(process, 1);} apr_pool_destroy(ptemp);
整个配置文件的完整读取过程包括三个部分。 (1)读取配置文件的准备工作。 (2)实际的配置文件读取。 (3)读取配置文件后的处理。
如果摸个模块由于某种原因需要启动分离的进程,就应该在这个阶段来完成,代码如下:
for (;;) {
apr_hook_deregister_all(); apr_pool_clear(pconf);
for (mod = ap_prelinked_modules; *mod != NULL; mod++) { ap_register_hooks(*mod, pconf); }
ap_conftree = NULL;
- 17 -
沈阳工程学院毕业论文 第3章 Apache体系结构
apr_pool_create(&ptemp, pconf); apr_pool_tag(ptemp, \
ap_server_root = def_server_root;
server_conf = ap_read_config(process, ptemp, confname,
&ap_conftree);
if (ap_run_pre_config(pconf, plog, ptemp) != OK) { ap_log_error(APLOG_MARK,
APLOG_STARTUPAPLOG_ERR, 0, NULL, \
destroy_and_exit_process(process, 1); }
if (ap_process_config_tree(server_conf, ap_conftree, process->pconf,
ptemp) != OK) {
destroy_and_exit_process(process, 1); } ap_fixup_virtual_hosts(pconf, server_conf); ap_fini_vhost_config(pconf, server_conf); apr_sort_hooks(); apr_pool_clear(plog);
if (ap_run_open_logs(pconf, plog, ptemp, server_conf) != OK) { ap_log_error(APLOG_MARK, APLOG_STARTUP |APLOG_ERR,
0, NULL, \ destroy_and_exit_process(process, 1);}
if (ap_run_post_config(pconf, plog, ptemp, server_conf) != OK) { ap_log_error(APLOG_MARK,
APLOG_STARTUP |APLOG_ERR,
0, NULL, \ destroy_and_exit_process(process, 1); } apr_pool_destroy(ptemp); apr_pool_lock(pconf, 1);
ap_run_optional_fn_retrieve();
if (ap_mpm_run(pconf, plog, server_conf))
break;
apr_pool_lock(pconf, 0); }
apr_pool_lock(pconf, 0);
destroy_and_exit_process(process, 0); return 0; /* Supress compiler warning. */ }
准备就绪后,Apache就进入了主循环for(;;)。循环中主进程所作的事情包括以下几点:
- 18 -
沈阳工程学院毕业论文 第3章 Apache体系结构
(1)挂钩注册
(2)二次配置文件读取
(3)到处注册所有的可选函数 (4)ap_mpm_run调用
如果ap_mpm_run在执行中发生错误,则返回1,否则返回0。 当ap_mpm_run退出的时候,整个主进程就相应的执行结束了。
- 19 -