[asterisk-commits] murf: branch murf/fast-ast r72765 - in /team/murf/fast-ast: include/asterisk/...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sat Jun 30 11:08:47 CDT 2007


Author: murf
Date: Sat Jun 30 11:08:46 2007
New Revision: 72765

URL: http://svn.digium.com/view/asterisk?view=rev&rev=72765
Log:
Pardon me while I try my best to get this branch back up into sync with trunk

Modified:
    team/murf/fast-ast/include/asterisk/hashtab.h
    team/murf/fast-ast/main/hashtab.c

Modified: team/murf/fast-ast/include/asterisk/hashtab.h
URL: http://svn.digium.com/view/asterisk/team/murf/fast-ast/include/asterisk/hashtab.h?view=diff&rev=72765&r1=72764&r2=72765
==============================================================================
--- team/murf/fast-ast/include/asterisk/hashtab.h (original)
+++ team/murf/fast-ast/include/asterisk/hashtab.h Sat Jun 30 11:08:46 2007
@@ -17,7 +17,7 @@
  */
 #ifndef _ASTERISK_HASHTAB_H_
 #define _ASTERISK_HASHTAB_H_
-#define __USE_UNIX98 1 /* what on earth? */
+#define __USE_UNIX98 1          /* to get the MUTEX_RECURSIVE stuff */
 
 /* generic (perhaps overly so) hashtable implementation */
 
@@ -27,7 +27,7 @@
 in O(1) (or close to that) time.
 
 The method: given: a set of {key,val} pairs. (at a minimum).
-            given: a hash function, which, given a the key,
+            given: a hash function, which, given a key,
             will return an integer. Ideally, each key in the
             set will have its own unique associated hash value.
 			This hash number will index into an array. "buckets"
@@ -57,17 +57,28 @@
     table size for ints, is provided; the user can use these simple
     algorithms to generate a hash, or implement any other algorithms they
     wish.
+ 6. Recently updated the hash routines to use Doubly-linked lists for buckets,
+    and added a doubly-linked list that threads thru every bucket in the table.
+    The list of all buckets is on the HashTab struct. The Traversal was modified
+    to go thru this list instead of searching the bucket array for buckets.
+    This also should make it safe to remove a bucket during the traversal.
+    Removal and destruction routines will work faster.
 */
 
 struct ast_hashtab_bucket
 {
 	const void *object;                    /* whatever it is we are storing in this table */
-	struct ast_hashtab_bucket *next; /* a simple LL of buckets in hash collision */
+	struct ast_hashtab_bucket *next;       /* a DLL of buckets in hash collision */
+	struct ast_hashtab_bucket *prev;       /* a DLL of buckets in hash collision */
+	struct ast_hashtab_bucket *tnext;      /* a DLL of all the hash buckets for traversal */
+	struct ast_hashtab_bucket *tprev;      /* a DLL of all the hash buckets for traversal */
 };
 
 struct ast_hashtab
 {
 	struct ast_hashtab_bucket **array;
+	struct ast_hashtab_bucket *tlist; /* the head of a DLList of all the hashbuckets in the table (for traversal). */
+	
 	int (*compare) (const void *a, const void *b);            /* a ptr to func that returns int, and take two void* ptrs, compares them, 
 													 rets -1 if a < b; rets 0 if a==b; rets 1 if a>b */
 	int (*newsize) (struct ast_hashtab *tab);     /* a ptr to func that returns int, a new size for hash tab, based on curr_size */
@@ -87,8 +98,7 @@
 struct ast_hashtab_iter              /* an iterator for traversing the buckets */
 {
 	struct ast_hashtab *tab;
-	int bucket_num;
-	struct ast_hashtab_bucket *curr;
+	struct ast_hashtab_bucket *next;
 };
 
 
@@ -114,16 +124,25 @@
 int ast_hashtab_resize_tight(struct ast_hashtab *tab); /* not yet specified; probably will return 1 if table is 100% full */
 
 
+int ast_hashtab_resize_none(struct ast_hashtab *tab); /* no resizing; always return 0 */
+
+
 int ast_hashtab_newsize_java(struct ast_hashtab *tab);  /* returns a prime number roughly 2x the current table size */
 
 
 int ast_hashtab_newsize_tight(struct ast_hashtab *tab); /* not yet specified, probably will return 1.5x the current table size */
 
 
+int ast_hashtab_newsize_none(struct ast_hashtab *tab); /* always return current size -- no resizing */
+
+
 int ast_hashtab_hash_string(const void *obj, int modulus); /* hashes a string to a number, mod is applied so it in the range 0 to mod-1 */
 
 
 int ast_hashtab_hash_string_nocase(const void *obj, int modulus);  /* upcases each char before using them for a hash */
+
+
+int ast_hashtab_hash_string_sax(const void *obj, int modulus); /* from Josh */
 
 
 int ast_hashtab_hash_int(const int num, int modulus);  /* right now, both these funcs are just result = num%modulus; */
@@ -175,19 +194,20 @@
 	/* returns key stats for the table */
 void ast_hashtab_get_stats( struct ast_hashtab *tab, int *biggest_bucket_size, int *resize_count, int *num_objects, int *num_buckets);
 
-	/* this function is called either internally, when the resize func returns 1, or
-	   externally by the user to force a resize of the hash table */
-void ast_hashtab_resize( struct ast_hashtab *tab);
-
+	/* this function returns the number of elements stored in the hashtab */
+int  ast_hashtab_size( struct ast_hashtab *tab);
+
+	/* this function returns the size of the bucket array in the hashtab */
+int  ast_hashtab_capacity( struct ast_hashtab *tab);
 
 	/* returns an iterator */
 struct ast_hashtab_iter *ast_hashtab_start_traversal(struct ast_hashtab *tab);
+
 	/* end the traversal, free the iterator, unlock if necc. */
 void ast_hashtab_end_traversal(struct ast_hashtab_iter *it);
 
-	/* returns the next object in the list, advances iter one step */
+	/* returns the next object in the list, advances iter one step, returns null on end of traversal */
 void *ast_hashtab_next(struct ast_hashtab_iter *it);
-
 
 
 	/* looks up the object; removes the corresponding bucket */
@@ -198,4 +218,32 @@
 	   calling the compare routine; removes the bucket */
 void *ast_hashtab_remove_this_object(struct ast_hashtab *tab, void *obj);
 
+/* ------------------ */
+/* for lock-enabled traversals with ability to remove an object during the traversal*/
+/* ------------------ */
+
+	/* returns an iterator */
+struct ast_hashtab_iter *ast_hashtab_start_write_traversal(struct ast_hashtab *tab);
+
+	/* looks up the object; removes the corresponding bucket */
+void *ast_hashtab_remove_object_via_lookup_nolock(struct ast_hashtab *tab, void *obj);
+
+
+	/* looks up the object by hash and then comparing pts in bucket list instead of
+	   calling the compare routine; removes the bucket */
+void *ast_hashtab_remove_this_object_nolock(struct ast_hashtab *tab, void *obj);
+
+/* ------------------ */
+/* ------------------ */
+
+/* user-controlled hashtab locking. Create a hashtab without locking, then call the
+   following locking routines yourself to lock the table between threads. */
+
+void ast_hashtab_initlock(struct ast_hashtab *tab); /* call this after you create the table to init the lock */
+void ast_hashtab_wrlock(struct ast_hashtab *tab); /* request a write-lock on the  table. */
+void ast_hashtab_rdlock(struct ast_hashtab *tab); /* request a read-lock on the table-- don't change anything! */
+void ast_hashtab_unlock(struct ast_hashtab *tab);      /* release a read- or write- lock. */
+void ast_hashtab_destroylock(struct ast_hashtab *tab); /* call this before you destroy the table. */
+
+
 #endif

Modified: team/murf/fast-ast/main/hashtab.c
URL: http://svn.digium.com/view/asterisk/team/murf/fast-ast/main/hashtab.c?view=diff&rev=72765&r1=72764&r2=72765
==============================================================================
--- team/murf/fast-ast/main/hashtab.c (original)
+++ team/murf/fast-ast/main/hashtab.c Sat Jun 30 11:08:46 2007
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2006, Digium, Inc.
+ * Copyright (C) 2007, Digium, Inc.
  *
  * Steve Murphy <murf at digium.com>
  *
@@ -16,11 +16,11 @@
  * at the top of the source tree.
  */
 /*! \file
- *  *
- *   * \brief code to implement generic hash tables
- *    *
- *     * \author Steve Murphy <murf at digium.com>
- *      */
+ *
+ *  \brief code to implement generic hash tables
+ *
+ *  \author Steve Murphy <murf at digium.com>
+ */
 
 #include "asterisk.h"
 
@@ -46,6 +46,7 @@
 #include "asterisk/linkedlists.h"
 #include "asterisk/hashtab.h"
 
+static void ast_hashtab_resize( struct ast_hashtab *tab);
 
 /* some standard, default routines for general use */
 
@@ -99,6 +100,12 @@
 	return 0;
 }
 
+int ast_hashtab_resize_none(struct ast_hashtab *tab) /* always return 0 -- no resizing */
+{
+	return 0;
+}
+
+
 int isPrime(int num)
 {
 	int tnum,limit;
@@ -139,6 +146,11 @@
 	while (!isPrime(i))
 		i++;
 	return i;
+}
+
+int ast_hashtab_newsize_none(struct ast_hashtab *tab) /* always return current size -- no resizing */
+{
+	return tab->hash_tab_size;
 }
 
 int ast_hashtab_hash_string(const void *obj, int modulus)
@@ -159,12 +171,12 @@
 	return (total % modulus);
 }
 
-static int ast_hashtab_hash_string_sax(const void *obj, int modulus) /* from Josh */
+int ast_hashtab_hash_string_sax(const void *obj, int modulus) /* from Josh */
 {
 	unsigned char *str = (unsigned char*)obj;
-	unsigned int total, c = 0;
-
-	while (c = *str++)
+	unsigned int total = 0, c = 0;
+
+	while ((c = *str++))
 		total ^= ( total << 5 ) + ( total >> 2 ) + ( total << 10) + c;
 
 	return (total % modulus);
@@ -231,27 +243,87 @@
 	return ht;
 }
 
+static void tlist_del_item(struct ast_hashtab_bucket **head, struct ast_hashtab_bucket *item)
+{
+	/* item had better be in the list! or suffer the weirdness that occurs, later! */
+	if (*head == item) { /* first item in the list */
+		*head = item->tnext;
+		if (item->tnext)
+			item->tnext->tprev = NULL;
+	} else {
+		/* short circuit stuff */
+		item->tprev->tnext = item->tnext;
+		if (item->tnext)
+			item->tnext->tprev = item->tprev;
+	}
+}
+
+static void tlist_add_head(struct ast_hashtab_bucket **head, struct ast_hashtab_bucket *item)
+{
+	if (*head) {
+		item->tnext = *head;
+		item->tprev = NULL;
+		(*head)->tprev = item;
+		*head = item;
+	} else {
+		/* the list is empty */
+		*head = item;
+		item->tprev = NULL;
+		item->tnext = NULL;
+	}
+}
+
+/* user-controlled hashtab locking. Create a hashtab without locking, then call the
+   following locking routines yourself to lock the table between threads. */
+
+void ast_hashtab_wrlock(struct ast_hashtab *tab)
+{
+	ast_rwlock_wrlock(&tab->lock);
+}
+
+void ast_hashtab_rdlock(struct ast_hashtab *tab)
+{
+	ast_rwlock_rdlock(&tab->lock);
+}
+
+void ast_hashtab_initlock(struct ast_hashtab *tab)
+{
+	ast_rwlock_init(&tab->lock);
+}
+
+void ast_hashtab_destroylock(struct ast_hashtab *tab)
+{
+	ast_rwlock_destroy(&tab->lock);
+}
+
+void ast_hashtab_unlock(struct ast_hashtab *tab)
+{
+	ast_rwlock_unlock(&tab->lock);
+}
+
+
 void ast_hashtab_destroy( struct ast_hashtab *tab)
 {
 	/* this func will free the hash table and all its memory. It
 	   doesn't touch the objects stored in it */
-	if (tab->do_locking)
-		ast_rwlock_wrlock(&tab->lock);
 	if (tab) {
 		
+		if (tab->do_locking)
+			ast_rwlock_wrlock(&tab->lock);
+
 		if (tab->array) {
 			/* go thru and destroy the buckets */
+			struct ast_hashtab_bucket *t;
 			int i;
-			for (i=0;i<tab->hash_tab_size;i++) {
-				struct ast_hashtab_bucket *b = tab->array[i];
-				struct ast_hashtab_bucket *N;
-				while (b) {
-					N = b->next;
-					b->next = 0; /* don't leave dead pointers laying about */
-					free(b);
-					b = N;
-				}
-				tab->array[i] = 0; /* don't leave dead pointers laying about */
+			
+			while (tab->tlist) {
+				t = tab->tlist;
+				tlist_del_item(&(tab->tlist), tab->tlist);
+				free(t);
+			}
+			
+			for (i=0;i<tab->hash_tab_size;i++) { 
+				tab->array[i] = NULL; /* not totally necc., but best to destroy old ptrs */
 			}
 			
 			free(tab->array);
@@ -277,8 +349,14 @@
 	int c;
 	struct ast_hashtab_bucket *b;
 	
-	if (!tab || !obj)
-		return 0;
+	if (!tab) {
+		ast_log(LOG_WARNING,"NULL table pointer given to INSERT.\n");
+		return 0;
+	}
+	if (!obj) {
+		ast_log(LOG_WARNING,"NULL object pointer given to INSERT.\n");
+		return 0;
+	}
 	if (tab->do_locking)
 		ast_rwlock_wrlock(&tab->lock);
 	h = (*tab->hash)(obj, tab->hash_tab_size);
@@ -290,6 +368,11 @@
 	b = ast_malloc(sizeof(struct ast_hashtab_bucket));
 	b->object = obj;
 	b->next = tab->array[h];
+	b->prev = NULL;
+	if (b->next)
+		b->next->prev = b;
+	tlist_add_head(&(tab->tlist),b);
+	
 	tab->array[h] = b;
 	tab->hash_tab_elements++;
 	if ((*tab->resize)(tab))
@@ -313,8 +396,6 @@
 	
 	if (!tab || !obj)
 		return 0;
-	if (tab->do_locking)
-		ast_rwlock_wrlock(&tab->lock);
 	
 	for (c=0,b=tab->array[h];b;b=b->next) {
 		c++;
@@ -324,12 +405,13 @@
 	b = ast_malloc(sizeof(struct ast_hashtab_bucket));
 	b->object = obj;
 	b->next = tab->array[h];
+	b->prev = NULL;
 	tab->array[h] = b;
+	b->next->prev = b;
+	tlist_add_head(&(tab->tlist), b);
 	tab->hash_tab_elements++;
 	if ((*tab->resize)(tab))
 		ast_hashtab_resize(tab);
-	if (tab->do_locking)
-		ast_rwlock_unlock(&tab->lock);
 	return 1;
 }
 
@@ -339,15 +421,46 @@
 	   it is not there. */
 	/* will force a resize if the resize func returns 1 */
 	/* returns 1 on success, 0 if there's a problem, or it's already there. */
-	int bucket;
+	int bucket = 0;
+	if (tab->do_locking)
+		ast_rwlock_wrlock(&tab->lock);
+
 	if (ast_hashtab_lookup_bucket(tab,obj,&bucket) == 0)
 	{
 		return ast_hashtab_insert_immediate_bucket(tab,obj,bucket);
 	}
+	if (tab->do_locking)
+		ast_rwlock_unlock(&tab->lock);
 	return 0;
 }
 
 void * ast_hashtab_lookup(struct ast_hashtab *tab, const void *obj)
+{
+	/* lookup this object in the hash table. return a ptr if found, or NULL if not */
+	int h;
+	const void *ret;
+	struct ast_hashtab_bucket *b;
+	if (!tab || !obj)
+		return 0;
+	
+	if (tab->do_locking)
+		ast_rwlock_rdlock(&tab->lock);
+	h = (*tab->hash)(obj, tab->hash_tab_size);
+	for (b=tab->array[h]; b; b=b->next) {
+		if ((*tab->compare)(obj,b->object) == 0) {
+			ret = b->object;
+			if (tab->do_locking)
+				ast_rwlock_unlock(&tab->lock);
+			return (void*)ret; /* I can't touch obj in this func, but the outside world is welcome to */
+		}
+	}
+	if (tab->do_locking)
+		ast_rwlock_unlock(&tab->lock);
+
+	return 0;
+}
+
+void * ast_hashtab_lookup_bucket(struct ast_hashtab *tab, const void *obj, int *bucket)
 {
 	/* lookup this object in the hash table. return a ptr if found, or NULL if not */
 	int h;
@@ -355,42 +468,14 @@
 	if (!tab || !obj)
 		return 0;
 	
-	if (tab->do_locking)
-		ast_rwlock_rdlock(&tab->lock);
 	h = (*tab->hash)(obj, tab->hash_tab_size);
-	for(b=tab->array[h]; b; b=b->next) {
-		if( (*tab->compare)(obj,b->object) == 0 ) {
+	for (b=tab->array[h]; b; b=b->next) {
+		if ((*tab->compare)(obj,b->object) == 0) {
 			if (tab->do_locking)
 				ast_rwlock_unlock(&tab->lock);
 			return (void*)b->object; /* I can't touch obj in this func, but the outside world is welcome to */
 		}
 	}
-	if (tab->do_locking)
-		ast_rwlock_unlock(&tab->lock);
-
-	return 0;
-}
-
-void * ast_hashtab_lookup_bucket(struct ast_hashtab *tab, const void *obj, int *bucket)
-{
-	/* lookup this object in the hash table. return a ptr if found, or NULL if not */
-	int h;
-	struct ast_hashtab_bucket *b;
-	if (!tab || !obj)
-		return 0;
-	
-	if (tab->do_locking)
-		ast_rwlock_rdlock(&tab->lock);
-	h = (*tab->hash)(obj, tab->hash_tab_size);
-	for(b=tab->array[h]; b; b=b->next) {
-		if( (*tab->compare)(obj,b->object) == 0 ) {
-			if (tab->do_locking)
-				ast_rwlock_unlock(&tab->lock);
-			return (void*)b->object; /* I can't touch obj in this func, but the outside world is welcome to */
-		}
-	}
-	if (tab->do_locking)
-		ast_rwlock_unlock(&tab->lock);
 	*bucket = h;
 	return 0;
 }
@@ -408,28 +493,38 @@
 		ast_rwlock_unlock(&tab->lock);
 }
 
+	/* this function returns the number of elements stored in the hashtab */
+int  ast_hashtab_size( struct ast_hashtab *tab)
+{
+	return tab->hash_tab_elements;
+}
+
+	/* this function returns the size of the bucket array in the hashtab */
+int  ast_hashtab_capacity( struct ast_hashtab *tab)
+{
+	return tab->hash_tab_size;
+}
+
+
+
 /* the insert operation calls this, and is wrlock'd when it does. */
 /* if you want to call it, you should set the wrlock yourself */
 
-void ast_hashtab_resize( struct ast_hashtab *tab)
+
+static void ast_hashtab_resize( struct ast_hashtab *tab)
 {
 	/* this function is called either internally, when the resize func returns 1, or
 	   externally by the user to force a resize of the hash table */
 	int newsize = (*tab->newsize)(tab), i, h,c;
-	struct ast_hashtab_bucket *list = 0, *b,*bn;
-	
-	/* there's two ways to do this: 
-	   1. allocate a new array, and move the elements into it from the old table directly, then
-	      free the old table. faster, requires more mem.
-	   2. relink the buckets into a single long chain; free the old array. Then, allocate the
-          new table, and move the buckets in. slower, minimal mem requirements. 
+	struct ast_hashtab_bucket *b,*bn;
+	
+	/* Since we keep a DLL of all the buckets in tlist,
+	   all we have to do is free the array, malloc a new one,
+	   and then go thru the tlist array and reassign them into 
+	   the bucket arrayj.
 	*/
-	for (i=0;i<tab->hash_tab_size;i++) {
-		for (b=tab->array[i]; b; b=bn) {
-			bn = b->next;
-			b->next = list;
-			list = b;
-		}
+	for (i=0;i<tab->hash_tab_size;i++) { /* don't absolutely have to do this, but
+											why leave ptrs laying around */
 		tab->array[i] = 0; /* erase old ptrs */
 	}
 	free(tab->array);
@@ -439,21 +534,23 @@
 	tab->hash_tab_size = newsize;
 	tab->largest_bucket_size = 0;
 
-	for (b=list;b;b=bn)
-	{
-		bn = b->next;
+	for (b=tab->tlist;b;b=bn)
+	{
+		b->prev = 0;
+		bn = b->tnext;
 		h = (*tab->hash)(b->object, tab->hash_tab_size);
 		b->next = tab->array[h];
+		if (b->next)
+			b->next->prev = b;
 		tab->array[h] = b;
 	}
-	list = 0;
 	/* recalc the largest bucket size */
 	for (i=0;i<tab->hash_tab_size;i++) {
 		c=0;
 		for (b=tab->array[i]; b; b=b->next) {
 			c++;
 		}
-		if( c > tab->largest_bucket_size )
+		if (c > tab->largest_bucket_size)
 			tab->largest_bucket_size = c;
 	}
 }
@@ -462,12 +559,22 @@
 {
 	/* returns an iterator */
 	struct ast_hashtab_iter *it = ast_malloc(sizeof(struct ast_hashtab_iter));
-	it->bucket_num = 0;
-	
-	it->curr = tab->array[0];
+	it->next = tab->tlist;
 	it->tab = tab;
 	if (tab->do_locking)
 		ast_rwlock_rdlock(&tab->lock);
+	return it;
+}
+
+/* use this function to get a write lock */
+struct ast_hashtab_iter *ast_hashtab_start_write_traversal(struct ast_hashtab *tab)
+{
+	/* returns an iterator */
+	struct ast_hashtab_iter *it = ast_malloc(sizeof(struct ast_hashtab_iter));
+	it->next = tab->tlist;
+	it->tab = tab;
+	if (tab->do_locking)
+		ast_rwlock_wrlock(&tab->lock);
 	return it;
 }
 
@@ -481,78 +588,120 @@
 void *ast_hashtab_next(struct ast_hashtab_iter *it)
 {
 	/* returns the next object in the list, advances iter one step */
-	int num;
-
-	
-	if( it->curr && it->curr->next )  /* there's a next in the bucket list */
-	{
-		it->curr = it->curr->next;
-		return (void*)it->curr->object;
-	} else if( !it->curr && it->bucket_num == 0 ){ /* first call to this */
-		for(num=it->bucket_num; num<it->tab->hash_tab_size; num++)
-		{
-			if (it->tab->array[num]) {
-				it->bucket_num = num;
-				it->curr = it->tab->array[num];
-				return (void*)it->curr->object; /* inside the hash code, the obj's are untouchable, but outside... */
-			} else {
-				continue; /* try the next bucket */
-			}
-			return 0; /* nothing in the whole table! */
-		}
-	} else if (it->curr && !it->curr->next) {  /* end of a bucket chain */
-		it->bucket_num++;
-		for(num=it->bucket_num; num<it->tab->hash_tab_size; num++)
-		{
-			if (it->tab->array[num]) {
-				it->bucket_num = num;
-				it->curr = it->tab->array[num];
-				return (void*)it->curr->object; /* inside the hash code, the obj's are untouchable, but outside... */
-			} else {
-				continue; /* try the next bucket */
-			}
-			return 0; /* nothing in the whole table! */
-		}
-		
-	} else if (!it->curr && it->bucket_num != 0 ) { /* call me again, after the list is traversed? */
-		return 0;
-	}
-	
-	return 0;
+	struct ast_hashtab_bucket *retval;
+	
+	if (it && it->next) { /* there's a next in the bucket list */
+		retval = it->next;
+		it->next = retval->tnext;
+		return (void*)retval->object;
+	}
+	return NULL;
+}
+
+static void *ast_hashtab_remove_object_internal(struct ast_hashtab *tab, struct ast_hashtab_bucket *b, int h)
+{
+	const void *obj2;
+	
+	if (b->prev) {
+		b->prev->next = b->next;
+	} else {
+		tab->array[h] = b->next;
+	}
+	
+	if (b->next) {
+		b->next->prev = b->prev;
+	}
+	
+	tlist_del_item(&(tab->tlist), b);
+	
+	obj2 = b->object;
+	b->object = b->next = (void*)2;
+	free(b); /* free up the hashbucket */
+	tab->hash_tab_elements--;
+#ifdef DEBUG
+	{
+		int c2;
+		struct ast_hashtab_bucket *b2;
+		/* do a little checking */
+		for (c2 = 0, b2 = tab->tlist;b2;b2=b2->tnext) {
+			c2++;
+		}
+		if (c2 != tab->hash_tab_elements) {
+			printf("Hey! we didn't delete right! there are %d elements in the list, and we expected %d\n",
+				   c2, tab->hash_tab_elements);
+		}
+		for (c2 = 0, b2 = tab->tlist;b2;b2=b2->tnext) {
+			unsigned int obj3 = (unsigned long)obj2;
+			unsigned int b3 = (unsigned long)b;
+			if (b2->object == obj2)
+				printf("Hey-- you've still got a bucket pointing at ht_element %x\n", obj3);
+			if (b2->next == b)
+				printf("Hey-- you've still got a bucket with next ptr pointing to deleted bucket %x\n", b3);
+			if (b2->prev == b)
+				printf("Hey-- you've still got a bucket with prev ptr pointing to deleted bucket %x\n", b3);
+			if (b2->tprev == b)
+				printf("Hey-- you've still got a bucket with tprev ptr pointing to deleted bucket %x\n", b3);
+			if (b2->tnext == b)
+				printf("Hey-- you've still got a bucket with tnext ptr pointing to deleted bucket %x\n", b3);
+		}
+	}
+#endif
+	return (void*)obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
 }
 
 void *ast_hashtab_remove_object_via_lookup(struct ast_hashtab *tab, void *obj)
 {
 	/* looks up the object; removes the corresponding bucket */
 	int h;
-	struct ast_hashtab_bucket *b,*last;
+	struct ast_hashtab_bucket *b;
 
 	if (!tab || !obj)
 		return 0;
-	last = 0;
 	if (tab->do_locking)
 		ast_rwlock_wrlock(&tab->lock);
 	h = (*tab->hash)(obj, tab->hash_tab_size);
-	for(b=tab->array[h]; b; b=b->next)
-	{
-		const void *obj2;
+	for (b=tab->array[h]; b; b=b->next)
+	{
+		void *obj2;
 		
 		if ((*tab->compare)(obj,b->object) == 0) {
-			if (last)
-				last->next = b->next;
-			else
-				tab->array[h] = b->next;
-			obj2 = b->object;
-			b->object = b->next = 0;
-			free(b); /* free up the hashbucket */
+
+			obj2 = ast_hashtab_remove_object_internal(tab,b,h);
+			
 			if (tab->do_locking)
 				ast_rwlock_unlock(&tab->lock);
+			
 			return (void*)obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
 		}
-		last = b;
 	}
 	if (tab->do_locking)
 		ast_rwlock_unlock(&tab->lock);
+	return 0;
+}
+
+void *ast_hashtab_remove_object_via_lookup_nolock(struct ast_hashtab *tab, void *obj)
+{
+	/* looks up the object; removes the corresponding bucket */
+	int h;
+	struct ast_hashtab_bucket *b;
+
+	if (!tab || !obj)
+		return 0;
+	h = (*tab->hash)(obj, tab->hash_tab_size);
+	for (b=tab->array[h]; b; b=b->next)
+	{
+		void *obj2;
+		
+		if ((*tab->compare)(obj,b->object) == 0) {
+
+			obj2 = ast_hashtab_remove_object_internal(tab,b,h);
+			
+			if (tab->do_locking)
+				ast_rwlock_unlock(&tab->lock);
+			
+			return (void*)obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
+		}
+	}
 	return 0;
 }
 
@@ -562,34 +711,61 @@
 	   calling the compare routine; removes the bucket -- a slightly cheaper operation */
 	/* looks up the object; removes the corresponding bucket */
 	int h;
-	struct ast_hashtab_bucket *b,*last;
+	struct ast_hashtab_bucket *b;
 
 	if (!tab || !obj)
 		return 0;
  
-	last = 0;
 	if (tab->do_locking)
 		ast_rwlock_wrlock(&tab->lock);
+
 	h = (*tab->hash)(obj, tab->hash_tab_size);
 	for (b=tab->array[h]; b; b=b->next)
 	{
 		const void *obj2;
 		
 		if (obj == b->object) {
-			if (last)
-				last->next = b->next;
-			else
-				tab->array[h] = b->next;
-			obj2 = b->object;
-			b->object = b->next = 0;
-			free(b); /* free up the hashbucket */
+
+			obj2 = ast_hashtab_remove_object_internal(tab,b,h);
+			
 			if (tab->do_locking)
 				ast_rwlock_unlock(&tab->lock);
+
 			return (void*)obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
 		}
-		last = b;
-	}
+	}
+	
 	if (tab->do_locking)
 		ast_rwlock_unlock(&tab->lock);
 	return 0;
 }
+
+void *ast_hashtab_remove_this_object_nolock(struct ast_hashtab *tab, void *obj)
+{
+	/* looks up the object by hash and then comparing pts in bucket list instead of
+	   calling the compare routine; removes the bucket -- a slightly cheaper operation */
+	/* looks up the object; removes the corresponding bucket */
+	int h;
+	struct ast_hashtab_bucket *b;
+
+	if (!tab || !obj)
+		return 0;
+ 
+	h = (*tab->hash)(obj, tab->hash_tab_size);
+	for (b=tab->array[h]; b; b=b->next)
+	{
+		const void *obj2;
+		
+		if (obj == b->object) {
+
+			obj2 = ast_hashtab_remove_object_internal(tab,b,h);
+			
+			if (tab->do_locking)
+				ast_rwlock_unlock(&tab->lock);
+
+			return (void*)obj2; /* inside this code, the obj's are untouchable, but outside, they aren't */
+		}
+	}
+
+	return 0;
+}




More information about the asterisk-commits mailing list