[svn-commits] mmichelson: branch mmichelson/ao2_containers r140400 - in /team/mmichelson/ao...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Thu Aug 28 14:37:39 CDT 2008


Author: mmichelson
Date: Thu Aug 28 14:37:39 2008
New Revision: 140400

URL: http://svn.digium.com/view/asterisk?view=rev&rev=140400
Log:
Hey! It compiles!

I implemented the ao2_hashtable_alloc function
now, and fixed all compilation issues.

Running Asterisk, there are no immediate segfaults
or anything horrible, and running with valgrind,
I don't see any errors from normal operation.

However, there is clearly something wrong right
now, since it seems like I can't successfully place
any calls and SIP registrations seem to be flaky.

I'd like to get everything running flawlessly before
I go and complicate things further by adding
linked list and skip list implementations


Modified:
    team/mmichelson/ao2_containers/include/asterisk/astobj2.h
    team/mmichelson/ao2_containers/include/asterisk/astobj2_private.h
    team/mmichelson/ao2_containers/main/Makefile
    team/mmichelson/ao2_containers/main/astobj2.c
    team/mmichelson/ao2_containers/main/astobj2_hashtable.c
    team/mmichelson/ao2_containers/utils/Makefile

Modified: team/mmichelson/ao2_containers/include/asterisk/astobj2.h
URL: http://svn.digium.com/view/asterisk/team/mmichelson/ao2_containers/include/asterisk/astobj2.h?view=diff&rev=140400&r1=140399&r2=140400
==============================================================================
--- team/mmichelson/ao2_containers/include/asterisk/astobj2.h (original)
+++ team/mmichelson/ao2_containers/include/asterisk/astobj2.h Thu Aug 28 14:37:39 2008
@@ -636,14 +636,15 @@
  */
 /*@{ */
 struct ao2_container;
+struct astobj2;
 
 struct ao2_container_impl {	
-	void *(* const link)(struct ao2_container *c, void *newobj);
+	void *(* const link)(struct ao2_container *c, struct astobj2 *newobj);
 	void *(* const unlink)(struct ao2_container *c, void *obj);
 	void *(* const callback)(struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg);
-	ao2_iterator *(* const iterator_init)(struct ao2_container *c, int flags);
+	struct ao2_iterator *(* const iterator_init)(struct ao2_container *c, int flags);
 	void *(* const iterator_next)(struct ao2_iterator *a);
-	void (const destroy)(void);
+	void (* const destroy)(struct ao2_container *c);
 };
 
 /*! \brief
@@ -667,7 +668,7 @@
 #define ao2_container_alloc(arg1,arg2,arg3)        ao2_hashtable_alloc_debug((arg1), (arg2), (arg3), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__)
 #else
 #define ao2_t_container_alloc(arg1,arg2,arg3,arg4) ao2_hashtable_alloc((arg1), (arg2), (arg3))
-#define ao2_container_alloc(arg1,arg2,arg3)        ao2_hasthable_alloc((arg1), (arg2), (arg3))
+#define ao2_container_alloc(arg1,arg2,arg3)        ao2_hashtable_alloc((arg1), (arg2), (arg3))
 #endif
 
 /* Container-specific allocation functions

Modified: team/mmichelson/ao2_containers/include/asterisk/astobj2_private.h
URL: http://svn.digium.com/view/asterisk/team/mmichelson/ao2_containers/include/asterisk/astobj2_private.h?view=diff&rev=140400&r1=140399&r2=140400
==============================================================================
--- team/mmichelson/ao2_containers/include/asterisk/astobj2_private.h (original)
+++ team/mmichelson/ao2_containers/include/asterisk/astobj2_private.h Thu Aug 28 14:37:39 2008
@@ -1,3 +1,8 @@
+#ifndef ASTOBJ2_PRIVATE_H
+#define ASTOBJ2_PRIVATE_H
+
+#include "asterisk.h"
+#include "asterisk/lock.h"
 
 /*!
  * A container; stores the hash and callback functions, information on
@@ -33,31 +38,48 @@
 };
 
 /*!
+ * astobj2 objects are always preceded by this data structure,
+ * which contains a lock, a reference counter,
+ * the flags and a pointer to a destructor.
+ * The refcount is used to decide when it is time to
+ * invoke the destructor.
+ * The magic number is used for consistency check.
+ * XXX the lock is not always needed, and its initialization may be
+ * expensive. Consider making it external.
+ */
+struct __priv_data {
+	ast_mutex_t lock;
+	int ref_counter;
+	ao2_destructor_fn destructor_fn;
+	/*! for stats */
+	size_t data_size;
+	/*! magic number.  This is used to verify that a pointer passed in is a
+	 *  valid astobj2 */
+	uint32_t magic;
+};
+/*!
+ * What an astobj2 object looks like: fixed-size private data
+ * followed by variable-size user data.
+ */
+struct astobj2 {
+	struct __priv_data priv_data;
+	void *user_data[0];
+};
+
+/*!
  * \brief convert from a pointer _p to an astobj2 object
  *
  * \return the pointer to the user-defined portion.
  */
 #define EXTERNAL_OBJ(_p)	((_p) == NULL ? NULL : (_p)->user_data)
 
-/*!
- * \brief convert from a pointer _p to a user-defined object
+/*! \brief common allocation routine for all types of containers
  *
- * \return the pointer to the astobj2 structure
+ * To avoid repeating the same code in all container allocation
+ * routines, this serves as the starting point which allocates
+ * the container and sets the base values for all of the 
+ * non-container-specific data
  */
-inline struct astobj2 *INTERNAL_OBJ(void *user_data)
-{
-	struct astobj2 *p;
+struct ao2_container *ao2_container_common_alloc(ao2_callback_fn *cmp_fn, const struct ao2_container_impl *impl);
 
-	if (!user_data) {
-		ast_log(LOG_ERROR, "user_data is NULL\n");
-		return NULL;
-	}
-
-	p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
-	if (AO2_MAGIC != (p->priv_data.magic) ) {
-		ast_log(LOG_ERROR, "bad magic number 0x%x for %p\n", p->priv_data.magic, p);
-		p = NULL;
-	}
-
-	return p;
-}
+#endif /*ASTOBJ2_PRIVATE_H*/

Modified: team/mmichelson/ao2_containers/main/Makefile
URL: http://svn.digium.com/view/asterisk/team/mmichelson/ao2_containers/main/Makefile?view=diff&rev=140400&r1=140399&r2=140400
==============================================================================
--- team/mmichelson/ao2_containers/main/Makefile (original)
+++ team/mmichelson/ao2_containers/main/Makefile Thu Aug 28 14:37:39 2008
@@ -27,7 +27,7 @@
 	netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
 	cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \
 	strcompat.o threadstorage.o dial.o event.o adsistub.o audiohook.o \
-	astobj2.o hashtab.o global_datastores.o version.o \
+	astobj2.o astobj2_hashtable.o hashtab.o global_datastores.o version.o \
 	features.o taskprocessor.o timing.o datastore.o
 
 # we need to link in the objects statically, not as a library, because

Modified: team/mmichelson/ao2_containers/main/astobj2.c
URL: http://svn.digium.com/view/asterisk/team/mmichelson/ao2_containers/main/astobj2.c?view=diff&rev=140400&r1=140399&r2=140400
==============================================================================
--- team/mmichelson/ao2_containers/main/astobj2.c (original)
+++ team/mmichelson/ao2_containers/main/astobj2.c Thu Aug 28 14:37:39 2008
@@ -28,37 +28,7 @@
 #include "asterisk/astobj2_private.h"
 #define REF_FILE "/tmp/refs"
 
-/*!
- * astobj2 objects are always preceded by this data structure,
- * which contains a lock, a reference counter,
- * the flags and a pointer to a destructor.
- * The refcount is used to decide when it is time to
- * invoke the destructor.
- * The magic number is used for consistency check.
- * XXX the lock is not always needed, and its initialization may be
- * expensive. Consider making it external.
- */
-struct __priv_data {
-	ast_mutex_t lock;
-	int ref_counter;
-	ao2_destructor_fn destructor_fn;
-	/*! for stats */
-	size_t data_size;
-	/*! magic number.  This is used to verify that a pointer passed in is a
-	 *  valid astobj2 */
-	uint32_t magic;
-};
-
 #define	AO2_MAGIC	0xa570b123
-
-/*!
- * What an astobj2 object looks like: fixed-size private data
- * followed by variable-size user data.
- */
-struct astobj2 {
-	struct __priv_data priv_data;
-	void *user_data[0];
-};
 
 #ifdef AST_DEVMODE
 #define AO2_DEBUG 1
@@ -98,17 +68,35 @@
 }
 #endif
 
+/*!
+ * \brief convert from a pointer _p to a user-defined object
+ *
+ * \return the pointer to the astobj2 structure
+ */
+static inline struct astobj2 *INTERNAL_OBJ(void *user_data)
+{
+	struct astobj2 *p;
+
+	if (!user_data) {
+		ast_log(LOG_ERROR, "user_data is NULL\n");
+		return NULL;
+	}
+
+	p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
+	if (AO2_MAGIC != (p->priv_data.magic) ) {
+		ast_log(LOG_ERROR, "bad magic number 0x%x for %p\n", p->priv_data.magic, p);
+		p = NULL;
+	}
+
+	return p;
+}
 /* the underlying functions common to debug and non-debug versions */
 
 static int __ao2_ref(void *user_data, const int delta);
 static void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn);
-static struct ao2_container *__ao2_container_alloc(struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn,
-											ao2_callback_fn *cmp_fn);
-static struct bucket_list *__ao2_link(struct ao2_container *c, void *user_data);
 static void *__ao2_callback(struct ao2_container *c,
 	const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg,
 					 char *tag, char *file, int line, const char *funcname);
-static void * __ao2_iterator_next(struct ao2_iterator *a, struct bucket_list **q);
 
 int ao2_lock(void *user_data)
 {
@@ -302,72 +290,30 @@
 /* internal callback to destroy a container. */
 static void container_destruct(void *c);
 
+#if 0
 /* internal callback to destroy a container. */
 static void container_destruct_debug(void *c);
-
-/* each bucket in the container is a tailq. */
-AST_LIST_HEAD_NOLOCK(bucket, bucket_list);
-
-/*!
- * \brief always zero hash function
- *
- * it is convenient to have a hash function that always returns 0.
- * This is basically used when we want to have a container that is
- * a simple linked list.
- *
- * \returns 0
- */
-static int hash_zero(const void *user_obj, const int flags)
-{
-	return 0;
-}
+#endif
 
 /*
  * A container is just an object, after all!
  */
-static struct ao2_container *__ao2_container_alloc(struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn,
-											ao2_callback_fn *cmp_fn)
-{
-	/* XXX maybe consistency check on arguments ? */
-	/* compute the container size */
+struct ao2_container *ao2_container_common_alloc(ao2_callback_fn *cmp_fn, const struct ao2_container_impl *impl)
+{
+	struct ao2_container *c = ao2_alloc(sizeof(*c), container_destruct);
 
 	if (!c)
 		return NULL;
 	
 	c->version = 1;	/* 0 is a reserved value here */
-	c->n_buckets = n_buckets;
-	c->hash_fn = hash_fn ? hash_fn : hash_zero;
 	c->cmp_fn = cmp_fn;
+	c->impl = impl;
 
 #ifdef AO2_DEBUG
 	ast_atomic_fetchadd_int(&ao2.total_containers, 1);
 #endif
 
 	return c;
-}
-
-struct ao2_container *_ao2_container_alloc_debug(const uint n_buckets, ao2_hash_fn *hash_fn,
-		ao2_callback_fn *cmp_fn, char *tag, char *file, int line, const char *funcname)
-{
-	/* XXX maybe consistency check on arguments ? */
-	/* compute the container size */
-	size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
-	struct ao2_container *c = _ao2_alloc_debug(container_size, container_destruct_debug, tag, file, line, funcname);
-
-	return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
-}
-
-struct ao2_container *
-_ao2_container_alloc(const uint n_buckets, ao2_hash_fn *hash_fn,
-		ao2_callback_fn *cmp_fn)
-{
-	/* XXX maybe consistency check on arguments ? */
-	/* compute the container size */
-
-	size_t container_size = sizeof(struct ao2_container) + n_buckets * sizeof(struct bucket);
-	struct ao2_container *c = _ao2_alloc(container_size, container_destruct);
-
-	return __ao2_container_alloc(c, n_buckets, hash_fn, cmp_fn);
 }
 
 /*!
@@ -481,7 +427,8 @@
 	const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg,
 	char *tag, char *file, int line, const char *funcname)
 {
-	void *ret = NULL;
+	struct astobj2 *ret = NULL;
+	void *user_data = NULL;
 
 	if (INTERNAL_OBJ(c) == NULL)	/* safety check on the argument */
 		return NULL;
@@ -500,11 +447,11 @@
 	ret = c->impl->callback(c, flags, cb_fn, arg);
 
 	if (ret)
-		ret = EXTERNAL_OBJ(ret);
+		user_data = EXTERNAL_OBJ(ret);
 	
 	ao2_unlock(c);
 
-	return ret;
+	return user_data;
 }
 
 void *_ao2_callback_debug(struct ao2_container *c,
@@ -549,15 +496,16 @@
 
 void * _ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname)
 {
-	void *ret = NULL;
+	struct astobj2 *ret = NULL;
+	void *user_data = NULL;
 
 	if (!(a->flags & F_AO2I_DONTLOCK))
 		ao2_lock(a->c);
 
-	ret = c->impl->iterator_next(a);
+	ret = a->c->impl->iterator_next(a);
 	
 	if (ret) {
-		ret = EXTERNAL_OBJ(ret);
+		user_data = EXTERNAL_OBJ(ret);
 		/* inc refcount of returned object */
 		_ao2_ref_debug(ret, 1, tag, file, line, funcname);
 	}
@@ -565,20 +513,21 @@
 	if (!(a->flags & F_AO2I_DONTLOCK))
 		ao2_unlock(a->c);
 
-	return ret;
+	return user_data;
 }
 
 void * _ao2_iterator_next(struct ao2_iterator *a)
 {
-	void *ret = NULL;
+	struct astobj2 *ret = NULL;
+	void *user_data = NULL;
 
 	if (!(a->flags & F_AO2I_DONTLOCK))
 		ao2_lock(a->c);
 
-	ret = c->impl->iterator_next(a);
+	ret = a->c->impl->iterator_next(a);
 	
 	if (ret) {
-		ret = EXTERNAL_OBJ(ret);
+		user_data = EXTERNAL_OBJ(ret);
 		/* inc refcount of returned object */
 		_ao2_ref(ret, 1);
 	}
@@ -586,7 +535,7 @@
 	if (!(a->flags & F_AO2I_DONTLOCK))
 		ao2_unlock(a->c);
 
-	return ret;
+	return user_data;
 }
 
 /* callback for destroying container.
@@ -597,17 +546,17 @@
 	_ao2_ref(obj, -1);
 	return 0;
 }
-	
+#if 0
 static int cd_cb_debug(void *obj, void *arg, int flag)
 {
 	_ao2_ref_debug(obj, -1, "deref object via container destroy",  __FILE__, __LINE__, __PRETTY_FUNCTION__);
 	return 0;
 }
+#endif
 	
 static void container_destruct(void *_c)
 {
 	struct ao2_container *c = _c;
-	int i;
 
 	_ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
 
@@ -617,11 +566,10 @@
 	ast_atomic_fetchadd_int(&ao2.total_containers, -1);
 #endif
 }
-
+#if 0
 static void container_destruct_debug(void *_c)
 {
 	struct ao2_container *c = _c;
-	int i;
 
 	_ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
 
@@ -631,6 +579,7 @@
 	ast_atomic_fetchadd_int(&ao2.total_containers, -1);
 #endif
 }
+#endif
 
 #ifdef AO2_DEBUG
 static int print_cb(void *obj, void *arg, int flag)

Modified: team/mmichelson/ao2_containers/main/astobj2_hashtable.c
URL: http://svn.digium.com/view/asterisk/team/mmichelson/ao2_containers/main/astobj2_hashtable.c?view=diff&rev=140400&r1=140399&r2=140400
==============================================================================
--- team/mmichelson/ao2_containers/main/astobj2_hashtable.c (original)
+++ team/mmichelson/ao2_containers/main/astobj2_hashtable.c Thu Aug 28 14:37:39 2008
@@ -18,6 +18,13 @@
 
 #include "asterisk/astobj2.h"
 #include "asterisk/astobj2_private.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/utils.h"
+
+static void *hashtable_link(struct ao2_container *c, struct astobj2 *newobj);
+static void *hashtable_callback(struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg);
+static void *hashtable_iterator_next(struct ao2_iterator *a);
+static void hashtable_destroy(struct ao2_container *c);
 
 static const struct ao2_container_impl hashtable_impl = {
 	.link = hashtable_link,
@@ -45,7 +52,44 @@
 	struct astobj2 *astobj;		/* pointer to internal data */
 };
 
-static void *hashtable_link(struct ao2_container *c, void *newobj)
+/*!
+ * \brief always zero hash function
+ *
+ * it is convenient to have a hash function that always returns 0.
+ * This is basically used when we want to have a container that is
+ * a simple linked list.
+ *
+ * \returns 0
+ */
+static int hash_zero(const void *user_obj, const int flags)
+{
+	return 0;
+}
+
+struct ao2_container *ao2_hashtable_alloc(uint n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
+{
+	struct hashtable_pvt *hash_pvt;
+	struct ao2_container *hashtable;
+	/* Handle the common allocation first */
+
+	if (!(hashtable = ao2_container_common_alloc(cmp_fn, &hashtable_impl))) {
+		/* OH CRAP */
+		return NULL;
+	}
+
+	if (!(hash_pvt = ast_calloc(1, sizeof (*hash_pvt) + (n_buckets * sizeof(struct bucket))))) {
+		/* OH CRAP */
+		return NULL;
+	}
+
+	hash_pvt->n_buckets = n_buckets;
+	hash_pvt->hash_fn = hash_fn ? hash_fn : hash_zero;
+	hashtable->private = hash_pvt;
+
+	return hashtable;
+}
+
+static void *hashtable_link(struct ao2_container *c, struct astobj2 *newobj)
 {
 	struct bucket_list *bl;
 	int bucket_number;
@@ -55,12 +99,12 @@
 		return NULL;
 	}
 
-	bucket_number = hash_pvt->hash_fn(EXTERNAL_OBJ(newobj));
+	bucket_number = hash_pvt->hash_fn(EXTERNAL_OBJ(newobj), OBJ_POINTER);
 
 	bucket_number %= hash_pvt->n_buckets;
 	bl->astobj = newobj;
 	bl->version = ast_atomic_fetchadd_int(&c->version, 1);
-	AST_LIST_INSERT_TAIL(&hash_pvt->buckets[i], bl, entry);
+	AST_LIST_INSERT_TAIL(&hash_pvt->buckets[bucket_number], bl, entry);
 	return bl;
 }
 
@@ -77,7 +121,7 @@
 	 * (this only for the time being. We need to optimize this.)
 	 */
 	if ((flags & OBJ_POINTER))	/* we know hash can handle this case */
-		i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets;
+		i = hash_pvt->hash_fn(arg, flags & OBJ_POINTER) % hash_pvt->n_buckets;
 	else			/* don't know, let's scan all buckets */
 		i = -1;		/* XXX this must be fixed later. */
 
@@ -106,7 +150,7 @@
 			/* we have a match (CMP_MATCH) here */
 			if (!(flags & OBJ_NODATA)) {	/* if must return the object, record the value */
 				/* it is important to handle this case before the unlink */
-				ao2_ref(EXTERNAL_OBJ(ret), 1);
+				ao2_ref(EXTERNAL_OBJ(cur->astobj), 1);
 			}
 
 			if (flags & OBJ_UNLINK) {	/* must unlink */
@@ -185,11 +229,11 @@
 	return ret;
 }
 
-void *hashtable_destroy(struct ao2_container *c)
+void hashtable_destroy(struct ao2_container *c)
 {
 	struct hashtable_pvt *hash_pvt = c->private;
 	int i;
-	for (i = 0; i < c->n_buckets; i++) {
+	for (i = 0; i < hash_pvt->n_buckets; i++) {
 		struct bucket_list *current;
 
 		while ((current = AST_LIST_REMOVE_HEAD(&hash_pvt->buckets[i], entry))) {

Modified: team/mmichelson/ao2_containers/utils/Makefile
URL: http://svn.digium.com/view/asterisk/team/mmichelson/ao2_containers/utils/Makefile?view=diff&rev=140400&r1=140399&r2=140400
==============================================================================
--- team/mmichelson/ao2_containers/utils/Makefile (original)
+++ team/mmichelson/ao2_containers/utils/Makefile Thu Aug 28 14:37:39 2008
@@ -76,7 +76,7 @@
 	rm -f *.s *.i
 	rm -f md5.c strcompat.c ast_expr2.c ast_expr2f.c pbx_ael.c pval.c hashtab.c
 	rm -f aelparse.c aelbison.c conf2ael
-	rm -f utils.c threadstorage.c sha1.c astobj2.c hashtest2 hashtest refcounter
+	rm -f utils.c threadstorage.c sha1.c astobj2.c astobj2_hashtable.c hashtest2 hashtest refcounter
 
 md5.c: $(ASTTOPDIR)/main/md5.c
 	@cp $< $@
@@ -135,6 +135,9 @@
 astobj2.c: $(ASTTOPDIR)/main/astobj2.c
 	@cp $< $@
 
+astobj2_hashtable.c: $(ASTTOPDIR)/main/astobj2_hashtable.c
+	@cp $< $@
+
 utils.c: $(ASTTOPDIR)/main/utils.c
 	@cp $< $@
 
@@ -146,7 +149,7 @@
 
 hashtest2.o: ASTCFLAGS+=-O0
 
-hashtest2: hashtest2.o md5.o utils.o astobj2.o sha1.o strcompat.o threadstorage.o clicompat.o
+hashtest2: hashtest2.o md5.o utils.o astobj2.o astobj2_hashtable.o sha1.o strcompat.o threadstorage.o clicompat.o
 
 hashtest: hashtest.o md5.o hashtab.o utils.o sha1.o strcompat.o threadstorage.o clicompat.o
 




More information about the svn-commits mailing list