大粨兔奶糖

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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 输出关闭
    • 全局变量以及结构
    • 垃圾回收机制
posted on 2017-04-07 11:00  大粨兔奶糖  阅读(245)  评论(0)    收藏  举报