[asterisk-commits] mmichelson: branch mmichelson/ao2_containers r140282 - in /team/mmichelson/ao...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Aug 26 19:58:36 CDT 2008


Author: mmichelson
Date: Tue Aug 26 19:58:36 2008
New Revision: 140282

URL: http://svn.digium.com/view/asterisk?view=rev&rev=140282
Log:
More progress. Still doesn't compile.

First, I have modified ao2_container_alloc to
allocate a hash table (this hash table allocation
function is presently not implemented).

Second, I have now moved hash table-specific
functions to a new file, main/astobj2_hashtable.c.

My main problem right now is that I need a good way
to implement a C analogue of C++'s "protected" keyword.
Essentially, I want just about all ao2_container data
to be private to astobj2.c as well as the various
container-specific source files. I figure that what
I can do is have a single allocation point which allocates
the containers and passes pointers to necessary functions
which will allow me to update parameters of the ao2_container
structure and call functions which are local to astobj2.c.
The other option is to place container-specific implementations
inside of astobj2.c, but I really don't want to do this.
ao2_internal_ref was a half-baked attempt at being able
to change the reference count on user data which already
had INTERNAL_OBJ called on it and will be removed or modified
in an upcoming commit.


Added:
    team/mmichelson/ao2_containers/main/astobj2_hashtable.c   (with props)
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=140282&r1=140281&r2=140282
==============================================================================
--- team/mmichelson/ao2_containers/include/asterisk/astobj2.h (original)
+++ team/mmichelson/ao2_containers/include/asterisk/astobj2.h Tue Aug 26 19:58:36 2008
@@ -446,6 +446,15 @@
 int _ao2_ref_debug(void *o, int delta, char *tag, char *file, int line, const char *funcname);
 int _ao2_ref(void *o, int delta);
 
+/* \brief
+ * Reference/unreference an internal astobj2 and return the old refcount.
+ *
+ * This functions exactly like ao2_ref, but must be used
+ * by the ao2_container implementations if they wish to
+ * increase the reference count on an object.
+ */
+int ao2_internal_ref(void *astobj, const int delta);
+
 /*! \brief
  * Lock an object.
  * 
@@ -663,17 +672,19 @@
  */
 
 #ifdef REF_DEBUG
-#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) _ao2_container_alloc_debug((arg1), (arg2), (arg3), (arg4),  __FILE__, __LINE__, __PRETTY_FUNCTION__)
-#define ao2_container_alloc(arg1,arg2,arg3)        _ao2_container_alloc_debug((arg1), (arg2), (arg3), "",  __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#define ao2_t_container_alloc(arg1,arg2,arg3,arg4) ao2_hashtable_alloc_debug((arg1), (arg2), (arg3), (arg4),  __FILE__, __LINE__, __PRETTY_FUNCTION__)
+#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_container_alloc((arg1), (arg2), (arg3))
-#define ao2_container_alloc(arg1,arg2,arg3)        _ao2_container_alloc((arg1), (arg2), (arg3))
+#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))
 #endif
-struct ao2_container *_ao2_container_alloc(const uint n_buckets,
+
+/* Container-specific allocation functions
+ * Each of these may be called in order to create a 
+ * new ao2_container of the type desired
+ */
+struct ao2_container *ao2_hashtable_alloc(const uint n_buckets,
 										  ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn);
-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);
 
 /*! \brief
  * Returns the number of elements in 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=140282&r1=140281&r2=140282
==============================================================================
--- team/mmichelson/ao2_containers/main/astobj2.c (original)
+++ team/mmichelson/ao2_containers/main/astobj2.c Tue Aug 26 19:58:36 2008
@@ -215,6 +215,12 @@
 			fclose(refo);
 	}
 	return __ao2_ref(user_data, delta);
+}
+
+int ao2_internal_ref(void *obj, const int delta)
+{
+	void *user_data = EXTERNAL_OBJ(obj);
+	return ao2_ref(user_data, delta);
 }
 
 int _ao2_ref(void *user_data, const int delta)
@@ -366,7 +372,8 @@
 	int elements;
 	/*! described above */
 	int version;
-	void *private_data;
+	/*! container data specific to each implementation */
+	void *private;
 };
  
 /*!
@@ -453,7 +460,7 @@
 
 	ao2_lock(c);
 
-	link_result = c->impl->link(c, user_data);
+	link_result = c->impl->link(c, obj);
 	
 	if (link_result) {
 		_ao2_ref_debug(user_data, +1, tag, file, line, funcname);
@@ -477,10 +484,11 @@
 
 	ao2_lock(c);
 
-	link_result = c->impl->link(c, user_data);
+	link_result = c->impl->link(c, obj);
 
 	if (link_result) {
 		_ao2_ref(user_data, +1);
+		ast_atomic_fetchadd_int(&c->elements, 1);
 	}
 	
 	ao2_unlock(c);
@@ -562,13 +570,6 @@
 
 	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);
 
@@ -679,13 +680,7 @@
 
 	_ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
 
-	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(c);
 
 #ifdef AO2_DEBUG
 	ast_atomic_fetchadd_int(&ao2.total_containers, -1);
@@ -699,7 +694,7 @@
 
 	_ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
 
-	c->impl->destroy();
+	c->impl->destroy(c);
 
 #ifdef AO2_DEBUG
 	ast_atomic_fetchadd_int(&ao2.total_containers, -1);

Added: team/mmichelson/ao2_containers/main/astobj2_hashtable.c
URL: http://svn.digium.com/view/asterisk/team/mmichelson/ao2_containers/main/astobj2_hashtable.c?view=auto&rev=140282
==============================================================================
--- team/mmichelson/ao2_containers/main/astobj2_hashtable.c (added)
+++ team/mmichelson/ao2_containers/main/astobj2_hashtable.c Tue Aug 26 19:58:36 2008
@@ -1,0 +1,204 @@
+/*
+ * astobj2 - replacement containers for asterisk data structures.
+ *
+ * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+#include "asterisk.h"
+
+#include "asterisk/astobj2.h"
+
+static const struct ao2_container_impl hashtable_impl = {
+	.link = hashtable_link,
+	.callback = hashtable_callback,
+	.iterator_next = hashtable_iterator_next,
+	.destroy = hashtable_destroy,
+};
+
+AST_LIST_HEAD_NOLOCK(bucket, bucket_list);
+
+struct hashtable_pvt {
+	int n_buckets;
+	ao2_hash_fn *hash_fn;
+	struct bucket buckets[0];
+};
+
+/*!
+ * 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 */
+};
+
+static void *hashtable_link(struct ao2_container *c, void *newobj)
+{
+	struct bucket_list *bl;
+	int bucket_number;
+	struct hashtable_pvt *hash_pvt = c->private;
+
+	if (!(bl = ast_calloc(1, sizeof(*bl)))) {
+		return NULL;
+	}
+
+	/*XXX this is hashing the INTERNAL_OBJ'd user data.
+	 * This is incorrect. Fix later
+	 */
+	bucket_number = hash_pvt->hash_fn(newobj);
+
+	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);
+	return bl;
+}
+
+static void *hashtable_callback(struct ao2_container *c, const enum search_flags flags, ao2_callback_fn *cb_fn, void *arg)
+{
+	int i, last; /* search boundaries */
+	void *ret = NULL;
+	struct hashtable_pvt *hash_pvt = c->private;
+
+	/*
+	 * 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 = hash_pvt->n_buckets;
+	} else {
+		last = i + 1;
+	}
+
+	for (; i < last ; i++) {
+		/* scan the list with prev-cur pointers */
+		struct bucket_list *cur;
+
+		AST_LIST_TRAVERSE_SAFE_BEGIN(&hash_pvt->buckets[i], cur, entry) {
+			/* XXX Use of EXTERNAL_OBJ will break compilation here since it is not a public
+			 * call. Need to find a way around this
+			 */
+			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 */
+				ao2_internal_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);
+				ao2_internal_ref(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;
+	}
+	return ret;
+}
+
+void *hashtable_iterator_next(struct ao2_iterator *a)
+{
+	int lim;
+	struct bucket_list *p = NULL;
+	void *ret = NULL;
+	struct hashtable_pvt *hash_pvt = a->c->private;
+	
+	/* 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 = hash_pvt->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(&hash_pvt->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;
+	}
+
+	return ret;
+}
+
+void *hashtable_destroy(struct ao2_container *c)
+{
+	struct hashtable_pvt *hash_pvt = c->private;
+	int i;
+	for (i = 0; i < c->n_buckets; i++) {
+		struct bucket_list *current;
+
+		while ((current = AST_LIST_REMOVE_HEAD(&hash_pvt->buckets[i], entry))) {
+			ast_free(current);
+		}
+	}
+}

Propchange: team/mmichelson/ao2_containers/main/astobj2_hashtable.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/mmichelson/ao2_containers/main/astobj2_hashtable.c
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision

Propchange: team/mmichelson/ao2_containers/main/astobj2_hashtable.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain




More information about the asterisk-commits mailing list