大粨兔奶糖

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

php 启动过程 - reqeust RSHUTDOWN 过程

概述

request RSHUTDOWN 过程在请求结束后调用

调用触发

  • 同 request RINIT 过程一样, 先是用 apache 注册的钩子函数 php_handler 处理请求
  • 执行 request RINIT 过程
  • 执行 request execute 过程
  • 调用 php_apache_request_dtor 开始进行 request RSHUTDOWN 过程

调用过程

  • php_handler 处理完请求后, 调用 php_apache_request_dtor 函数进行 request RSHUTDOWN 过程

    • static int php_handler(request_rec *r)
      {
      	// 省略 ...
      
      	if (!parent_req) {
      		// 销毁释放请求
      		php_apache_request_dtor(r TSRMLS_CC);
      		ctx->request_processed = 1;
      		bucket = apr_bucket_eos_create(r->connection->bucket_alloc);
      		APR_BRIGADE_INSERT_TAIL(brigade, bucket);
      
      		rv = ap_pass_brigade(r->output_filters, brigade);
      		if (rv != APR_SUCCESS || r->connection->aborted) {
      zend_first_try {
      			php_handle_aborted_connection();
      } zend_end_try();
      		}
      		apr_brigade_cleanup(brigade);
      		apr_pool_cleanup_run(r->pool, (void *)&SG(server_context), php_server_context_cleanup);
      	} else {
      		ctx->r = parent_req;
      	}
      
      	return OK;
      }
      
    • 调用 php_apache_request_dtor

      static void php_apache_request_dtor(request_rec *r TSRMLS_DC)
      {
      	php_request_shutdown(NULL);
      }
      
      • 调用 php_request_shutdown 函数

        • void php_request_shutdown(void *dummy)
          {
          	zend_bool report_memleaks;
          	TSRMLS_FETCH();
          	// 内存泄漏信息
          	report_memleaks = PG(report_memleaks);
          	// 设置 opcode 执行相关变量为空
          	EG(opline_ptr) = NULL;
          	EG(active_op_array) = NULL;
          	// 销毁 tick 相关
          	php_deactivate_ticks(TSRMLS_C);
          	// 调用 register_shutdown_function 注册的 shutdown 函数
          	if (PG(modules_activated)) zend_try {
          		php_call_shutdown_functions(TSRMLS_C);
          	} zend_end_try();
          	// 调用析构函数
          	zend_try {
          		zend_call_destructors(TSRMLS_C);
          	} zend_end_try();
          	// flush 输出缓冲区
          	zend_try {
          		zend_bool send_buffer = SG(request_info).headers_only ? 0 : 1;
          
          		if (CG(unclean_shutdown) && PG(last_error_type) == E_ERROR &&
          			(size_t)PG(memory_limit) < zend_memory_usage(1 TSRMLS_CC)
          		) {
          			send_buffer = 0;
          		}
          
          		if (!send_buffer) {
          			php_output_discard_all(TSRMLS_C);
          		} else {
          			php_output_end_all(TSRMLS_C);
          		}
          	} zend_end_try();
          	// 重置 max_execution_time
          	zend_try {
          		zend_unset_timeout(TSRMLS_C);
          	} zend_end_try();
          	// 调用各子模块的 RSHUTDOWN 函数
          	if (PG(modules_activated)) {
          		zend_deactivate_modules(TSRMLS_C);
          		php_free_shutdown_functions(TSRMLS_C);
          	}
          	// 关闭 output
          	zend_try {
          		php_output_deactivate(TSRMLS_C);
          	} zend_end_try();
          	// 销毁 PG(http_globals)
          	zend_try {
          		int i;
          
          		for (i=0; i<NUM_TRACK_VARS; i++) {
          			if (PG(http_globals)[i]) {
          				zval_ptr_dtor(&PG(http_globals)[i]);
          			}
          		}
          	} zend_end_try();
          	// 释放错误信息
          	if (PG(last_error_message)) {
          		free(PG(last_error_message));
          		PG(last_error_message) = NULL;
          	}
          	if (PG(last_error_file)) {
          		free(PG(last_error_file));
          		PG(last_error_file) = NULL;
          	}
          	// 关闭临时目录
          	php_shutdown_temporary_directory();
          	// 关闭 扫描器, 执行器, 编译器, 初始化 ini_entries
          	zend_deactivate(TSRMLS_C);
          	// 调用各子模块的 post_deactivate_func 函数
          	zend_try {
          		zend_post_deactivate_modules(TSRMLS_C);
          	} zend_end_try();
          	// 关闭 sapi
          	zend_try {
          		sapi_deactivate(TSRMLS_C);
          	} zend_end_try();
          
          	/* 10. Destroy stream hashes */
          	zend_try {
          		php_shutdown_stream_hashes(TSRMLS_C);
          	} zend_end_try();
          	// 关闭内存管理器
          	zend_try {
          		shutdown_memory_manager(CG(unclean_shutdown) || !report_memleaks, 0 TSRMLS_CC);
          	} zend_end_try();
          	zend_interned_strings_restore(TSRMLS_C);
          	// 重置 max_execution_time
          	zend_try {
          		zend_unset_timeout(TSRMLS_C);
          	} zend_end_try();
          
          #ifdef PHP_WIN32
          	if (PG(com_initialized)) {
          		CoUninitialize();
          		PG(com_initialized) = 0;
          	}
          #endif
          
          #ifdef HAVE_DTRACE
          	DTRACE_REQUEST_SHUTDOWN(SAFE_FILENAME(SG(request_info).path_translated), SAFE_FILENAME(SG(request_info).request_uri), (char *)SAFE_FILENAME(SG(request_info).request_method));
          #endif /* HAVE_DTRACE */
          }
          
        • php_call_shutdown_functions, 调用 register_shutdown_function 注册的 shutdown 函数

          void php_call_shutdown_functions(TSRMLS_D)
          {
          	if (BG(user_shutdown_function_names)) {
          		zend_try {
          			zend_hash_apply(BG(user_shutdown_function_names), (apply_func_t) user_shutdown_function_call TSRMLS_CC);
          		}
          		zend_end_try();
          		php_free_shutdown_functions(TSRMLS_C);
          	}
          }
          
          • 调用 zend_hash_apply, 实际上是对 BG(user_shutdown_function_names) 循环调用 user_shutdown_function_call 函数

            • ZEND_API void zend_hash_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC)
              {
              	Bucket *p;
              
              	IS_CONSISTENT(ht);
              
              	HASH_PROTECT_RECURSION(ht);
              	p = ht->pListHead;
              	while (p != NULL) {
              		int result = apply_func(p->pData TSRMLS_CC);
              		
              		if (result & ZEND_HASH_APPLY_REMOVE) {
              			p = zend_hash_apply_deleter(ht, p);
              		} else {
              			p = p->pListNext;
              		}
              		if (result & ZEND_HASH_APPLY_STOP) {
              			break;
              		}
              	}
              	HASH_UNPROTECT_RECURSION(ht);
              }
              
            • user_shutdown_function_call 函数

              static int user_shutdown_function_call(php_shutdown_function_entry *shutdown_function_entry TSRMLS_DC)
              {
              	zval retval;
              	char *function_name;
              
              	if (!zend_is_callable(shutdown_function_entry->arguments[0], 0, &function_name TSRMLS_CC)) {
              		php_error(E_WARNING, "(Registered shutdown functions) Unable to call %s() - function does not exist", function_name);
              		if (function_name) {
              			efree(function_name);
              		}
              		return 0;
              	}
              	if (function_name) {
              		efree(function_name);
              	}
              
              	if (call_user_function(EG(function_table), NULL,
              				shutdown_function_entry->arguments[0],
              				&retval,
              				shutdown_function_entry->arg_count - 1,
              				shutdown_function_entry->arguments + 1
              				TSRMLS_CC ) == SUCCESS)
              	{
              		zval_dtor(&retval);
              	}
              	return 0;
              }
              
        • zend_call_destructors, 调用各变量的析构函数 __destruct

          void zend_call_destructors(TSRMLS_D)
          {
          	zend_try {
          		shutdown_destructors(TSRMLS_C);
          	} zend_end_try();
          }
          
          • 调用 shutdown_destructors 函数

            • void shutdown_destructors(TSRMLS_D) /* {{{ */
              {
              	zend_try {
              		int symbols;
              		do {
              			symbols = zend_hash_num_elements(&EG(symbol_table));
              			zend_hash_reverse_apply(&EG(symbol_table), (apply_func_t) zval_call_destructor TSRMLS_CC);
              		} while (symbols != zend_hash_num_elements(&EG(symbol_table)));
              		zend_objects_store_call_destructors(&EG(objects_store) TSRMLS_CC);
              	} zend_catch {
              		/* if we couldn't destruct cleanly, mark all objects as destructed anyway */
              		zend_objects_store_mark_destructed(&EG(objects_store) TSRMLS_CC);
              	} zend_end_try();
              }
              
            • zend_hash_reverse_apply 对 EG(symbol_table) 循环调用 zval_call_destructor 函数

              static int zval_call_destructor(zval **zv TSRMLS_DC)
              {
              	if (Z_TYPE_PP(zv) == IS_OBJECT && Z_REFCOUNT_PP(zv) == 1) {
              		return ZEND_HASH_APPLY_REMOVE;
              	} else {
              		return ZEND_HASH_APPLY_KEEP;
              	}
              }
              
            • 调用 zend_objects_store_call_destructors, 调用各变量的析构函数

              ZEND_API void zend_objects_store_call_destructors(zend_objects_store *objects TSRMLS_DC)
              {
              	zend_uint i = 1;
              
              	for (i = 1; i < objects->top ; i++) {
              		if (objects->object_buckets[i].valid) {
              			struct _store_object *obj = &objects->object_buckets[i].bucket.obj;
              
              			if (!objects->object_buckets[i].destructor_called) {
              				objects->object_buckets[i].destructor_called = 1;
              				if (obj->dtor && obj->object) {
              					obj->refcount++;
              					// 调用析构函数
              					obj->dtor(obj->object, i TSRMLS_CC);
              					obj = &objects->object_buckets[i].bucket.obj;
              					obj->refcount--;
              
              					if (obj->refcount == 0) {
              						GC_REMOVE_ZOBJ_FROM_BUFFER(obj);
              					}
              				}
              			}
              		}
              	}
              }
              
        • php_output_discard_all 或者 php_output_end_all, flush 输出缓冲区 (在后续对输出功能做讲解时在详细展开)

        • zend_deactivate_modules, 调用各子模块的 RSHUTDOWN 函数

          void zend_deactivate_modules(TSRMLS_D)
          {
          	EG(opline_ptr) = NULL; /* we're no longer executing anything */
          
          	zend_try {
          		if (EG(full_tables_cleanup)) {
          			// 若全部清除, 则对 module_registry 循环调用 module_registry_cleanup 来循环调用 各子模块的 request_shutdown_func 函数
          			zend_hash_reverse_apply(&module_registry, (apply_func_t) module_registry_cleanup TSRMLS_CC);
          		} else {
          			zend_module_entry **p = module_request_shutdown_handlers;
          
          			while (*p) {
          				zend_module_entry *module = *p;
          				// 循环调用各子模块的 request_shutdown_func 函数
          				module->request_shutdown_func(module->type, module->module_number TSRMLS_CC);
          				p++;
          			}
          		}
          	} zend_end_try();
          }
          
        • php_output_deactivate, 关闭 output, 释放所有 handler

          PHPAPI void php_output_deactivate(TSRMLS_D)
          {
          	php_output_handler **handler = NULL;
          
          	if ((OG(flags) & PHP_OUTPUT_ACTIVATED)) {
          		php_output_header(TSRMLS_C);
          
          		OG(flags) ^= PHP_OUTPUT_ACTIVATED;
          		OG(active) = NULL;
          		OG(running) = NULL;
          		// 释放 handlers
          		if (OG(handlers).elements) {
          			while (SUCCESS == zend_stack_top(&OG(handlers), (void *) &handler)) {
          				php_output_handler_free(handler TSRMLS_CC);
          				zend_stack_del_top(&OG(handlers));
          			}
          			zend_stack_destroy(&OG(handlers));
          		}
          	}
          }
          
        • 销毁超全局变量

          	zend_try {
          		int i;
          		// 循环释放 PG(http_globals)
          		for (i=0; i<NUM_TRACK_VARS; i++) {
          			if (PG(http_globals)[i]) {
          				zval_ptr_dtor(&PG(http_globals)[i]);
          			}
          		}
          	} zend_end_try();
          
        • zend_deactivate, 关闭扫描器, 执行器, 编译器, 重置 ini_entries

          void zend_deactivate(TSRMLS_D)
          {
          	/* we're no longer executing anything */
          	EG(opline_ptr) = NULL;
          	EG(active_symbol_table) = NULL;
          
          	zend_try {
          		shutdown_scanner(TSRMLS_C);
          	} zend_end_try();
          
          	// 调用各扩展的 deactivate 方法
          	shutdown_executor(TSRMLS_C);
          
          	zend_try {
          		// 销毁编译器
          		shutdown_compiler(TSRMLS_C);
          	} zend_end_try();
          
          	zend_destroy_rsrc_list(&EG(regular_list) TSRMLS_CC);
          
          #ifdef ZEND_DEBUG
          	if (GC_G(gc_enabled) && !CG(unclean_shutdown)) {
          		gc_collect_cycles(TSRMLS_C);
          	}
          #endif
          
          #if GC_BENCH
          	fprintf(stderr, "GC Statistics\n");
          	fprintf(stderr, "-------------\n");
          	fprintf(stderr, "Runs:               %d\n", GC_G(gc_runs));
          	fprintf(stderr, "Collected:          %d\n", GC_G(collected));
          	fprintf(stderr, "Root buffer length: %d\n", GC_G(root_buf_length));
          	fprintf(stderr, "Root buffer peak:   %d\n\n", GC_G(root_buf_peak));
          	fprintf(stderr, "      Possible            Remove from  Marked\n");
          	fprintf(stderr, "        Root    Buffered     buffer     grey\n");
          	fprintf(stderr, "      --------  --------  -----------  ------\n");
          	fprintf(stderr, "ZVAL  %8d  %8d  %9d  %8d\n", GC_G(zval_possible_root), GC_G(zval_buffered), GC_G(zval_remove_from_buffer), GC_G(zval_marked_grey));
          	fprintf(stderr, "ZOBJ  %8d  %8d  %9d  %8d\n", GC_G(zobj_possible_root), GC_G(zobj_buffered), GC_G(zobj_remove_from_buffer), GC_G(zobj_marked_grey));
          #endif
          
          	zend_try {
          		// 调用 zend_ini_entry 的 on_modify 函数
          		// 释放 ini_entry 的值
          		zend_ini_deactivate(TSRMLS_C);
          	} zend_end_try();
          }
          
        • zend_post_deactivate_modules, 调用各子模块的 post_deactivate_func 函数

          void zend_post_deactivate_modules(TSRMLS_D)
          {
          	if (EG(full_tables_cleanup)) {
          		zend_hash_apply(&module_registry, (apply_func_t) exec_done_cb TSRMLS_CC);
          		zend_hash_reverse_apply(&module_registry, (apply_func_t) module_registry_unload_temp TSRMLS_CC);
          	} else {
          		zend_module_entry **p = module_post_deactivate_handlers;
          		// 循环调用各模块的 post_deactivate_func 函数
          		while (*p) {
          			zend_module_entry *module = *p;
          			module->post_deactivate_func();
          			p++;
          		}
          	}
          }
          
        • sapi_deactivate, 关闭 sapi, 释放 sapi 相关的结构体

        • shutdown_memory_manager, 关闭内存管理器

总结

request RSHUTDOWN 过程在每次请求结束后均会调用

主要做的事情是销毁请求执行过程中的一些内存使用

  • 调用 register_shutdown_function 注册的函数
  • 调用 __destruction 函数
  • flush 输出缓存
  • 调用各扩展的 RSHUTDOWN 函数
  • 关闭 php 输出
  • 销毁超全局数组
  • 释放扫描器, 执行器, 编译器, ini_entries
  • 调用各扩展的 post_deactivate_func 函数
  • 关闭 sapi
  • 关闭内存管理器
posted on 2017-04-10 08:09  大粨兔奶糖  阅读(339)  评论(0)    收藏  举报