[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