[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