diff options
author | Dmitry Stogov <dmitry@zend.com> | 2017-06-22 01:45:28 +0300 |
---|---|---|
committer | Dmitry Stogov <dmitry@zend.com> | 2017-06-22 01:45:28 +0300 |
commit | f25ecdacf805f840f743b67b6d84485b2deceb4f (patch) | |
tree | f8f6c7606287b952dcdf51e2ee9f528606bb9a2c /Zend/zend_execute_API.c | |
parent | 9fb0e6ffe29cc37b6b84a093d7438f0453cc1c41 (diff) | |
download | php-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.c | 206 |
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; } |