summaryrefslogtreecommitdiff
path: root/Zend/zend_execute_API.c
diff options
context:
space:
mode:
authorDmitry Stogov <dmitry@zend.com>2017-06-22 01:45:28 +0300
committerDmitry Stogov <dmitry@zend.com>2017-06-22 01:45:28 +0300
commitf25ecdacf805f840f743b67b6d84485b2deceb4f (patch)
treef8f6c7606287b952dcdf51e2ee9f528606bb9a2c /Zend/zend_execute_API.c
parent9fb0e6ffe29cc37b6b84a093d7438f0453cc1c41 (diff)
downloadphp-git-f25ecdacf805f840f743b67b6d84485b2deceb4f.tar.gz
shutdown_executor() refactoring (reuse opcache fast request shutdown code)
Diffstat (limited to 'Zend/zend_execute_API.c')
-rw-r--r--Zend/zend_execute_API.c206
1 files changed, 95 insertions, 111 deletions
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index ef29546ac0..3c453e64ef 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -100,28 +100,21 @@ static void zend_extension_deactivator(zend_extension *extension) /* {{{ */
}
/* }}} */
-static int clean_non_persistent_function(zval *zv) /* {{{ */
+static int clean_non_persistent_constant_full(zval *zv) /* {{{ */
{
- zend_function *function = Z_PTR_P(zv);
- return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE;
+ zend_constant *c = Z_PTR_P(zv);
+ return (c->flags & CONST_PERSISTENT) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
}
/* }}} */
-ZEND_API int clean_non_persistent_function_full(zval *zv) /* {{{ */
+static int clean_non_persistent_function_full(zval *zv) /* {{{ */
{
zend_function *function = Z_PTR_P(zv);
return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
}
/* }}} */
-static int clean_non_persistent_class(zval *zv) /* {{{ */
-{
- zend_class_entry *ce = Z_PTR_P(zv);
- return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE;
-}
-/* }}} */
-
-ZEND_API int clean_non_persistent_class_full(zval *zv) /* {{{ */
+static int clean_non_persistent_class_full(zval *zv) /* {{{ */
{
zend_class_entry *ce = Z_PTR_P(zv);
return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
@@ -253,123 +246,117 @@ void shutdown_destructors(void) /* {{{ */
void shutdown_executor(void) /* {{{ */
{
- zend_function *func;
- zend_class_entry *ce;
+ zend_string *key;
+ zval *zv;
+#if ZEND_DEBUG
+ zend_bool fast_shutdown = 0;
+#else
+ zend_bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup);
+#endif
zend_try {
+ zend_llist_destroy(&CG(open_files));
+ } zend_end_try();
-/* Removed because this can not be safely done, e.g. in this situation:
- Object 1 creates object 2
- Object 3 holds reference to object 2.
- Now when 1 and 2 are destroyed, 3 can still access 2 in its destructor, with
- very problematic results */
-/* zend_objects_store_call_destructors(&EG(objects_store)); */
+ zend_try {
+ zend_close_rsrc_list(&EG(regular_list));
+ } zend_end_try();
-/* Moved after symbol table cleaners, because some of the cleaners can call
- destructors, which would use EG(symtable_cache_ptr) and thus leave leaks */
-/* while (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
- zend_hash_destroy(*EG(symtable_cache_ptr));
- efree(*EG(symtable_cache_ptr));
- EG(symtable_cache_ptr)--;
- }
-*/
- zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
+ zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown);
- zend_hash_graceful_reverse_destroy(&EG(symbol_table));
+ /* All resources and objects are destroyed. */
+ /* No PHP callback functions may be called after this point. */
+
+ zend_try {
+ zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
} zend_end_try();
+
EG(valid_symbol_table) = 0;
- zend_try {
- zval *zeh;
+ if (fast_shutdown) {
+ /* Fast Request Shutdown
+ * =====================
+ * Zend Memory Manager frees memory by its own. We don't have to free
+ * each allocated block separately.
+ */
+ ZEND_HASH_REVERSE_FOREACH_VAL(EG(zend_constants), zv) {
+ zend_constant *c = Z_PTR_P(zv);
+ if (c->flags & CONST_PERSISTENT) {
+ break;
+ }
+ } ZEND_HASH_FOREACH_END_DEL();
+ ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) {
+ zend_function *func = Z_PTR_P(zv);
+ if (func->type == ZEND_INTERNAL_FUNCTION) {
+ break;
+ }
+ } ZEND_HASH_FOREACH_END_DEL();
+ ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
+ zend_class_entry *ce = Z_PTR_P(zv);
+ if (ce->type == ZEND_INTERNAL_CLASS) {
+ break;
+ }
+ } ZEND_HASH_FOREACH_END_DEL();
+ } else {
+ zend_hash_graceful_reverse_destroy(&EG(symbol_table));
+
+#if ZEND_DEBUG
+ if (GC_G(gc_enabled) && !CG(unclean_shutdown)) {
+ gc_collect_cycles();
+ }
+#endif
+
/* remove error handlers before destroying classes and functions,
* so that if handler used some class, crash would not happen */
if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
- zeh = &EG(user_error_handler);
- zval_ptr_dtor(zeh);
+ zval_ptr_dtor(&EG(user_error_handler));
ZVAL_UNDEF(&EG(user_error_handler));
}
if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
- zeh = &EG(user_exception_handler);
- zval_ptr_dtor(zeh);
+ zval_ptr_dtor(&EG(user_exception_handler));
ZVAL_UNDEF(&EG(user_exception_handler));
}
zend_stack_clean(&EG(user_error_handlers_error_reporting), NULL, 1);
zend_stack_clean(&EG(user_error_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1);
zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1);
- } zend_end_try();
- zend_try {
- /* Cleanup static data for functions and arrays.
- * We need a separate cleanup stage because of the following problem:
- * Suppose we destroy class X, which destroys the class's function table,
- * and in the function table we have function foo() that has static $bar.
- * Now if an object of class X is assigned to $bar, its destructor will be
- * called and will fail since X's function table is in mid-destruction.
- * So we want first of all to clean up all data and then move to tables destruction.
- * Note that only run-time accessed data need to be cleaned up, pre-defined data can
- * not contain objects and thus are not probelmatic */
+ zend_vm_stack_destroy();
+
if (EG(full_tables_cleanup)) {
- ZEND_HASH_FOREACH_PTR(EG(function_table), func) {
- if (func->type == ZEND_USER_FUNCTION) {
- zend_cleanup_op_array_data((zend_op_array *) func);
+ zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant_full);
+ zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
+ zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full);
+ } else {
+ ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(zend_constants), key, zv) {
+ zend_constant *c = Z_PTR_P(zv);
+ if (c->flags & CONST_PERSISTENT) {
+ break;
}
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) {
- if (ce->type == ZEND_USER_CLASS) {
- zend_cleanup_user_class_data(ce);
- } else {
- zend_cleanup_internal_class_data(ce);
+ zval_ptr_dtor(&c->value);
+ if (c->name) {
+ zend_string_release(c->name);
}
- } ZEND_HASH_FOREACH_END();
- } else {
- ZEND_HASH_REVERSE_FOREACH_PTR(EG(function_table), func) {
- if (func->type != ZEND_USER_FUNCTION) {
+ efree(c);
+ zend_string_release(key);
+ } ZEND_HASH_FOREACH_END_DEL();
+ ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(function_table), key, zv) {
+ zend_function *func = Z_PTR_P(zv);
+ if (func->type == ZEND_INTERNAL_FUNCTION) {
break;
}
- zend_cleanup_op_array_data((zend_op_array *) func);
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) {
- if (ce->type != ZEND_USER_CLASS) {
+ destroy_op_array(&func->op_array);
+ zend_string_release(key);
+ } ZEND_HASH_FOREACH_END_DEL();
+ ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
+ zend_class_entry *ce = Z_PTR_P(zv);
+ if (ce->type == ZEND_INTERNAL_CLASS) {
break;
}
- zend_cleanup_user_class_data(ce);
- } ZEND_HASH_FOREACH_END();
- zend_cleanup_internal_classes();
- }
- } zend_end_try();
-
- zend_try {
- zend_llist_destroy(&CG(open_files));
- } zend_end_try();
-
- zend_try {
- clean_non_persistent_constants();
- } zend_end_try();
-
- zend_try {
- zend_close_rsrc_list(&EG(regular_list));
- } zend_end_try();
-
-#if ZEND_DEBUG
- if (GC_G(gc_enabled) && !CG(unclean_shutdown)) {
- gc_collect_cycles();
- }
-#endif
-
- zend_try {
- zend_objects_store_free_object_storage(&EG(objects_store));
-
- zend_vm_stack_destroy();
-
- /* Destroy all op arrays */
- if (EG(full_tables_cleanup)) {
- zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
- zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full);
- } else {
- zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function);
- zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class);
+ destroy_zend_class(zv);
+ zend_string_release(key);
+ } ZEND_HASH_FOREACH_END_DEL();
}
while (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
@@ -377,12 +364,6 @@ void shutdown_executor(void) /* {{{ */
FREE_HASHTABLE(*EG(symtable_cache_ptr));
EG(symtable_cache_ptr)--;
}
- } zend_end_try();
-
- zend_try {
-#if 0&&ZEND_DEBUG
- signal(SIGSEGV, original_sigsegv_handler);
-#endif
zend_hash_destroy(&EG(included_files));
@@ -394,9 +375,11 @@ void shutdown_executor(void) /* {{{ */
zend_hash_destroy(EG(in_autoload));
FREE_HASHTABLE(EG(in_autoload));
}
- } zend_end_try();
- zend_shutdown_fpu();
+ if (EG(ht_iterators) != EG(ht_iterators_slots)) {
+ efree(EG(ht_iterators));
+ }
+ }
#if ZEND_DEBUG
if (EG(ht_iterators_used) && !CG(unclean_shutdown)) {
@@ -405,9 +388,10 @@ void shutdown_executor(void) /* {{{ */
#endif
EG(ht_iterators_used) = 0;
- if (EG(ht_iterators) != EG(ht_iterators_slots)) {
- efree(EG(ht_iterators));
- }
+
+ zend_cleanup_internal_classes();
+
+ zend_shutdown_fpu();
EG(active) = 0;
}