Permalink
Browse files

- 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
  • Loading branch information...
1 parent 97e1ad1 commit ee08b81aabcbc65c9b10b535f028b3654b732e4a @zsuraski zsuraski committed Jan 16, 2000
Showing with 88 additions and 43 deletions.
  1. +2 −2 Zend/zend.c
  2. +1 −1 Zend/zend_execute_API.c
  3. +78 −30 Zend/zend_hash.c
  4. +1 −0 Zend/zend_hash.h
  5. +4 −8 Zend/zend_list.c
  6. +2 −2 Zend/zend_list.h
View
@@ -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
}
View
@@ -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)) {
View
@@ -836,55 +836,107 @@ 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;
}
}
}
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;
}
}
}
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;
}
}
View
@@ -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, ...);
View
@@ -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));
}
View
@@ -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);

0 comments on commit ee08b81

Please sign in to comment.