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 过程的更多相关文章

  1. php 启动过程 - sapi MINIT 过程

    php 启动过程 - sapi MINIT 过程 sapi 概念 sapi 是 php 的应用编程接口, server 端接收请求通过 sapi 接口层交给 php 处理 不同的 server 端底层 ...

  2. php 启动过程 - reqeust RSHUTDOWN 过程

    php 启动过程 - reqeust RSHUTDOWN 过程 概述 request RSHUTDOWN 过程在请求结束后调用 调用触发 同 request RINIT 过程一样, 先是用 apach ...

  3. php 启动过程 - reqeust RINIT 过程

    php 启动过程 - reqeust RINIT 过程 概述 apache 接收到请求之后, 交给 php 处理 php 模块在接收到请求后, 会对请求进行初始化, 及 RINIT 过程 调用触发 a ...

  4. SpringBoot IoC启动流程、初始化过程及Bean生命周期各个阶段的作用

    目录 SpringBoot IoC启动流程.初始化过程及Bean生命周期各个阶段的作用 简述 首先明确IoC容器是啥 准备-SpringApplication的实例化 启动-SpringApplica ...

  5. 第三次作业(1) Visual Studio程序安装过程和练习过程

    Visual Studio程序安装过程和练习过程 第一步 首先要在网上找一个VS2013的安装包,之后我安装在D盘上,C盘上也需要有5.2G空间,勾选相应的选项,才能继续安装. 安装的过程很漫长,接近 ...

  6. Atitit. 软件开发中的管理哲学--一个伟大的事业必然是过程导向为主 过程导向 vs 结果导向

    Atitit. 软件开发中的管理哲学--一个伟大的事业必然是过程导向为主    过程导向 vs 结果导向 1. 一个伟大的事业必然是过程导向为主 1 1.1. 过程的执行情况(有明确的执行手册及标准) ...

  7. VScript 函数调用的两种分类:Sub过程和Function过程

    来源:http://soft.zdnet.com.cn/software_zone/2007/0925/523318.shtml 在 VBScript 中,过程被分为两类:Sub 过程和 Functi ...

  8. Oracle数据库体系结构、启动过程、关闭过程

    一.Oracle数据库体系结构体系结构由下面组件组成:1.Oracle服务器(Server):由数据库实例和数据库文件组成,另外在用户建立与服务器的连接时启动服务器进程并分配PGA(程序全局区) (1 ...

  9. iOS开发实践:一个类微博客户端从启动到与用户交互的过程

    本文基于数据字典和数据流图两种工具讲述一个完整微博客户端的实现.数据字典和数据流图都可以用来表达线程的执行流程,同时定义了需要的类,是进一步设计类的基础. 数据字典实际上是一张表,表的第一个字段是程序 ...

随机推荐

  1. TypeScript设计模式之门面、适配器

    看看用TypeScript怎样实现常见的设计模式,顺便复习一下. 学模式最重要的不是记UML,而是知道什么模式可以解决什么样的问题,在做项目时碰到问题可以想到用哪个模式可以解决,UML忘了可以查,思想 ...

  2. [LeetCode]Rotate Image(矩阵旋转)

    48. Rotate Image     Total Accepted: 69437 Total Submissions: 198781 Difficulty: Medium You are give ...

  3. Maven settings.xml配置解读

    本文对${maven.home}\conf\settings.xml的官方文档作个简单的解读,请确保自己的maven环境安装成功,具体安装流程详见Maven安装 第一步:看settings.xml的内 ...

  4. cocos studio UI 1.6.0.0 修改导出项目路径

    因为cocos studio UI 1.6.0.0版本没有自动修改默认导出路径的功能,新建项目后默认导出的路径还是上一个项目的,每次导出都要重新设置路径很麻烦.于是考虑是否可以找到默认配置文件,终于还 ...

  5. STC-单片机控制系统

    电源测量命令 60V开 FD02060001010100000060V关 FD02060002010100000060V保开 60V保关 -8KV开 -8KV关 FD02092802010201000 ...

  6. SQL语句流程函数

    本人因为今天用到了流程函数,顿时感觉语法生疏啊,为了防止以后忘记,故写此篇!!! 流程函数是MySQL相对常用的一类函数, 用户可以使用这类函数在一个SQL语句中实现条件选择, 这样能够提高效率. 下 ...

  7. Maven项目搭建(一):Maven初体验

    今天给大家介绍一个项目管理和综合工具:Maven. Maven: maven读作 ['meivin],本意是指可以被信任的领域专家,致力于传播知识(来自于http://en.wikipedia.org ...

  8. commonJS的核心思想

    服务器端的 Node.js 遵循 CommonJS规范,该规范的核心思想是允许模块通过 require 方法来同步加载所要依赖的其他模块,然后通过 exports 或 module.exports 来 ...

  9. Windows7 java-jdk1.7安装及设置变量过程

    jdk安装的次数较少,容易忘记,这里专门记录一下. 1:jdk1.7网上到处都是可以随便下载一个.然后进行安装,不过在安装过程中把安装路径单独记忆一下,在配置变量的时候会用到. 2:安装完JDK后配置 ...

  10. 标准之路网站上一篇文章《十天学会web标准(div+css)》的营养精华

    以下精华出自如下链接,“http://www.aa25.cn/special/10day/index.shtml”,<十天学会web标准(DIV+CSS)>. 这个内容不要删掉:“< ...