From ee08b81aabcbc65c9b10b535f028b3654b732e4a Mon Sep 17 00:00:00 2001 From: Zeev Suraski Date: Sun, 16 Jan 2000 20:59:03 +0000 Subject: [PATCH] - Make zend_hash_apply() (and friends) reentrant and much, much quicker - Introduce zend_hash_graceful_destroy(), which allows the destructor functions to use zend_hash_apply() and/or zend_hash_graceful_destroy() - Switch to zend_hash_graceful_destroy() in the resource list shutdowns --- Zend/zend.c | 4 +- Zend/zend_execute_API.c | 2 +- Zend/zend_hash.c | 108 +++++++++++++++++++++++++++++----------- Zend/zend_hash.h | 1 + Zend/zend_list.c | 12 ++--- Zend/zend_list.h | 4 +- 6 files changed, 88 insertions(+), 43 deletions(-) diff --git a/Zend/zend.c b/Zend/zend.c index de6bf93ecd..ba07725523 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -283,7 +283,7 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) static void executor_globals_dtor(zend_executor_globals *executor_globals) { zend_shutdown_constants(ELS_C); - destroy_resource_plist(); + destroy_resource_plist(ELS_C); } @@ -381,7 +381,7 @@ void zend_shutdown() zend_shutdown_extensions(); free(zend_version_info); #ifndef ZTS - zend_shutdown_constants(ELS_C); + zend_shutdown_constants(); #endif } diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index fe7f7b301e..8e3c1fcf93 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -132,7 +132,7 @@ void shutdown_executor(ELS_D) zend_hash_destroy(&EG(symbol_table)); - destroy_resource_list(); /* must be destroyed after the main symbol table is destroyed */ + destroy_resource_list(ELS_C); /* must be destroyed after the main symbol table is destroyed */ zend_ptr_stack_destroy(&EG(argument_stack)); if (EG(main_op_array)) { diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index 2d2053670d..db53b4ab04 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -836,26 +836,82 @@ ZEND_API void zend_hash_clean(HashTable *ht) } +/* This function is used by the various apply() functions. + * It deletes the passed bucket, and returns the address of the + * next bucket. The hash *may* be altered during that time, the + * returned value will still be valid. + */ +static Bucket *zend_hash_apply_deleter(HashTable *ht, Bucket *p) +{ + Bucket *retval; + + HANDLE_BLOCK_INTERRUPTIONS(); + + if (!p->bIsPointer) { + if (ht->pDestructor) { + ht->pDestructor(p->pData); + } + if (!p->pDataPtr) { + pefree(p->pData, ht->persistent); + } + } + retval = p->pListNext; + + if (p->pListLast != NULL) { + p->pListLast->pListNext = p->pListNext; + } else { + /* Deleting the head of the list */ + ht->pListHead = p->pListNext; + } + if (p->pListNext != NULL) { + p->pListNext->pListLast = p->pListLast; + } else { + ht->pListTail = p->pListLast; + } + if (ht->pInternalPointer == p) { + ht->pInternalPointer = p->pListNext; + } + pefree(p,ht->persistent); + HANDLE_UNBLOCK_INTERRUPTIONS(); + ht->nNumOfElements--; + + return retval; +} + + +ZEND_API void zend_hash_graceful_destroy(HashTable *ht) +{ + Bucket *p; + + IS_CONSISTENT(ht); + + p = ht->pListHead; + while (p != NULL) { + p = zend_hash_apply_deleter(ht, p); + } + pefree(ht->arBuckets,ht->persistent); + + SET_INCONSISTENT(2); +} + /* This is used to selectively delete certain entries from a hashtable. * destruct() receives the data and decides if the entry should be deleted * or not */ + + ZEND_API void zend_hash_apply(HashTable *ht,int (*destruct) (void *)) { - Bucket *p, *q; + Bucket *p; IS_CONSISTENT(ht); p = ht->pListHead; while (p != NULL) { - q = p; - p = p->pListNext; - if (destruct(q->pData)) { - if (q->nKeyLength==0) { - zend_hash_index_del(ht, q->h); - } else { - zend_hash_del(ht,q->arKey,q->nKeyLength); - } + if (destruct(p->pData)) { + p = zend_hash_apply_deleter(ht, p); + } else { + p = p->pListNext; } } } @@ -863,20 +919,16 @@ ZEND_API void zend_hash_apply(HashTable *ht,int (*destruct) (void *)) ZEND_API void zend_hash_apply_with_argument(HashTable *ht,int (*destruct) (void *, void *), void *argument) { - Bucket *p, *q; + Bucket *p; IS_CONSISTENT(ht); p = ht->pListHead; while (p != NULL) { - q = p; - p = p->pListNext; - if (destruct(q->pData, argument)) { - if (q->nKeyLength == 0) { - zend_hash_index_del(ht, q->h); - } else { - zend_hash_del(ht,q->arKey,q->nKeyLength); - } + if (destruct(p->pData, argument)) { + p = zend_hash_apply_deleter(ht, p); + } else { + p = p->pListNext; } } } @@ -884,7 +936,7 @@ ZEND_API void zend_hash_apply_with_argument(HashTable *ht,int (*destruct) (void ZEND_API void zend_hash_apply_with_arguments(HashTable *ht,int (*destruct)(void *, int, va_list, zend_hash_key *), int num_args, ...) { - Bucket *p, *q; + Bucket *p; va_list args; zend_hash_key hash_key; @@ -894,17 +946,13 @@ ZEND_API void zend_hash_apply_with_arguments(HashTable *ht,int (*destruct)(void p = ht->pListHead; while (p != NULL) { - q = p; - p = p->pListNext; - hash_key.arKey = q->arKey; - hash_key.nKeyLength = q->nKeyLength; - hash_key.h = q->h; - if (destruct(q->pData, num_args, args, &hash_key)) { - if (q->nKeyLength == 0) { - zend_hash_index_del(ht, q->h); - } else { - zend_hash_del(ht,q->arKey,q->nKeyLength); - } + hash_key.arKey = p->arKey; + hash_key.nKeyLength = p->nKeyLength; + hash_key.h = p->h; + if (destruct(p->pData, num_args, args, &hash_key)) { + p = zend_hash_apply_deleter(ht, p); + } else { + p = p->pListNext; } } diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index feefc73105..60ac82d65c 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -118,6 +118,7 @@ ZEND_API int zend_hash_pointer_index_update_or_next_insert(HashTable *ht, ulong zend_hash_pointer_index_update_or_next_insert(ht,h,pData,HASH_UPDATE) #define zend_hash_next_index_pointer_insert(ht,pData) \ zend_hash_pointer_index_update_or_next_insert(ht,0,pData,HASH_NEXT_INSERT) +ZEND_API void zend_hash_graceful_destroy(HashTable *ht); ZEND_API void zend_hash_apply(HashTable *ht,int (*destruct)(void *)); ZEND_API void zend_hash_apply_with_argument(HashTable *ht,int (*destruct)(void *, void *), void *); ZEND_API void zend_hash_apply_with_arguments(HashTable *ht, ZEND_STD_HASH_APPLIER, int, ...); diff --git a/Zend/zend_list.c b/Zend/zend_list.c index b154a51027..570ceb31b0 100644 --- a/Zend/zend_list.c +++ b/Zend/zend_list.c @@ -248,19 +248,15 @@ int init_resource_plist(ELS_D) } -void destroy_resource_list(void) +void destroy_resource_list(ELS_D) { - ELS_FETCH(); - - zend_hash_destroy(&EG(regular_list)); + zend_hash_graceful_destroy(&EG(regular_list)); } -void destroy_resource_plist(void) +void destroy_resource_plist(ELS_D) { - ELS_FETCH(); - - zend_hash_destroy(&EG(persistent_list)); + zend_hash_graceful_destroy(&EG(persistent_list)); } diff --git a/Zend/zend_list.h b/Zend/zend_list.h index ac0b4038e5..816b52e398 100644 --- a/Zend/zend_list.h +++ b/Zend/zend_list.h @@ -52,8 +52,8 @@ int plist_entry_destructor(void *ptr); int clean_module_resource_destructors(list_destructors_entry *ld, int *module_number); int init_resource_list(ELS_D); int init_resource_plist(ELS_D); -void destroy_resource_list(void); -void destroy_resource_plist(void); +void destroy_resource_list(ELS_D); +void destroy_resource_plist(ELS_D); ZEND_API int zend_list_insert(void *ptr, int type); ZEND_API int zend_plist_insert(void *ptr, int type); -- 2.50.1