php 啓動過程 - sapi MSHUTDOWN 過程

php 啓動過程 - sapi MSHUTDOWN 過程

概述

當服務器關閉時, 會走到 sapi MSHUTDOWN 過程php

註冊過程

本次內容是在 php 啓動過程 - sapi MINIT 過程 以後寫的, 對於調用過程本次只作簡單描述apache

  • apache 加載 php 模塊, apache 啓動時調用註冊的鉤子函數 php_apache_server_startup
  • php_apache_server_startup 中使用 apr_pool_cleanup_register 函數註冊模塊關閉函數 php_apache_server_shutdown

MSHUTDOWN 調用過程

  • 調用 php_apache_server_shutdownapi

    • 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_flushapp

          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 引擎運行過程當中產生的數據以及結構code

          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_entriesserver

        • 調用 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 輸出關閉
    • 全局變量以及結構
    • 垃圾回收機制
相關文章
相關標籤/搜索