]> granicus.if.org Git - php/commitdiff
shutdown_executor() refactoring (reuse opcache fast request shutdown code)
authorDmitry Stogov <dmitry@zend.com>
Wed, 21 Jun 2017 22:45:28 +0000 (01:45 +0300)
committerDmitry Stogov <dmitry@zend.com>
Wed, 21 Jun 2017 22:45:28 +0000 (01:45 +0300)
14 files changed:
Zend/zend.c
Zend/zend_compile.h
Zend/zend_constants.c
Zend/zend_constants.h
Zend/zend_execute_API.c
Zend/zend_hash.h
Zend/zend_objects_API.c
Zend/zend_objects_API.h
Zend/zend_opcode.c
ext/opcache/README
ext/opcache/ZendAccelerator.c
ext/opcache/ZendAccelerator.h
ext/opcache/zend_accelerator_module.c
main/streams/streams.c

index d51bd277a6160415c9615542f11991f38a819c79..a5434c2e5e43d3cd81a5e3b0a05f7ca79b664b80 100644 (file)
@@ -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();
index 4264232bc426d7b72416894aee925bfb5272957f..99f8e372402a9c61eba1566b8003dd2acae5d1e1 100644 (file)
@@ -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);
index 77124fcf12621d6b95f2f19615dd18cb4b645828..4d128c484378bba3f1a396be510e207bdf72fa8f 100644 (file)
@@ -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);
@@ -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;
index 531ef665d86422726771236468074b3a3cf5b87c..3622cc45b8de73f56b64a11b3428bbf9d3b05ed6 100644 (file)
@@ -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);
index ef29546ac07981611d6a99f4a9bd932aedd2879b..3c453e64efbfdbb1656fb873933eb77b699a0553 100644 (file)
@@ -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;
 }
index 638fbe27fc02d035ab798123ae75e6ec9809c794..ef0d23bbbf66611592d0ea245074c6406706a1ac 100644 (file)
@@ -800,8 +800,9 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht,
        zend_hash_get_current_data_ptr_ex(ht, &(ht)->nInternalPointer)
 
 #define ZEND_HASH_FOREACH(_ht, indirect) do { \
-               Bucket *_p = (_ht)->arData; \
-               Bucket *_end = _p + (_ht)->nNumUsed; \
+               HashTable *__ht = (_ht); \
+               Bucket *_p = __ht->arData; \
+               Bucket *_end = _p + __ht->nNumUsed; \
                for (; _p != _end; _p++) { \
                        zval *_z = &_p->val; \
                        if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
@@ -810,9 +811,10 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht,
                        if (UNEXPECTED(Z_TYPE_P(_z) == IS_UNDEF)) continue;
 
 #define ZEND_HASH_REVERSE_FOREACH(_ht, indirect) do { \
+               HashTable *__ht = (_ht); \
                uint32_t _idx; \
-               for (_idx = (_ht)->nNumUsed; _idx > 0; _idx--) { \
-                       Bucket *_p = (_ht)->arData + _idx - 1; \
+               for (_idx = __ht->nNumUsed; _idx > 0; _idx--) { \
+                       Bucket *_p = __ht->arData + (_idx - 1); \
                        zval *_z = &_p->val; \
                        if (indirect && Z_TYPE_P(_z) == IS_INDIRECT) { \
                                _z = Z_INDIRECT_P(_z); \
@@ -823,6 +825,27 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht,
                } \
        } while (0)
 
+#define ZEND_HASH_FOREACH_END_DEL() \
+                       __ht->nNumOfElements--; \
+                       do { \
+                               uint32_t j = HT_IDX_TO_HASH(_idx - 1); \
+                               uint32_t nIndex = _p->h | __ht->nTableMask; \
+                               uint32_t i = HT_HASH(__ht, nIndex); \
+                               if (j != i) { \
+                                       Bucket *prev = HT_HASH_TO_BUCKET(__ht, i); \
+                                       while (Z_NEXT(prev->val) != j) { \
+                                               i = Z_NEXT(prev->val); \
+                                               prev = HT_HASH_TO_BUCKET(__ht, i); \
+                                       } \
+                                       Z_NEXT(prev->val) = Z_NEXT(_p->val); \
+                               } else { \
+                                        HT_HASH(__ht, _p->h | __ht->nTableMask) = Z_NEXT(_p->val); \
+                               } \
+                       } while (0); \
+               } \
+               __ht->nNumUsed = _idx; \
+       } while (0)
+
 #define ZEND_HASH_FOREACH_BUCKET(ht, _bucket) \
        ZEND_HASH_FOREACH(ht, 0); \
        _bucket = _p;
@@ -911,6 +934,11 @@ static zend_always_inline void *zend_hash_get_current_data_ptr_ex(HashTable *ht,
        ZEND_HASH_REVERSE_FOREACH(ht, 1); \
        _val = _z;
 
+#define ZEND_HASH_REVERSE_FOREACH_STR_KEY_VAL(ht, _key, _val) \
+       ZEND_HASH_REVERSE_FOREACH(ht, 0); \
+       _key = _p->key; \
+       _val = _z;
+
 #define ZEND_HASH_REVERSE_FOREACH_KEY_VAL(ht, _h, _key, _val) \
        ZEND_HASH_REVERSE_FOREACH(ht, 0); \
        _h = _p->h; \
index 53a0c3be2388e4058f140265a6699c9c3b6c91f4..f838eddc9755e707cf333c9fd7bf3454ab674e9c 100644 (file)
@@ -76,7 +76,7 @@ ZEND_API void zend_objects_store_mark_destructed(zend_objects_store *objects)
        }
 }
 
-ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects)
+ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects, zend_bool fast_shutdown)
 {
        zend_object **obj_ptr, **end, *obj;
 
@@ -88,20 +88,37 @@ ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects
        end = objects->object_buckets + 1;
        obj_ptr = objects->object_buckets + objects->top;
 
-       do {
-               obj_ptr--;
-               obj = *obj_ptr;
-               if (IS_OBJ_VALID(obj)) {
-                       if (!(GC_FLAGS(obj) & IS_OBJ_FREE_CALLED)) {
-                               GC_FLAGS(obj) |= IS_OBJ_FREE_CALLED;
-                               if (obj->handlers->free_obj) {
-                                       GC_REFCOUNT(obj)++;
-                                       obj->handlers->free_obj(obj);
-                                       GC_REFCOUNT(obj)--;
+       if (fast_shutdown) {
+               do {
+                       obj_ptr--;
+                       obj = *obj_ptr;
+                       if (IS_OBJ_VALID(obj)) {
+                               if (!(GC_FLAGS(obj) & IS_OBJ_FREE_CALLED)) {
+                                       GC_FLAGS(obj) |= IS_OBJ_FREE_CALLED;
+                                       if (obj->handlers->free_obj && obj->handlers->free_obj != zend_object_std_dtor) {
+                                               GC_REFCOUNT(obj)++;
+                                               obj->handlers->free_obj(obj);
+                                               GC_REFCOUNT(obj)--;
+                                       }
                                }
                        }
-               }
-       } while (obj_ptr != end);
+               } while (obj_ptr != end);
+       } else {
+               do {
+                       obj_ptr--;
+                       obj = *obj_ptr;
+                       if (IS_OBJ_VALID(obj)) {
+                               if (!(GC_FLAGS(obj) & IS_OBJ_FREE_CALLED)) {
+                                       GC_FLAGS(obj) |= IS_OBJ_FREE_CALLED;
+                                       if (obj->handlers->free_obj) {
+                                               GC_REFCOUNT(obj)++;
+                                               obj->handlers->free_obj(obj);
+                                               GC_REFCOUNT(obj)--;
+                                       }
+                               }
+                       }
+               } while (obj_ptr != end);
+       }
 }
 
 
index 223060035e2878e4f158ef8defc7cedadb5caee3..b105def1766df80b0c0131b4779847c1a3e15750 100644 (file)
@@ -68,7 +68,7 @@ static zend_always_inline void zend_object_store_ctor_failed(zend_object *obj)
        GC_FLAGS(obj) |= IS_OBJ_DESTRUCTOR_CALLED;
 }
 
-ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects);
+ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects, zend_bool fast_shutdown);
 
 #define ZEND_OBJECTS_STORE_HANDLERS 0, zend_object_std_dtor, zend_objects_destroy_object, zend_objects_clone_obj
 
index e8764e964a4cde9b461c06c1967d80a46bfd5224..a0ec0684053cd19550b87be0e294161918820824 100644 (file)
@@ -148,51 +148,6 @@ ZEND_API void zend_function_dtor(zval *zv)
        }
 }
 
-ZEND_API void zend_cleanup_op_array_data(zend_op_array *op_array)
-{
-       if (op_array->static_variables &&
-           !(GC_FLAGS(op_array->static_variables) & IS_ARRAY_IMMUTABLE)
-       ) {
-               /* The static variables are initially shared when inheriting methods and will
-                * be separated on first use. If they are never used, they stay shared. Cleaning
-                * a shared static variables table is safe, as the intention is to clean all
-                * such tables. */
-               HT_ALLOW_COW_VIOLATION(op_array->static_variables);
-
-               zend_hash_clean(op_array->static_variables);
-       }
-}
-
-ZEND_API void zend_cleanup_user_class_data(zend_class_entry *ce)
-{
-       /* Clean all parts that can contain run-time data */
-       /* Note that only run-time accessed data need to be cleaned up, pre-defined data can
-          not contain objects and thus are not probelmatic */
-       if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
-               zend_function *func;
-
-               ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
-                       if (func->type == ZEND_USER_FUNCTION) {
-                               zend_cleanup_op_array_data((zend_op_array *) func);
-                       }
-               } ZEND_HASH_FOREACH_END();
-       }
-       if (ce->static_members_table) {
-               zval *static_members = ce->static_members_table;
-               zval *p = static_members;
-               zval *end = p + ce->default_static_members_count;
-
-
-               ce->default_static_members_count = 0;
-               ce->default_static_members_table = ce->static_members_table = NULL;
-               while (p != end) {
-                       i_zval_ptr_dtor(p ZEND_FILE_LINE_CC);
-                       p++;
-               }
-               efree(static_members);
-       }
-}
-
 ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce)
 {
        if (CE_STATIC_MEMBERS(ce)) {
index cf305ad9d1d162543e8c3aab13ba16ab4a5564c5..6f07f7ee582178a7586efdb77895ce07136c04f1 100644 (file)
@@ -47,7 +47,6 @@ opcache.memory_consumption=128
 opcache.interned_strings_buffer=8
 opcache.max_accelerated_files=4000
 opcache.revalidate_freq=60
-opcache.fast_shutdown=1
 opcache.enable_cli=1
 
 You also may add the following, but it may break some applications and
@@ -137,11 +136,6 @@ opcache.save_comments (default "1")
        size of the optimized code. Disabling "Doc Comments" may break some
        existing applications and frameworks (e.g. Doctrine, ZF2, PHPUnit)
 
-opcache.fast_shutdown (default "0")
-       If enabled, a fast shutdown sequence is used for the accelerated code
-       The fast shutdown sequence doesn't free each allocated block, but lets
-       the Zend Engine Memory Manager do the work.
-
 opcache.enable_file_override (default "0")
        Allow file existence override (file_exists, etc.) performance feature.
 
index e6dc4ce684d0689e888e0e978ded06136ba00cec..7e375e8289565eb3b7b7a3a49a9e7c6029081221 100644 (file)
@@ -2250,192 +2250,6 @@ static void accel_activate(void)
        }
 }
 
-#if !ZEND_DEBUG
-
-/* Fast Request Shutdown
- * =====================
- * Zend Memory Manager frees memory by its own. We don't have to free each
- * allocated block separately, but we like to call all the destructors and
- * callbacks in exactly the same order.
- */
-static void accel_fast_hash_destroy(HashTable *ht);
-
-static void accel_fast_zval_dtor(zval *zvalue)
-{
-tail_call:
-       switch (Z_TYPE_P(zvalue)) {
-               case IS_ARRAY:
-                       GC_REMOVE_FROM_BUFFER(Z_ARR_P(zvalue));
-                       if (Z_ARR_P(zvalue) != &EG(symbol_table)) {
-                               /* break possible cycles */
-                               ZVAL_NULL(zvalue);
-                               accel_fast_hash_destroy(Z_ARRVAL_P(zvalue));
-                       }
-                       break;
-               case IS_OBJECT:
-                       OBJ_RELEASE(Z_OBJ_P(zvalue));
-                       break;
-               case IS_RESOURCE:
-                       zend_list_delete(Z_RES_P(zvalue));
-                       break;
-               case IS_REFERENCE: {
-                               zend_reference *ref = Z_REF_P(zvalue);
-
-                               if (--GC_REFCOUNT(ref) == 0) {
-                                       if (Z_REFCOUNTED(ref->val) && Z_DELREF(ref->val) == 0) {
-                                               zvalue = &ref->val;
-                                               goto tail_call;
-                                       }
-                               }
-                       }
-                       break;
-       }
-}
-
-static void accel_fast_hash_destroy(HashTable *ht)
-{
-       Bucket *p = ht->arData;
-       Bucket *end = p + ht->nNumUsed;
-
-       while (p != end) {
-               if (Z_REFCOUNTED(p->val) && Z_DELREF(p->val) == 0) {
-                       accel_fast_zval_dtor(&p->val);
-               }
-               p++;
-       }
-}
-
-static inline void zend_accel_fast_del_bucket(HashTable *ht, uint32_t idx, Bucket *p)
-{
-       uint32_t nIndex = p->h | ht->nTableMask;
-       uint32_t i = HT_HASH(ht, nIndex);
-
-       ht->nNumOfElements--;
-       if (idx != i) {
-               Bucket *prev = HT_HASH_TO_BUCKET(ht, i);
-               while (Z_NEXT(prev->val) != idx) {
-                       i = Z_NEXT(prev->val);
-                       prev = HT_HASH_TO_BUCKET(ht, i);
-               }
-               Z_NEXT(prev->val) = Z_NEXT(p->val);
-       } else {
-               HT_HASH(ht, p->h | ht->nTableMask) = Z_NEXT(p->val);
-       }
-}
-
-static void zend_accel_fast_shutdown(void)
-{
-       if (EG(full_tables_cleanup)) {
-               return;
-       }
-
-       if (EG(objects_store).top > 1 || zend_hash_num_elements(&EG(regular_list)) > 0) {
-               /* We don't have to destroy all zvals if they cannot call any destructors */
-               zend_try {
-                       ZEND_HASH_REVERSE_FOREACH(&EG(symbol_table), 0) {
-                               if (Z_REFCOUNTED(_p->val) && Z_DELREF(_p->val) == 0) {
-                                       accel_fast_zval_dtor(&_p->val);
-                               }
-                               zend_accel_fast_del_bucket(&EG(symbol_table), HT_IDX_TO_HASH(_idx-1), _p);
-                       } ZEND_HASH_FOREACH_END();
-               } zend_end_try();
-               zend_hash_init(&EG(symbol_table), 8, NULL, NULL, 0);
-
-               ZEND_HASH_REVERSE_FOREACH(EG(function_table), 0) {
-                       zend_function *func = Z_PTR(_p->val);
-
-                       if (func->type == ZEND_INTERNAL_FUNCTION) {
-                               break;
-                       } else {
-                               if (func->op_array.static_variables) {
-                                       if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
-                                               if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
-                                                       accel_fast_hash_destroy(func->op_array.static_variables);
-                                               }
-                                       }
-                               }
-                               zend_accel_fast_del_bucket(EG(function_table), HT_IDX_TO_HASH(_idx-1), _p);
-                       }
-               } ZEND_HASH_FOREACH_END();
-
-               ZEND_HASH_REVERSE_FOREACH(EG(class_table), 0) {
-                       zend_class_entry *ce = Z_PTR(_p->val);
-
-                       if (ce->type == ZEND_INTERNAL_CLASS) {
-                               break;
-                       } else {
-                               if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) {
-                                       zend_function *func;
-
-                                       ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
-                                               if (func->type == ZEND_USER_FUNCTION) {
-                                                       if (func->op_array.static_variables) {
-                                                               if (!(GC_FLAGS(func->op_array.static_variables) & IS_ARRAY_IMMUTABLE)) {
-                                                                       if (--GC_REFCOUNT(func->op_array.static_variables) == 0) {
-                                                                               accel_fast_hash_destroy(func->op_array.static_variables);
-                                                                       }
-                                                               }
-                                                               func->op_array.static_variables = NULL;
-                                                       }
-                                               }
-                                       } ZEND_HASH_FOREACH_END();
-                               }
-                               if (ce->static_members_table) {
-                                       int i;
-
-                                       for (i = 0; i < ce->default_static_members_count; i++) {
-                                               zval *zv = &ce->static_members_table[i];
-                                               ZVAL_UNDEF(&ce->static_members_table[i]);
-                                               if (Z_REFCOUNTED_P(zv) && Z_DELREF_P(zv) == 0) {
-                                                       accel_fast_zval_dtor(zv);
-                                               }
-                                       }
-                                       ce->static_members_table = NULL;
-                               }
-                               zend_accel_fast_del_bucket(EG(class_table), HT_IDX_TO_HASH(_idx-1), _p);
-                       }
-               } ZEND_HASH_FOREACH_END();
-
-       } else {
-
-               zend_hash_init(&EG(symbol_table), 8, NULL, NULL, 0);
-
-               ZEND_HASH_REVERSE_FOREACH(EG(function_table), 0) {
-                       zend_function *func = Z_PTR(_p->val);
-
-                       if (func->type == ZEND_INTERNAL_FUNCTION) {
-                               break;
-                       } else {
-                               zend_accel_fast_del_bucket(EG(function_table), HT_IDX_TO_HASH(_idx-1), _p);
-                       }
-               } ZEND_HASH_FOREACH_END();
-
-               ZEND_HASH_REVERSE_FOREACH(EG(class_table), 0) {
-                       zend_class_entry *ce = Z_PTR(_p->val);
-
-                       if (ce->type == ZEND_INTERNAL_CLASS) {
-                               break;
-                       } else {
-                               zend_accel_fast_del_bucket(EG(class_table), HT_IDX_TO_HASH(_idx-1), _p);
-                       }
-               } ZEND_HASH_FOREACH_END();
-       }
-
-       ZEND_HASH_REVERSE_FOREACH(EG(zend_constants), 0) {
-               zend_constant *c = Z_PTR(_p->val);
-
-               if (c->flags & CONST_PERSISTENT) {
-                       break;
-               } else {
-                       zend_accel_fast_del_bucket(EG(zend_constants), HT_IDX_TO_HASH(_idx-1), _p);
-               }
-       } ZEND_HASH_FOREACH_END();
-       EG(function_table)->nNumUsed = EG(function_table)->nNumOfElements;
-       EG(class_table)->nNumUsed = EG(class_table)->nNumOfElements;
-       EG(zend_constants)->nNumUsed = EG(zend_constants)->nNumOfElements;
-}
-#endif
-
 int accel_post_deactivate(void)
 {
        if (!ZCG(enabled) || !accel_startup_ok) {
@@ -2464,12 +2278,6 @@ static void accel_deactivate(void)
        if (!ZCG(enabled) || !accel_startup_ok) {
                return;
        }
-
-#if !ZEND_DEBUG
-       if (ZCG(accel_directives).fast_shutdown && is_zend_mm()) {
-               zend_accel_fast_shutdown();
-       }
-#endif
 }
 
 static int accelerator_remove_cb(zend_extension *element1, zend_extension *element2)
index 6faa263db233e31087226eb8aa377a32b6e9e6bd..17b6f8da521f5c0d1e33db8847b6a7c57a1b6abd 100644 (file)
@@ -175,7 +175,6 @@ typedef struct _zend_accel_directives {
        zend_bool      validate_timestamps;
        zend_bool      revalidate_path;
        zend_bool      save_comments;
-       zend_bool      fast_shutdown;
        zend_bool      protect_memory;
        zend_bool      file_override_enabled;
        zend_bool      inherited_hack;
index 6f76851455360b12446129fece6586abd30a79f5..6c8efac7c71b2b431e88a67f85632eed01092d73 100644 (file)
@@ -299,7 +299,6 @@ ZEND_INI_BEGIN()
 
        STD_PHP_INI_ENTRY("opcache.protect_memory"        , "0"  , PHP_INI_SYSTEM, OnUpdateBool,                  accel_directives.protect_memory,            zend_accel_globals, accel_globals)
        STD_PHP_INI_ENTRY("opcache.save_comments"         , "1"  , PHP_INI_SYSTEM, OnUpdateBool,                  accel_directives.save_comments,             zend_accel_globals, accel_globals)
-       STD_PHP_INI_ENTRY("opcache.fast_shutdown"         , "0"  , PHP_INI_SYSTEM, OnUpdateBool,                  accel_directives.fast_shutdown,             zend_accel_globals, accel_globals)
 
        STD_PHP_INI_ENTRY("opcache.optimization_level"    , DEFAULT_OPTIMIZATION_LEVEL , PHP_INI_SYSTEM, OnUpdateLong, accel_directives.optimization_level,   zend_accel_globals, accel_globals)
        STD_PHP_INI_ENTRY("opcache.opt_debug_level"       , "0"      , PHP_INI_SYSTEM, OnUpdateLong,             accel_directives.opt_debug_level,            zend_accel_globals, accel_globals)
@@ -722,7 +721,6 @@ static ZEND_FUNCTION(opcache_get_configuration)
 
        add_assoc_bool(&directives,   "opcache.protect_memory",         ZCG(accel_directives).protect_memory);
        add_assoc_bool(&directives,   "opcache.save_comments",          ZCG(accel_directives).save_comments);
-       add_assoc_bool(&directives,   "opcache.fast_shutdown",          ZCG(accel_directives).fast_shutdown);
        add_assoc_bool(&directives,   "opcache.enable_file_override",   ZCG(accel_directives).file_override_enabled);
        add_assoc_long(&directives,      "opcache.optimization_level",     ZCG(accel_directives).optimization_level);
 
index 25898cd2c4f5901c4a88a9d9e52c3fa2f2ade66e..23d46455c16d9fe08358321ccc59781e4452dc26 100644 (file)
@@ -502,43 +502,13 @@ fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remov
                        /* we don't work with *stream but need its value for comparison */
                        zend_hash_apply_with_argument(&EG(persistent_list), _php_stream_free_persistent, stream);
                }
-#if ZEND_DEBUG
-               if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) && (stream->__exposed == 0) && (EG(error_reporting) & E_WARNING)) {
-                       /* it leaked: Lets deliberately NOT pefree it so that the memory manager shows it
-                        * as leaked; it will log a warning, but lets help it out and display what kind
-                        * of stream it was. */
-                       if (!CG(unclean_shutdown)) {
-                               char *leakinfo;
-                               spprintf(&leakinfo, 0, __FILE__ "(%d) : Stream of type '%s' %p (path:%s) was not closed\n", __LINE__, stream->ops->label, stream, stream->orig_path);
-
-                               if (stream->orig_path) {
-                                       pefree(stream->orig_path, stream->is_persistent);
-                                       stream->orig_path = NULL;
-                               }
 
-# if defined(PHP_WIN32)
-                               OutputDebugString(leakinfo);
-# else
-                               fprintf(stderr, "%s", leakinfo);
-# endif
-                               efree(leakinfo);
-                       }
-               } else {
-                       if (stream->orig_path) {
-                               pefree(stream->orig_path, stream->is_persistent);
-                               stream->orig_path = NULL;
-                       }
-
-                       pefree(stream, stream->is_persistent);
-               }
-#else
                if (stream->orig_path) {
                        pefree(stream->orig_path, stream->is_persistent);
                        stream->orig_path = NULL;
                }
 
                pefree(stream, stream->is_persistent);
-#endif
        }
 
        if (context) {