php 启动过程 - sapi MSHUTDOWN 过程
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 输出关闭
- 全局变量以及结构
- 垃圾回收机制
php 启动过程 - sapi MSHUTDOWN 过程的更多相关文章
- php 启动过程 - sapi MINIT 过程
php 启动过程 - sapi MINIT 过程 sapi 概念 sapi 是 php 的应用编程接口, server 端接收请求通过 sapi 接口层交给 php 处理 不同的 server 端底层 ...
- php 启动过程 - reqeust RSHUTDOWN 过程
php 启动过程 - reqeust RSHUTDOWN 过程 概述 request RSHUTDOWN 过程在请求结束后调用 调用触发 同 request RINIT 过程一样, 先是用 apach ...
- php 启动过程 - reqeust RINIT 过程
php 启动过程 - reqeust RINIT 过程 概述 apache 接收到请求之后, 交给 php 处理 php 模块在接收到请求后, 会对请求进行初始化, 及 RINIT 过程 调用触发 a ...
- SpringBoot IoC启动流程、初始化过程及Bean生命周期各个阶段的作用
目录 SpringBoot IoC启动流程.初始化过程及Bean生命周期各个阶段的作用 简述 首先明确IoC容器是啥 准备-SpringApplication的实例化 启动-SpringApplica ...
- 第三次作业(1) Visual Studio程序安装过程和练习过程
Visual Studio程序安装过程和练习过程 第一步 首先要在网上找一个VS2013的安装包,之后我安装在D盘上,C盘上也需要有5.2G空间,勾选相应的选项,才能继续安装. 安装的过程很漫长,接近 ...
- Atitit. 软件开发中的管理哲学--一个伟大的事业必然是过程导向为主 过程导向 vs 结果导向
Atitit. 软件开发中的管理哲学--一个伟大的事业必然是过程导向为主 过程导向 vs 结果导向 1. 一个伟大的事业必然是过程导向为主 1 1.1. 过程的执行情况(有明确的执行手册及标准) ...
- VScript 函数调用的两种分类:Sub过程和Function过程
来源:http://soft.zdnet.com.cn/software_zone/2007/0925/523318.shtml 在 VBScript 中,过程被分为两类:Sub 过程和 Functi ...
- Oracle数据库体系结构、启动过程、关闭过程
一.Oracle数据库体系结构体系结构由下面组件组成:1.Oracle服务器(Server):由数据库实例和数据库文件组成,另外在用户建立与服务器的连接时启动服务器进程并分配PGA(程序全局区) (1 ...
- iOS开发实践:一个类微博客户端从启动到与用户交互的过程
本文基于数据字典和数据流图两种工具讲述一个完整微博客户端的实现.数据字典和数据流图都可以用来表达线程的执行流程,同时定义了需要的类,是进一步设计类的基础. 数据字典实际上是一张表,表的第一个字段是程序 ...
随机推荐
- noscript 标签,一个被忽视的重要标签
打开 Drupal 的新后台,发现显示大面积空白 .本以为是 CSS 的问题,后来折腾好久才发现是我之前因为某些站的安全问题把浏览器的 Javascript 给禁用了.Javascript 的日益强大 ...
- 学习H5一周随笔
H5学习也已经进行了一个周了,除了学习过程中的乱哄哄的脑子,对H5初学者(我)常见的问题有了如下见解. 1.初学者在建立新的Html文件之后,有时候会把 <meta charset=" ...
- 利用内核cgroup机制轻松实现类似docker的系统资源管控
近几年,以docker为代表的容器技术异常火热,它的轻量.高效让人欣喜若狂,它被赋予了改变传统IT运维的使命.相信随着时间推移,以容器云为落地形式的产品将真正实现这一使命. 我们都知道docker能够 ...
- 读书笔记 effective c++ Item 31 把文件之间的编译依赖降到最低
1. 牵一发而动全身 现在开始进入你的C++程序,你对你的类实现做了一个很小的改动.注意,不是接口,只是实现:一个私有的stuff.然后你需要rebuild你的程序,计算着这个build应该几秒钟就足 ...
- 1682: [Usaco2005 Mar]Out of Hay 干草危机
1682: [Usaco2005 Mar]Out of Hay 干草危机 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 391 Solved: 258[ ...
- Markdown语法讲解及MWeb使用教程
写了一个月的博客,忽然感觉Markdown编辑器比较好用,于是就下载了一个本地的Markdown编辑软件学习了一下,刚好软件里自带了一篇英文的指示文档,顺便翻译了一下,通过这个过程也大致熟悉了Mark ...
- 关于PHP单双引号解析变量的问题
双引号可以解析变量,单引号不行 $qweqwe = 123; echo "$qweqwe"; 输出123 echo '$qweqqwe'; 输出$qweqwe
- C++—this指针的用法
this指针抽象比喻 当我们在进入一个房子之后, 可以看见房子里的桌子,椅子. 地板等,但是看不到房子的全貌.对于一个类的实例来说, 你可以看到它的成员 函数. 成员 变量, 但是实例本身呢? thi ...
- springmvc基础学习3---注解简单理解
1:@Controller 用来注解这个bean是MVC模型中的一个C 会被spring的auto-scan扫到纳入管理.Spring mvc框架中的action层注入,也就是控制层.控制器Contr ...
- WebSocket数据包协议详解
其实我一直想不明白HTML5包装个应用层办议作为Socket通过基础目的是为了什么,其实直接支持Socket tcp相对来说更加简单灵活.既然标准已经制定而浏览器也支持那对于我们开发者来说只能用的分. ...