[svn-commits] mmichelson: branch mmichelson/ao2_containers r140276 - in /team/mmichelson/ao...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Tue Aug 26 18:04:09 CDT 2008
Author: mmichelson
Date: Tue Aug 26 18:04:08 2008
New Revision: 140276
URL: http://svn.digium.com/view/asterisk?view=rev&rev=140276
Log:
Progress. This code does not compile currently.
The first step was to add container-specific callbacks
so that each container operation can be customized
depending on the container used. The ao2_container_impl
struct in astobj2.h handles this.
These callbacks are now peppered throughout astobj2.c
in place of the hash table-specific code. The one function
that has not been taken care of yet is ao2_container_alloc.
It will be taken care of in the next phase, which is to
port the former hash table material to its own file.
Modified:
team/mmichelson/ao2_containers/include/asterisk/astobj2.h
team/mmichelson/ao2_containers/main/astobj2.c
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=140276&r1=140275&r2=140276
==============================================================================
--- team/mmichelson/ao2_containers/include/asterisk/astobj2.h (original)
+++ team/mmichelson/ao2_containers/include/asterisk/astobj2.h Tue Aug 26 18:04:08 2008
@@ -636,6 +636,15 @@
*/
/*@{ */
struct ao2_container;
+
+struct ao2_container_impl {
+ void *(* const link)(struct ao2_container *c, void *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);
+ void *(* const iterator_next)(struct ao2_iterator *a);
+ void (const destroy)(void);
+};
/*! \brief
* Allocate and initialize a container
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=140276&r1=140275&r2=140276
==============================================================================
--- team/mmichelson/ao2_containers/main/astobj2.c (original)
+++ team/mmichelson/ao2_containers/main/astobj2.c Tue Aug 26 18:04:08 2008
@@ -360,15 +360,13 @@
* we hold the lock (that we need anyways).
*/
struct ao2_container {
- ao2_hash_fn *hash_fn;
+ const struct ao2_container_impl *impl;
ao2_callback_fn *cmp_fn;
- int n_buckets;
/*! Number of elements in the container */
int elements;
/*! described above */
int version;
- /*! variable size */
- struct bucket buckets[0];
+ void *private_data;
};
/*!
@@ -385,6 +383,7 @@
return 0;
}
+
/*
* A container is just an object, after all!
*/
@@ -441,27 +440,10 @@
return c->elements;
}
-/*!
- * A structure to create a linked list of entries,
- * used within a bucket.
- * XXX \todo this should be private to the container code
- */
-struct bucket_list {
- AST_LIST_ENTRY(bucket_list) entry;
- int version;
- struct astobj2 *astobj; /* pointer to internal data */
-};
-
-/*
- * link an object to a container
- */
-
-static struct bucket_list *__ao2_link(struct ao2_container *c, void *user_data)
-{
- int i;
- /* create a new list entry */
- struct bucket_list *p;
+void *_ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
+{
struct astobj2 *obj = INTERNAL_OBJ(user_data);
+ void *link_result = NULL;
if (!obj)
return NULL;
@@ -469,43 +451,41 @@
if (INTERNAL_OBJ(c) == NULL)
return NULL;
- p = ast_calloc(1, sizeof(*p));
- if (!p)
- return NULL;
-
- i = c->hash_fn(user_data, OBJ_POINTER);
-
ao2_lock(c);
- i %= c->n_buckets;
- p->astobj = obj;
- p->version = ast_atomic_fetchadd_int(&c->version, 1);
- AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
- ast_atomic_fetchadd_int(&c->elements, 1);
-
- /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
- return p;
-}
-
-void *_ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
-{
- struct bucket_list *p = __ao2_link(c, user_data);
-
- if (p) {
+
+ link_result = c->impl->link(c, user_data);
+
+ if (link_result) {
_ao2_ref_debug(user_data, +1, tag, file, line, funcname);
- ao2_unlock(c);
- }
- return p;
+ }
+
+ ao2_unlock(c);
+
+ return link_result;
}
void *_ao2_link(struct ao2_container *c, void *user_data)
{
- struct bucket_list *p = __ao2_link(c, user_data);
-
- if (p) {
+ struct astobj2 *obj = INTERNAL_OBJ(user_data);
+ void *link_result = NULL;
+
+ if (!obj)
+ return NULL;
+
+ if (INTERNAL_OBJ(c) == NULL)
+ return NULL;
+
+ ao2_lock(c);
+
+ link_result = c->impl->link(c, user_data);
+
+ if (link_result) {
_ao2_ref(user_data, +1);
- ao2_unlock(c);
- }
- return p;
+ }
+
+ ao2_unlock(c);
+
+ return link_result;
}
/*!
@@ -562,7 +542,6 @@
const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg,
char *tag, char *file, int line, const char *funcname)
{
- int i, last; /* search boundaries */
void *ret = NULL;
if (INTERNAL_OBJ(c) == NULL) /* safety check on the argument */
@@ -576,83 +555,23 @@
/* override the match function if necessary */
if (cb_fn == NULL) /* if NULL, match everything */
cb_fn = cb_true;
- /*
- * XXX this can be optimized.
- * If we have a hash function and lookup by pointer,
- * run the hash function. Otherwise, scan the whole container
- * (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;
- else /* don't know, let's scan all buckets */
- i = -1; /* XXX this must be fixed later. */
-
- /* determine the search boundaries: i..last-1 */
- if (i < 0) {
- i = 0;
- last = c->n_buckets;
- } else {
- last = i + 1;
- }
ao2_lock(c); /* avoid modifications to the content */
-
- for (; i < last ; i++) {
- /* scan the list with prev-cur pointers */
- struct bucket_list *cur;
-
- AST_LIST_TRAVERSE_SAFE_BEGIN(&c->buckets[i], cur, entry) {
- int match = cb_fn(EXTERNAL_OBJ(cur->astobj), arg, flags) & (CMP_MATCH | CMP_STOP);
-
- /* we found the object, performing operations according flags */
- if (match == 0) { /* no match, no stop, continue */
- continue;
- } else if (match == CMP_STOP) { /* no match but stop, we are done */
- i = last;
- break;
- }
- /* 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 */
- ret = EXTERNAL_OBJ(cur->astobj);
- if (tag)
- _ao2_ref_debug(ret, 1, tag, file, line, funcname);
- else
- _ao2_ref(ret, 1);
- }
-
- if (flags & OBJ_UNLINK) { /* must unlink */
- struct bucket_list *x = cur;
-
- /* we are going to modify the container, so update version */
- ast_atomic_fetchadd_int(&c->version, 1);
- AST_LIST_REMOVE_CURRENT(entry);
- /* update number of elements and version */
- ast_atomic_fetchadd_int(&c->elements, -1);
- if (tag)
- _ao2_ref_debug(EXTERNAL_OBJ(x->astobj), -1, tag, file, line, funcname);
- else
- _ao2_ref(EXTERNAL_OBJ(x->astobj), -1);
- free(x); /* free the link record */
- }
-
- if ((match & CMP_STOP) || (flags & OBJ_MULTIPLE) == 0) {
- /* We found the only match we need */
- i = last; /* force exit from outer loop */
- break;
- }
- if (!(flags & OBJ_NODATA)) {
-#if 0 /* XXX to be completed */
- /*
- * This is the multiple-return case. We need to link
- * the object in a list. The refcount is already increased.
- */
-#endif
- }
- }
- AST_LIST_TRAVERSE_SAFE_END;
- }
+
+ ret = c->impl->callback(c, flags, cb_fn, arg);
+
+ if (ret)
+ ret = EXTERNAL_OBJ(ret);
+
+ if (ret && !(flags & OBJ_NODATA)) {
+ if (tag)
+ _ao2_ref_debug(ret, 1, tag, file, line, funcname);
+ else
+ _ao2_ref(ret, 1);
+ }
+
ao2_unlock(c);
+
return ret;
}
@@ -696,72 +615,17 @@
return a;
}
-/*
- * move to the next element in the container.
- */
-static void * __ao2_iterator_next(struct ao2_iterator *a, struct bucket_list **q)
-{
- int lim;
- struct bucket_list *p = NULL;
+void * _ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname)
+{
void *ret = NULL;
-
- *q = NULL;
-
- if (INTERNAL_OBJ(a->c) == NULL)
- return NULL;
if (!(a->flags & F_AO2I_DONTLOCK))
ao2_lock(a->c);
- /* optimization. If the container is unchanged and
- * we have a pointer, try follow it
- */
- if (a->c->version == a->c_version && (p = a->obj) ) {
- if ( (p = AST_LIST_NEXT(p, entry)) )
- goto found;
- /* nope, start from the next bucket */
- a->bucket++;
- a->version = 0;
- a->obj = NULL;
- }
-
- lim = a->c->n_buckets;
-
- /* Browse the buckets array, moving to the next
- * buckets if we don't find the entry in the current one.
- * Stop when we find an element with version number greater
- * than the current one (we reset the version to 0 when we
- * switch buckets).
- */
- for (; a->bucket < lim; a->bucket++, a->version = 0) {
- /* scan the current bucket */
- AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) {
- if (p->version > a->version)
- goto found;
- }
- }
-
-found:
- if (p) {
- a->version = p->version;
- a->obj = p;
- a->c_version = a->c->version;
- ret = EXTERNAL_OBJ(p->astobj);
- /* inc refcount of returned object */
- *q = p;
- }
-
- return ret;
-}
-
-void * _ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname)
-{
- struct bucket_list *p;
- void *ret = NULL;
-
- ret = __ao2_iterator_next(a, &p);
-
- if (p) {
+ ret = c->impl->iterator_next(a);
+
+ if (ret) {
+ ret = EXTERNAL_OBJ(ret);
/* inc refcount of returned object */
_ao2_ref_debug(ret, 1, tag, file, line, funcname);
}
@@ -774,12 +638,15 @@
void * _ao2_iterator_next(struct ao2_iterator *a)
{
- struct bucket_list *p = NULL;
void *ret = NULL;
- ret = __ao2_iterator_next(a, &p);
-
- if (p) {
+ if (!(a->flags & F_AO2I_DONTLOCK))
+ ao2_lock(a->c);
+
+ ret = c->impl->iterator_next(a);
+
+ if (ret) {
+ ret = EXTERNAL_OBJ(ret);
/* inc refcount of returned object */
_ao2_ref(ret, 1);
}
@@ -832,13 +699,7 @@
_ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
- for (i = 0; i < c->n_buckets; i++) {
- struct bucket_list *current;
-
- while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
- ast_free(current);
- }
- }
+ c->impl->destroy();
#ifdef AO2_DEBUG
ast_atomic_fetchadd_int(&ao2.total_containers, -1);
More information about the svn-commits
mailing list