Skip to content

Commit

Permalink
shutdown_executor() refactoring (reuse opcache fast request shutdown …
Browse files Browse the repository at this point in the history
…code)
  • Loading branch information
dstogov committed Jun 21, 2017
1 parent 9fb0e6f commit f25ecda
Show file tree
Hide file tree
Showing 14 changed files with 158 additions and 459 deletions.
25 changes: 0 additions & 25 deletions Zend/zend.c
Original file line number Diff line number Diff line change
Expand Up @@ -903,31 +903,6 @@ void zend_post_startup(void) /* {{{ */
void zend_shutdown(void) /* {{{ */
{
zend_destroy_rsrc_list(&EG(persistent_list));
if (EG(active))
{
/*
* The order of destruction is important here.
* See bugs #65463 and 66036.
*/
zend_function *func;
zend_class_entry *ce;

ZEND_HASH_REVERSE_FOREACH_PTR(GLOBAL_FUNCTION_TABLE, func) {
if (func->type == ZEND_USER_FUNCTION) {
zend_cleanup_op_array_data((zend_op_array *) func);
}
} ZEND_HASH_FOREACH_END();
ZEND_HASH_REVERSE_FOREACH_PTR(GLOBAL_CLASS_TABLE, ce) {
if (ce->type == ZEND_USER_CLASS) {
zend_cleanup_user_class_data(ce);
} else {
break;
}
} ZEND_HASH_FOREACH_END();
zend_cleanup_internal_classes();
zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) clean_non_persistent_function_full);
zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) clean_non_persistent_class_full);
}
zend_destroy_modules();

virtual_cwd_deactivate();
Expand Down
4 changes: 0 additions & 4 deletions Zend/zend_compile.h
Original file line number Diff line number Diff line change
Expand Up @@ -779,12 +779,8 @@ ZEND_API int open_file_for_scanning(zend_file_handle *file_handle);
ZEND_API void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size);
ZEND_API void destroy_op_array(zend_op_array *op_array);
ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle);
ZEND_API void zend_cleanup_user_class_data(zend_class_entry *ce);
ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce);
ZEND_API void zend_cleanup_internal_classes(void);
ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array);
ZEND_API int clean_non_persistent_function_full(zval *zv);
ZEND_API int clean_non_persistent_class_full(zval *zv);

ZEND_API void destroy_zend_function(zend_function *function);
ZEND_API void zend_function_dtor(zval *zv);
Expand Down
24 changes: 0 additions & 24 deletions Zend/zend_constants.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,20 +69,6 @@ void zend_copy_constants(HashTable *target, HashTable *source)
}


static int clean_non_persistent_constant(zval *zv)
{
zend_constant *c = Z_PTR_P(zv);
return (c->flags & CONST_PERSISTENT) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE;
}


static int clean_non_persistent_constant_full(zval *zv)
{
zend_constant *c = Z_PTR_P(zv);
return (c->flags & CONST_PERSISTENT) ? 0 : 1;
}


static int clean_module_constant(zval *el, void *arg)
{
zend_constant *c = (zend_constant *)Z_PTR_P(el);
Expand Down Expand Up @@ -152,16 +138,6 @@ int zend_shutdown_constants(void)
return SUCCESS;
}


void clean_non_persistent_constants(void)
{
if (EG(full_tables_cleanup)) {
zend_hash_apply(EG(zend_constants), clean_non_persistent_constant_full);
} else {
zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant);
}
}

ZEND_API void zend_register_null_constant(const char *name, size_t name_len, int flags, int module_number)
{
zend_constant c;
Expand Down
1 change: 0 additions & 1 deletion Zend/zend_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ void free_zend_constant(zval *zv);
int zend_startup_constants(void);
int zend_shutdown_constants(void);
void zend_register_standard_constants(void);
void clean_non_persistent_constants(void);
ZEND_API int zend_verify_const_access(zend_class_constant *c, zend_class_entry *ce);
ZEND_API zval *zend_get_constant(zend_string *name);
ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len);
Expand Down
206 changes: 95 additions & 111 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -253,136 +246,124 @@ 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)) {
zend_hash_destroy(*EG(symtable_cache_ptr));
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));

Expand All @@ -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)) {
Expand All @@ -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;
}
Expand Down
Loading

0 comments on commit f25ecda

Please sign in to comment.