Skip to content

Commit f25ecda

Browse files
committed
shutdown_executor() refactoring (reuse opcache fast request shutdown code)
1 parent 9fb0e6f commit f25ecda

14 files changed

+158
-459
lines changed

Zend/zend.c

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -903,31 +903,6 @@ void zend_post_startup(void) /* {{{ */
903903
void zend_shutdown(void) /* {{{ */
904904
{
905905
zend_destroy_rsrc_list(&EG(persistent_list));
906-
if (EG(active))
907-
{
908-
/*
909-
* The order of destruction is important here.
910-
* See bugs #65463 and 66036.
911-
*/
912-
zend_function *func;
913-
zend_class_entry *ce;
914-
915-
ZEND_HASH_REVERSE_FOREACH_PTR(GLOBAL_FUNCTION_TABLE, func) {
916-
if (func->type == ZEND_USER_FUNCTION) {
917-
zend_cleanup_op_array_data((zend_op_array *) func);
918-
}
919-
} ZEND_HASH_FOREACH_END();
920-
ZEND_HASH_REVERSE_FOREACH_PTR(GLOBAL_CLASS_TABLE, ce) {
921-
if (ce->type == ZEND_USER_CLASS) {
922-
zend_cleanup_user_class_data(ce);
923-
} else {
924-
break;
925-
}
926-
} ZEND_HASH_FOREACH_END();
927-
zend_cleanup_internal_classes();
928-
zend_hash_reverse_apply(GLOBAL_FUNCTION_TABLE, (apply_func_t) clean_non_persistent_function_full);
929-
zend_hash_reverse_apply(GLOBAL_CLASS_TABLE, (apply_func_t) clean_non_persistent_class_full);
930-
}
931906
zend_destroy_modules();
932907

933908
virtual_cwd_deactivate();

Zend/zend_compile.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -779,12 +779,8 @@ ZEND_API int open_file_for_scanning(zend_file_handle *file_handle);
779779
ZEND_API void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size);
780780
ZEND_API void destroy_op_array(zend_op_array *op_array);
781781
ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle);
782-
ZEND_API void zend_cleanup_user_class_data(zend_class_entry *ce);
783782
ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce);
784783
ZEND_API void zend_cleanup_internal_classes(void);
785-
ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array);
786-
ZEND_API int clean_non_persistent_function_full(zval *zv);
787-
ZEND_API int clean_non_persistent_class_full(zval *zv);
788784

789785
ZEND_API void destroy_zend_function(zend_function *function);
790786
ZEND_API void zend_function_dtor(zval *zv);

Zend/zend_constants.c

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -69,20 +69,6 @@ void zend_copy_constants(HashTable *target, HashTable *source)
6969
}
7070

7171

72-
static int clean_non_persistent_constant(zval *zv)
73-
{
74-
zend_constant *c = Z_PTR_P(zv);
75-
return (c->flags & CONST_PERSISTENT) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE;
76-
}
77-
78-
79-
static int clean_non_persistent_constant_full(zval *zv)
80-
{
81-
zend_constant *c = Z_PTR_P(zv);
82-
return (c->flags & CONST_PERSISTENT) ? 0 : 1;
83-
}
84-
85-
8672
static int clean_module_constant(zval *el, void *arg)
8773
{
8874
zend_constant *c = (zend_constant *)Z_PTR_P(el);
@@ -152,16 +138,6 @@ int zend_shutdown_constants(void)
152138
return SUCCESS;
153139
}
154140

155-
156-
void clean_non_persistent_constants(void)
157-
{
158-
if (EG(full_tables_cleanup)) {
159-
zend_hash_apply(EG(zend_constants), clean_non_persistent_constant_full);
160-
} else {
161-
zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant);
162-
}
163-
}
164-
165141
ZEND_API void zend_register_null_constant(const char *name, size_t name_len, int flags, int module_number)
166142
{
167143
zend_constant c;

Zend/zend_constants.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ void free_zend_constant(zval *zv);
6464
int zend_startup_constants(void);
6565
int zend_shutdown_constants(void);
6666
void zend_register_standard_constants(void);
67-
void clean_non_persistent_constants(void);
6867
ZEND_API int zend_verify_const_access(zend_class_constant *c, zend_class_entry *ce);
6968
ZEND_API zval *zend_get_constant(zend_string *name);
7069
ZEND_API zval *zend_get_constant_str(const char *name, size_t name_len);

Zend/zend_execute_API.c

Lines changed: 95 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -100,28 +100,21 @@ static void zend_extension_deactivator(zend_extension *extension) /* {{{ */
100100
}
101101
/* }}} */
102102

103-
static int clean_non_persistent_function(zval *zv) /* {{{ */
103+
static int clean_non_persistent_constant_full(zval *zv) /* {{{ */
104104
{
105-
zend_function *function = Z_PTR_P(zv);
106-
return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE;
105+
zend_constant *c = Z_PTR_P(zv);
106+
return (c->flags & CONST_PERSISTENT) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
107107
}
108108
/* }}} */
109109

110-
ZEND_API int clean_non_persistent_function_full(zval *zv) /* {{{ */
110+
static int clean_non_persistent_function_full(zval *zv) /* {{{ */
111111
{
112112
zend_function *function = Z_PTR_P(zv);
113113
return (function->type == ZEND_INTERNAL_FUNCTION) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
114114
}
115115
/* }}} */
116116

117-
static int clean_non_persistent_class(zval *zv) /* {{{ */
118-
{
119-
zend_class_entry *ce = Z_PTR_P(zv);
120-
return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_STOP : ZEND_HASH_APPLY_REMOVE;
121-
}
122-
/* }}} */
123-
124-
ZEND_API int clean_non_persistent_class_full(zval *zv) /* {{{ */
117+
static int clean_non_persistent_class_full(zval *zv) /* {{{ */
125118
{
126119
zend_class_entry *ce = Z_PTR_P(zv);
127120
return (ce->type == ZEND_INTERNAL_CLASS) ? ZEND_HASH_APPLY_KEEP : ZEND_HASH_APPLY_REMOVE;
@@ -253,136 +246,124 @@ void shutdown_destructors(void) /* {{{ */
253246

254247
void shutdown_executor(void) /* {{{ */
255248
{
256-
zend_function *func;
257-
zend_class_entry *ce;
249+
zend_string *key;
250+
zval *zv;
251+
#if ZEND_DEBUG
252+
zend_bool fast_shutdown = 0;
253+
#else
254+
zend_bool fast_shutdown = is_zend_mm() && !EG(full_tables_cleanup);
255+
#endif
258256

259257
zend_try {
258+
zend_llist_destroy(&CG(open_files));
259+
} zend_end_try();
260260

261-
/* Removed because this can not be safely done, e.g. in this situation:
262-
Object 1 creates object 2
263-
Object 3 holds reference to object 2.
264-
Now when 1 and 2 are destroyed, 3 can still access 2 in its destructor, with
265-
very problematic results */
266-
/* zend_objects_store_call_destructors(&EG(objects_store)); */
261+
zend_try {
262+
zend_close_rsrc_list(&EG(regular_list));
263+
} zend_end_try();
267264

268-
/* Moved after symbol table cleaners, because some of the cleaners can call
269-
destructors, which would use EG(symtable_cache_ptr) and thus leave leaks */
270-
/* while (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
271-
zend_hash_destroy(*EG(symtable_cache_ptr));
272-
efree(*EG(symtable_cache_ptr));
273-
EG(symtable_cache_ptr)--;
274-
}
275-
*/
276-
zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
265+
zend_objects_store_free_object_storage(&EG(objects_store), fast_shutdown);
277266

278-
zend_hash_graceful_reverse_destroy(&EG(symbol_table));
267+
/* All resources and objects are destroyed. */
268+
/* No PHP callback functions may be called after this point. */
269+
270+
zend_try {
271+
zend_llist_apply(&zend_extensions, (llist_apply_func_t) zend_extension_deactivator);
279272
} zend_end_try();
273+
280274
EG(valid_symbol_table) = 0;
281275

282-
zend_try {
283-
zval *zeh;
276+
if (fast_shutdown) {
277+
/* Fast Request Shutdown
278+
* =====================
279+
* Zend Memory Manager frees memory by its own. We don't have to free
280+
* each allocated block separately.
281+
*/
282+
ZEND_HASH_REVERSE_FOREACH_VAL(EG(zend_constants), zv) {
283+
zend_constant *c = Z_PTR_P(zv);
284+
if (c->flags & CONST_PERSISTENT) {
285+
break;
286+
}
287+
} ZEND_HASH_FOREACH_END_DEL();
288+
ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) {
289+
zend_function *func = Z_PTR_P(zv);
290+
if (func->type == ZEND_INTERNAL_FUNCTION) {
291+
break;
292+
}
293+
} ZEND_HASH_FOREACH_END_DEL();
294+
ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
295+
zend_class_entry *ce = Z_PTR_P(zv);
296+
if (ce->type == ZEND_INTERNAL_CLASS) {
297+
break;
298+
}
299+
} ZEND_HASH_FOREACH_END_DEL();
300+
} else {
301+
zend_hash_graceful_reverse_destroy(&EG(symbol_table));
302+
303+
#if ZEND_DEBUG
304+
if (GC_G(gc_enabled) && !CG(unclean_shutdown)) {
305+
gc_collect_cycles();
306+
}
307+
#endif
308+
284309
/* remove error handlers before destroying classes and functions,
285310
* so that if handler used some class, crash would not happen */
286311
if (Z_TYPE(EG(user_error_handler)) != IS_UNDEF) {
287-
zeh = &EG(user_error_handler);
288-
zval_ptr_dtor(zeh);
312+
zval_ptr_dtor(&EG(user_error_handler));
289313
ZVAL_UNDEF(&EG(user_error_handler));
290314
}
291315

292316
if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
293-
zeh = &EG(user_exception_handler);
294-
zval_ptr_dtor(zeh);
317+
zval_ptr_dtor(&EG(user_exception_handler));
295318
ZVAL_UNDEF(&EG(user_exception_handler));
296319
}
297320

298321
zend_stack_clean(&EG(user_error_handlers_error_reporting), NULL, 1);
299322
zend_stack_clean(&EG(user_error_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1);
300323
zend_stack_clean(&EG(user_exception_handlers), (void (*)(void *))ZVAL_PTR_DTOR, 1);
301-
} zend_end_try();
302324

303-
zend_try {
304-
/* Cleanup static data for functions and arrays.
305-
* We need a separate cleanup stage because of the following problem:
306-
* Suppose we destroy class X, which destroys the class's function table,
307-
* and in the function table we have function foo() that has static $bar.
308-
* Now if an object of class X is assigned to $bar, its destructor will be
309-
* called and will fail since X's function table is in mid-destruction.
310-
* So we want first of all to clean up all data and then move to tables destruction.
311-
* Note that only run-time accessed data need to be cleaned up, pre-defined data can
312-
* not contain objects and thus are not probelmatic */
325+
zend_vm_stack_destroy();
326+
313327
if (EG(full_tables_cleanup)) {
314-
ZEND_HASH_FOREACH_PTR(EG(function_table), func) {
315-
if (func->type == ZEND_USER_FUNCTION) {
316-
zend_cleanup_op_array_data((zend_op_array *) func);
328+
zend_hash_reverse_apply(EG(zend_constants), clean_non_persistent_constant_full);
329+
zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
330+
zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full);
331+
} else {
332+
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(zend_constants), key, zv) {
333+
zend_constant *c = Z_PTR_P(zv);
334+
if (c->flags & CONST_PERSISTENT) {
335+
break;
317336
}
318-
} ZEND_HASH_FOREACH_END();
319-
ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) {
320-
if (ce->type == ZEND_USER_CLASS) {
321-
zend_cleanup_user_class_data(ce);
322-
} else {
323-
zend_cleanup_internal_class_data(ce);
337+
zval_ptr_dtor(&c->value);
338+
if (c->name) {
339+
zend_string_release(c->name);
324340
}
325-
} ZEND_HASH_FOREACH_END();
326-
} else {
327-
ZEND_HASH_REVERSE_FOREACH_PTR(EG(function_table), func) {
328-
if (func->type != ZEND_USER_FUNCTION) {
341+
efree(c);
342+
zend_string_release(key);
343+
} ZEND_HASH_FOREACH_END_DEL();
344+
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(function_table), key, zv) {
345+
zend_function *func = Z_PTR_P(zv);
346+
if (func->type == ZEND_INTERNAL_FUNCTION) {
329347
break;
330348
}
331-
zend_cleanup_op_array_data((zend_op_array *) func);
332-
} ZEND_HASH_FOREACH_END();
333-
ZEND_HASH_REVERSE_FOREACH_PTR(EG(class_table), ce) {
334-
if (ce->type != ZEND_USER_CLASS) {
349+
destroy_op_array(&func->op_array);
350+
zend_string_release(key);
351+
} ZEND_HASH_FOREACH_END_DEL();
352+
ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(EG(class_table), key, zv) {
353+
zend_class_entry *ce = Z_PTR_P(zv);
354+
if (ce->type == ZEND_INTERNAL_CLASS) {
335355
break;
336356
}
337-
zend_cleanup_user_class_data(ce);
338-
} ZEND_HASH_FOREACH_END();
339-
zend_cleanup_internal_classes();
340-
}
341-
} zend_end_try();
342-
343-
zend_try {
344-
zend_llist_destroy(&CG(open_files));
345-
} zend_end_try();
346-
347-
zend_try {
348-
clean_non_persistent_constants();
349-
} zend_end_try();
350-
351-
zend_try {
352-
zend_close_rsrc_list(&EG(regular_list));
353-
} zend_end_try();
354-
355-
#if ZEND_DEBUG
356-
if (GC_G(gc_enabled) && !CG(unclean_shutdown)) {
357-
gc_collect_cycles();
358-
}
359-
#endif
360-
361-
zend_try {
362-
zend_objects_store_free_object_storage(&EG(objects_store));
363-
364-
zend_vm_stack_destroy();
365-
366-
/* Destroy all op arrays */
367-
if (EG(full_tables_cleanup)) {
368-
zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function_full);
369-
zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class_full);
370-
} else {
371-
zend_hash_reverse_apply(EG(function_table), clean_non_persistent_function);
372-
zend_hash_reverse_apply(EG(class_table), clean_non_persistent_class);
357+
destroy_zend_class(zv);
358+
zend_string_release(key);
359+
} ZEND_HASH_FOREACH_END_DEL();
373360
}
374361

375362
while (EG(symtable_cache_ptr)>=EG(symtable_cache)) {
376363
zend_hash_destroy(*EG(symtable_cache_ptr));
377364
FREE_HASHTABLE(*EG(symtable_cache_ptr));
378365
EG(symtable_cache_ptr)--;
379366
}
380-
} zend_end_try();
381-
382-
zend_try {
383-
#if 0&&ZEND_DEBUG
384-
signal(SIGSEGV, original_sigsegv_handler);
385-
#endif
386367

387368
zend_hash_destroy(&EG(included_files));
388369

@@ -394,9 +375,11 @@ void shutdown_executor(void) /* {{{ */
394375
zend_hash_destroy(EG(in_autoload));
395376
FREE_HASHTABLE(EG(in_autoload));
396377
}
397-
} zend_end_try();
398378

399-
zend_shutdown_fpu();
379+
if (EG(ht_iterators) != EG(ht_iterators_slots)) {
380+
efree(EG(ht_iterators));
381+
}
382+
}
400383

401384
#if ZEND_DEBUG
402385
if (EG(ht_iterators_used) && !CG(unclean_shutdown)) {
@@ -405,9 +388,10 @@ void shutdown_executor(void) /* {{{ */
405388
#endif
406389

407390
EG(ht_iterators_used) = 0;
408-
if (EG(ht_iterators) != EG(ht_iterators_slots)) {
409-
efree(EG(ht_iterators));
410-
}
391+
392+
zend_cleanup_internal_classes();
393+
394+
zend_shutdown_fpu();
411395

412396
EG(active) = 0;
413397
}

0 commit comments

Comments
 (0)