
php 启动过程 - sapi MSHUTDOWN 过程
概述
当服务器关闭时, 会走到 sapi MSHUTDOWN 过程
注册过程
本次内容是在
php 启动过程 - sapi MINIT 过程
之后写的, 对于调用过程本次只做简单描述
- apache 加载 php 模块, apache 启动时调用注册的钩子函数 php_apache_server_startup
- php_apache_server_startup 中使用 apr_pool_cleanup_register 函数注册模块关闭函数 php_apache_server_shutdown
MSHUTDOWN 调用过程
-
调用 php_apache_server_shutdown
static apr_status_t php_apache_server_shutdown(void *tmp)
{
apache2_sapi_module.shutdown(&apache2_sapi_module);
sapi_shutdown();
#ifdef ZTS
tsrm_shutdown();
#endif
return APR_SUCCESS;
}-
调用 apache2_sapi_module.shutdown, 实际上是调用的 php_module_shutdown_wrapper 函数
int php_module_shutdown_wrapper(sapi_module_struct *sapi_globals)
{
TSRMLS_FETCH();
php_module_shutdown(TSRMLS_C);
return SUCCESS;
}-
调用 php_module_shutdown 函数
void php_module_shutdown(TSRMLS_D)
{
int module_number=0; /* for UNREGISTER_INI_ENTRIES() */
module_shutdown = 1;
// 若模块未初始化过, 直接返回
if (!module_initialized) {
return;
} // 省略 ... sapi_flush(TSRMLS_C);
zend_shutdown(TSRMLS_C);
php_shutdown_stream_wrappers(module_number TSRMLS_CC);
UNREGISTER_INI_ENTRIES();
php_shutdown_config(); #ifndef ZTS
zend_ini_shutdown(TSRMLS_C);
shutdown_memory_manager(CG(unclean_shutdown), 1 TSRMLS_CC);
#else
zend_ini_global_shutdown(TSRMLS_C);
#endif php_output_shutdown(); module_initialized = 0; #ifndef ZTS
core_globals_dtor(&core_globals TSRMLS_CC);
gc_globals_dtor(TSRMLS_C);
#else
ts_free_id(core_globals_id);
#endif // 省略 ...
}-
调用 sapi_flush, 刷新 sapi 缓存数据, 实际调用的是 php_apache_sapi_flush
SAPI_API int sapi_flush(TSRMLS_D)
{
if (sapi_module.flush) {
sapi_module.flush(SG(server_context));
return SUCCESS;
} else {
return FAILURE;
}
}// 调用 php_apache_sapi_flush 函数
static void php_apache_sapi_flush(void *server_context)
{
// server_context
php_struct *ctx;
// apache 请求对象
request_rec *r;
TSRMLS_FETCH(); // 省略 ... // sapi 发送响应头信息
sapi_send_headers(TSRMLS_C);
// 响应头信息发送记录
r->status = SG(sapi_headers).http_response_code;
SG(headers_sent) = 1; if (ap_rflush(r) < 0 || r->connection->aborted) {
php_handle_aborted_connection();
}
}-
php_struct 结构
// server_context 结构
typedef struct php_struct {
int state;
request_rec *r;
apr_bucket_brigade *brigade;
/* stat structure of the current file */
#if defined(NETWARE) && defined(CLIB_STAT_PATCH)
struct stat_libc finfo;
#else
struct stat finfo;
#endif
// 是否在处理请求
int request_processed;
// content_type
char *content_type;
} php_struct;
-
-
调用 zend_shutdown, 关闭 zend 引擎, 主要是关闭 zend 引擎运行过程中产生的数据以及结构
void zend_shutdown(TSRMLS_D) /* {{{ */
{
#ifdef ZEND_SIGNALS
zend_signal_shutdown(TSRMLS_C);
#endif
zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC);
/*
* 以下所有的事情都是清除以及释放函数表, 类表, 常量表, 以及全局性的一些结构
* 其中 zend_shutdown_extensions 调用每个扩展自己的 shutdown 函数
*/
if (EG(active))
{
zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC);
zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) zend_cleanup_user_class_data TSRMLS_CC);
zend_cleanup_internal_classes(TSRMLS_C);
zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) clean_non_persistent_function_full TSRMLS_CC);
zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) clean_non_persistent_class_full TSRMLS_CC);
} zend_destroy_modules(); zend_hash_destroy(GLOBAL_FUNCTION_TABLE);
zend_hash_destroy(GLOBAL_CLASS_TABLE);
zend_hash_destroy(GLOBAL_AUTO_GLOBALS_TABLE);
free(GLOBAL_AUTO_GLOBALS_TABLE);
zend_shutdown_extensions(TSRMLS_C);
free(zend_version_info);
free(GLOBAL_FUNCTION_TABLE);
free(GLOBAL_CLASS_TABLE);
zend_hash_destroy(GLOBAL_CONSTANTS_TABLE);
free(GLOBAL_CONSTANTS_TABLE);
zend_shutdown_strtod(); #ifdef ZTS
GLOBAL_FUNCTION_TABLE = NULL;
GLOBAL_CLASS_TABLE = NULL;
GLOBAL_AUTO_GLOBALS_TABLE = NULL;
GLOBAL_CONSTANTS_TABLE = NULL;
#endif
zend_destroy_rsrc_list_dtors();
zend_interned_strings_dtor(TSRMLS_C);
}- 其中, zend_shutdown_extensions 会调用每个扩展的 shutdown 函数
调用 UNREGISTER_INI_ENTRIES, 注销 ini_entries
-
调用 php_shutdown_config, 销毁 php.ini 配置信息
int php_shutdown_config(void)
{
zend_hash_destroy(&configuration_hash);
if (php_ini_opened_path) {
free(php_ini_opened_path);
php_ini_opened_path = NULL;
}
if (php_ini_scanned_files) {
free(php_ini_scanned_files);
php_ini_scanned_files = NULL;
}
return SUCCESS;
} 销毁 zend ini 信息
-
调用 php_output_shutdown, 关闭 output
PHPAPI void php_output_shutdown(void)
{
php_output_direct = php_output_stderr;
zend_hash_destroy(&php_output_handler_aliases);
zend_hash_destroy(&php_output_handler_conflicts);
zend_hash_destroy(&php_output_handler_reverse_conflicts);
} -
释放 core_globals
static void core_globals_dtor(php_core_globals *core_globals TSRMLS_DC)
{
if (core_globals->last_error_message) {
free(core_globals->last_error_message);
}
if (core_globals->last_error_file) {
free(core_globals->last_error_file);
}
if (core_globals->disable_functions) {
free(core_globals->disable_functions);
}
if (core_globals->disable_classes) {
free(core_globals->disable_classes);
}
if (core_globals->php_binary) {
free(core_globals->php_binary);
} php_shutdown_ticks(TSRMLS_C);
} 释放垃圾回收机制
-
总结
sapi MSHUTDOWN 处理函数在 sapi MINIT 启动过程中注册
当 sapi 关闭时触发 MSHUTDOWN 过程
MSHUTDOWN 过程主要做了一下几件事:
- 刷新并清空当前 sapi 的请求
- zend 引擎功能关闭, 释放相关内存结构
- 注销, 释放, 清除 php 模块相关结构
- ini_entry
- php.ini 配置信息
- zend_ini 信息
- 内存管理
- output 输出关闭
- 全局变量以及结构
- 垃圾回收机制