[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