[asterisk-commits] mmichelson: branch mmichelson/ao2_containers r140400 - in /team/mmichelson/ao...
SVN commits to the Asterisk project
asterisk-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 asterisk-commits
mailing list