[svn-commits] rizzo: branch rizzo/astobj2 r45807 - in
/team/rizzo/astobj2: include/asterisk...
svn-commits at lists.digium.com
svn-commits at lists.digium.com
Fri Oct 20 15:07:38 MST 2006
Author: rizzo
Date: Fri Oct 20 17:07:38 2006
New Revision: 45807
URL: http://svn.digium.com/view/asterisk?rev=45807&view=rev
Log:
bring in a very preliminary version of astobj2
Added:
team/rizzo/astobj2/include/asterisk/astobj2.h (with props)
team/rizzo/astobj2/main/astobj2.c (with props)
Modified:
team/rizzo/astobj2/main/Makefile
Added: team/rizzo/astobj2/include/asterisk/astobj2.h
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/include/asterisk/astobj2.h?rev=45807&view=auto
==============================================================================
--- team/rizzo/astobj2/include/asterisk/astobj2.h (added)
+++ team/rizzo/astobj2/include/asterisk/astobj2.h Fri Oct 20 17:07:38 2006
@@ -1,0 +1,441 @@
+/*
+ * 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.
+ */
+
+#ifndef _ASTERISK_ASTOBJ2_H
+#define _ASTERISK_ASTOBJ2_H
+
+#include <inttypes.h>
+#include <strings.h>
+
+#include "asterisk/lock.h"
+
+/*! \file
+ *
+ * \brief Object Model implementing objects and containers.
+ *
+These functions implement a container for user-defined object,
+supporting locking, reference counting and callbacks.
+The internal implementation of the container is, in principle,
+opaque to the user so we can use different data structures
+as needs arise. At the moment, however, the only internal
+data structure is a hash table. When other structures will
+be implemented, the initialization function may change.
+
+A container must first be allocated, specifying the initial
+parameters. At the moment, this is done as follows:
+
+ <b>Sample Usage:</b>
+ \code
+
+ struct container *c;
+
+ c = astobj2_container_alloc(MAX_BUCKETS, my_hash_fn, my_cmp_fn, my_dump_fn);
+
+where
+- MAX_BUCKETS is the number of buckets in the hash table,
+- my_hash_fn() is the (user-supplied) function that returns a
+ hash key for the object (further reduced moduly MAX_BUCKETS
+ by the container's code);
+- my_cmp_fn() is the default comparison function used when doing
+ searches on the container,
+- my_dump_fn() is a helper function used only for debugging.
+
+A container knows little or nothing about the object itself,
+other than the fact that it has been created by astobj2_obj_alloc()
+(which is supposed to provide the extra data field used by
+the container code for manipulation).
+All knowledge of the (user-defined) internals of the object
+is left to the (user-supplied) functions defined above.
+
+An object must be allocated with the function astobj2_obj_alloc(),
+which needs to know the size of the user-defined structure,
+and a pointer to a destructor function that is invoked
+when the object is not referenced anymore:
+
+ struct foo *o;
+
+ o = astobj2_obj_alloc(sizeof(struct foo), my_destructor_fn);
+
+the object return has a refcount = 1.
+Note that the memory for the object is zeroed.
+
+Note that we cannot do free(o) to dispose of the object
+created in this way. Rather, we need to call
+
+ astobj2_ref(o, -1)
+
+which will drop a reference, causing the destructor to be
+called (and then memory freed) when the refcount goes to 0.
+
+If we want to insert the object in the container, we should
+initialize its fields -- especially, those used by my_hash_fn()
+to compute the bucket to use.
+Once done, we can link an object to a container with
+
+ astobj2_link(c, o);
+
+The function returns NULL in case of errors (and the object
+is not inserted in the container). Other values mean success
+(we are not supposed to use the value as a pointer to anything).
+
+\note inserting the object in the container creates another reference
+to the object (owned by the container) so we still need to drop
+ours when we are done.
+
+\note While an object o is in a container, we expect that
+my_hash_fn(o) will always return the same value. The function
+does not lock the object to be computed, so modifications of
+those fields that affect the computation of the hash should
+be done by extractiong the object from the container, and
+reinserting it after the change (this is not terribly expensive).
+
+\note A container with a single buckets is effectively a linked
+list. However there is no ordering among elements.
+
+Objects implement a reference counter keeping the count
+of the number of references that reference an object.
+
+When this number becomes zero the destructor will be
+called and the object will be free'd.
+ */
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+/*!
+ * Invoked just before freeing the memory for the object.
+ * It is passed a pointer to user data.
+ */
+typedef void (*astobj2_destructor_fn)(void *);
+
+/*!
+ * astobj2 objects are always prepended 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.
+ */
+struct astobj2_priv_data {
+ ast_mutex_t lock;
+ int ref_counter;
+ astobj2_destructor_fn destructor_fn;
+};
+
+/*!
+ * What an astobj2 object looks like: fixed-size private data
+ * followed by variable-size user data.
+ */
+struct astobj2 {
+ struct astobj2_priv_data priv_data;
+ void *user_data[0];
+};
+
+/*!
+ * Lock an object.
+ *
+ * \param a A pointer to the object we want lock.
+ * \return 0 on success, other values on error.
+ */
+int astobj2_lock(void *a);
+
+/*!
+ * Unlock an object.
+ *
+ * \param a A pointer to the object we want unlock.
+ * \return 0 on success, other values on error.
+ */
+int astobj2_unlock(void *a);
+
+/*!
+ * Reference/unreference an object.
+ *
+ * \param o A pointer to the object
+ * \param delta Value to add to the reference counter.
+ * \return The value of the reference counter before the operation.
+ *
+ * Increase/decrease the reference counter according
+ * the value of delta.
+ * If the refcount goes to zero, the object is destroyed.
+ * \note: if we know the pointer to an object, it is because we
+ * have a reference count to it, so the only case when the object
+ * can go away is when we release our reference, and it is
+ * the last one in existence.
+ */
+int astobj2_ref(void *o, int delta);
+
+/*!
+ * Allocate and initialize an object.
+ *
+ * \param data_size The sizeof() of user-defined structure.
+ * \param destructor_fn The function destructor (can be NULL)
+ * \return A pointer to user data.
+ *
+ * Allocates a struct astobj2 with sufficient space for the
+ * user-defined structure.
+ * \notes:
+ * - storage is zeroed; XXX maybe we want a flag to enable/disable this.
+ * - the refcount of the object just created is 1
+ * - the returned pointer cannot be free()'d or realloc()'ed;
+ * rather, we just call astobj2_ref(o, -1);
+ */
+void *astobj2_obj_alloc(const size_t data_size,
+ astobj2_destructor_fn destructor_fn);
+
+/*!
+ * We can perform different operation on an object. We do this
+ * according the following flags.
+ */
+enum search_flags {
+ OBJ_UNLINK = 0x01, /* unlink the object found */
+ OBJ_DATA = 0x02, /* on match, return the object. */
+ OBJ_SINGLE = 0x08, /* stop at the first match */
+ OBJ_POINTER = 0x10 /* the pointer is an object pointer */
+};
+
+/*!
+ * Type of a generic function to generate a hash value from an object.
+ *
+ */
+typedef int (*astobj2_hash_fn)(const void *obj, const int is_obj);
+
+/*!
+ * valid callback results:
+ * We return a combination of
+ * CMP_MATCH when the object matches the request,
+ * and CMP_STOP when we should not continue the search further.
+ */
+enum _cb_results {
+ CMP_MATCH = 0x1,
+ CMP_STOP = 0x2,
+};
+
+/*!
+ * generic function to compare objects.
+ * This, as other callbacks, should return a combination of
+ * _cb_results as described above.
+ *
+ * \param o object from container
+ * \param arg search parameters (directly from astobj2_find)
+ * \param flags passed directly from astobj2_find
+ * XXX explain.
+ */
+
+/*!
+ * Type of a generic callback function
+ * \param obj pointer to the (user-defined part) of an object.
+ * \param arg callback argument from astobj2_callback()
+ * \param flags flags from astobj2_callback()
+ * The return values are the same as a compare function.
+ * In fact, they are the same thing.
+ */
+typedef int (*astobj2_callback_fn)(void *obj, void *arg, int flags);
+
+/*! \typedef astobj_dump_fn XXX should go away
+ *
+ * \brief Type of a generic function to dump external values of an objects.
+ */
+typedef void (*astobj2_dump_fn)(const void *obj);
+
+/*!
+ * A structure to create a linked list of entries,
+ * used within a bucket.
+ * XXX this should be private to the container code
+ */
+struct astobj2_bucket_list {
+ struct astobj2_bucket_list *next; /* pointer to next bucket_list */
+ struct astobj2 *obj; /* pointer to internal data */
+};
+
+/*!
+ * Here start declarations of containers.
+ */
+
+/*!
+ * This structure contains the total number of buckets
+ * and variable size array of object pointers.
+ */
+struct container {
+ astobj2_hash_fn hash_fn;
+ astobj2_callback_fn cmp_fn;
+ int n_buckets;
+ int elements; /* number of elements in the container */
+ struct astobj2_bucket_list *buckets[0]; /* variable size */
+};
+
+/*!
+ * Allocate and initialize a container
+ * with the desired number of buckets.
+ *
+ * We allocate space for a struct astobj_container, struct container
+ * and the buckets[] array.
+ *
+ * \param astobj_hash_fn Pointer to a function computing a hash value.
+ * \param astobj_cmp_fn Pointer to a function comparating key-value
+ * with a string. (can be NULL)
+ * \param astobj_dump_fn Pointer to a function dumping the objects value.
+ * used for debug. (can be NULL)
+ * \return A pointer to a struct container.
+ *
+ * destructor is set implicitly.
+ */
+struct container *astobj2_container_alloc(const uint n_buckets,
+ astobj2_hash_fn hash_fn, astobj2_callback_fn cmp_fn);
+
+/*!
+ * Check if a container is empty.
+ *
+ * This function return 0 if the container is empty
+ * otherwise return a non zero value.
+ *
+ * \param c The container to investigate.
+ * \return Zero if the container is empty.
+ */
+int astobj2_container_empty(struct container *c);
+
+/*
+ * Here we have functions to manage objects.
+ *
+ * We can use the functions below on any kind of
+ * object defined by the user.
+ */
+/*!
+ * Add an object to a container.
+ *
+ * \param c the container to operate on.
+ * \param obj the object to be added.
+ * \return NULL on errors, other values on success.
+ *
+ * This function insert an object in a container according its key.
+ *
+ * \note Remember to set the key before calling this function.
+ */
+void *astobj2_link(struct container *c, void *newobj);
+
+/*! \struct Used as return value if the flag OBJ_MULTIPLE is set */
+struct astobj2_list {
+ struct astobj2_list *next;
+ void *obj_pointer;
+};
+
+/*!
+ * astobj2_callback() and astob2_find() are the same thing with only one difference:
+ * the latter uses as a callback the function passed as my_cmp_f() at
+ * the time of the creation of the container.
+ *
+ * \param c A pointer to the container to operate on.
+ * \param arg passed to the callback.
+ * \param flags A set of flags specifying the operation to perform,
+ partially used by the container code, but also passed to
+ the callback.
+ * \return A pointer to the object found/marked,
+ * a pointer to a list of objects matching comparison function,
+ * NULL if not found.
+ * If the function returns any objects, their refcount is incremented,
+ * and the caller is in charge of decrementing them once done.
+ * Also, in case of multiple values returned, the list used
+ * to store the objects must be freed by the caller.
+ *
+ * This function searches through a container and performs operations
+ * on objects according on flags passed.
+ * XXX describe better
+ * The comparison is done calling the compare function set implicitly.
+ * The p pointer can be a pointer to an object or to a key,
+ * we can say this looking at flags value.
+ * If p points to an object we will search for the object pointed
+ * by this value, otherwise we serch for a key value.
+ * If the key is not uniq we only find the first matching valued.
+ * If we use the OBJ_MARK flags, we mark all the objects matching
+ * the condition.
+ *
+ * The use of flags argument is the follow:
+ *
+ * OBJ_UNLINK unlinks the object found
+ * OBJ_DATA on match, return an object
+ * Callbacks do not use OBJ_DATA,
+ * functions such as find() do
+ * OBJ_SINGLE stop at the first match.
+ * Default for _find();
+ * to a key (not yet supported)
+ * OBJ_POINTER the pointer is an object pointer
+ *
+ * In case we return a list, the callee must take care to destroy
+ * that list when no longer used.
+ *
+ * \note When the returned object is no longer in use, astobj2_ref() should
+ * be used to free the additional reference possibly created by this function.
+ */
+void *astobj2_find(struct container *c, void *arg, enum search_flags flags);
+void *astobj2_callback(struct container *c,
+ enum search_flags flags,
+ astobj2_callback_fn cb_fn, void *arg);
+
+/*!
+ *
+
+When we need to walk through a container, we use
+astobj2_iterator to keep track of the current position.
+
+Because the navigation is typically done without locking
+the container, objects can be inserted or deleted or moved
+while we work. As a consequence, there is no guarantee that
+the we manage to touch all the elements on the list, or it
+is possible that we touch the same object multiple times.
+We do implement a few things to reduce the chance of the
+above happening.
+
+An iterator must be first initialized with astobj2_iterator_init(),
+then we can use o = astobj2_iterator_next() to move from one
+element to the next. Remember that the object returned by
+astobj2_iterator_next() has its refcount incremented,
+and the refcount will be decremented by the next call to
+astobj2_iterator_next(). If we terminate the loop early,
+we need to release the refcount explicitly when we are
+done with the object.
+Example:
+
+ \code
+
+ struct astobj2_iterator i;;
+ struct my_obj *o;
+
+ astobj2_iterator_init(&i);
+
+ while ( (o = astobj2_iterator_next(&i)) ) {
+ ... do something on o ...
+ }
+ if (o)
+ astobj2_ref(o, -1);
+
+ \endcode
+
+ */
+struct astobj2_iterator {
+ struct container *c; /* the container */
+ int bucket; /* current bucket */
+ int pos; /* current position in bucket */
+ struct astobj2 *cur; /* current object, NULL at start */
+};
+
+void astobj2_iterator_init(struct container *c, struct astobj2_iterator *i);
+
+void *astobj2_iterator_next(struct astobj2_iterator *a);
+
+#endif /* _ASTERISK_ASTOBJ2_H */
Propchange: team/rizzo/astobj2/include/asterisk/astobj2.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/rizzo/astobj2/include/asterisk/astobj2.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/rizzo/astobj2/include/asterisk/astobj2.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: team/rizzo/astobj2/main/Makefile
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/main/Makefile?rev=45807&r1=45806&r2=45807&view=diff
==============================================================================
--- team/rizzo/astobj2/main/Makefile (original)
+++ team/rizzo/astobj2/main/Makefile Fri Oct 20 17:07:38 2006
@@ -26,6 +26,7 @@
utils.o plc.o jitterbuf.o dnsmgr.o devicestate.o \
netsock.o slinfactory.o ast_expr2.o ast_expr2f.o \
cryptostub.o sha1.o http.o fixedjitterbuf.o abstract_jb.o \
+ astobj2.o \
strcompat.o
# we need to link in the objects statically, not as a library, because
Added: team/rizzo/astobj2/main/astobj2.c
URL: http://svn.digium.com/view/asterisk/team/rizzo/astobj2/main/astobj2.c?rev=45807&view=auto
==============================================================================
--- team/rizzo/astobj2/main/astobj2.c (added)
+++ team/rizzo/astobj2/main/astobj2.c Fri Oct 20 17:07:38 2006
@@ -1,0 +1,388 @@
+/*
+ * 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.
+ */
+
+/*
+ * Function implementing astobj2 objects.
+ */
+#include "asterisk.h"
+#include <assert.h>
+
+/* TODO: Revision: ? */
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "asterisk/astobj2.h"
+
+/*
+ * From a pointer _p to a user-defined object,
+ * return the pointer to the astobj2 structure
+ */
+#define INTERNAL_OBJ(_p) ((struct astobj2 *)( (_p) == NULL ? NULL : (char *)(_p) - sizeof(struct astobj2) ))
+
+/*
+ * 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)
+
+int astobj2_lock(void *a)
+{
+ return ast_mutex_lock( &INTERNAL_OBJ(a)->priv_data.lock );
+}
+
+int astobj2_unlock(void *a)
+{
+ return ast_mutex_unlock( &INTERNAL_OBJ(a)->priv_data.lock );
+}
+
+/*
+ * we expect a to be non-NULL
+ */
+int astobj2_ref(void *a, const int delta)
+{
+#if 0
+ ast_log(LOG_NOTICE, "Reference counter changed by %i\n", delta);
+#endif
+ struct astobj2 *obj = INTERNAL_OBJ(a);
+
+ int current_value;
+ int ret;
+
+ assert(a != NULL);
+ /* if delta is 0, just return the refcount */
+ if (delta == 0)
+ return (obj->priv_data.ref_counter);
+
+ /* we modify with an atomic operation the reference counter */
+ ret = ast_atomic_fetchadd_int( &obj->priv_data.ref_counter, delta );
+ current_value = ret + delta;
+
+ /* this case must never happen */
+ if (current_value < 0)
+ ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, a);
+
+ if ( current_value <= 0 ) { /* last reference, destroy the object */
+ ast_log(LOG_DEBUG, "refcount %d on object %p, we destroy the object\n", current_value, a);
+
+ if (obj->priv_data.destructor_fn != NULL)
+ obj->priv_data.destructor_fn(a);
+
+ ast_mutex_destroy(&obj->priv_data.lock);
+ /* for safety, zero-out the astobj2 header and also the
+ * first word of the user-data, which we make sure is always
+ * allocated.
+ */
+ bzero(obj, sizeof(struct astobj2 *) + sizeof(void *) );
+ free( obj );
+ }
+
+ return ret;
+}
+
+/*
+ * We always alloc at least the size of a void *,
+ * for debugging purposes.
+ */
+void *astobj2_obj_alloc(size_t data_size, astobj2_destructor_fn destructor_fn)
+{
+ /* allocation */
+ struct astobj2 *a;
+
+ if (data_size < sizeof(void *))
+ data_size = sizeof(void *);
+
+ a = calloc ( 1, sizeof(struct astobj2) + data_size );
+
+ if ( a == NULL)
+ return NULL;
+
+ /* init */
+ ast_mutex_init(&a->priv_data.lock);
+ a->priv_data.ref_counter = 1;
+ a->priv_data.destructor_fn = destructor_fn; /* can be NULL */
+
+ /* return a pointer to the user data */
+ return EXTERNAL_OBJ(a);
+}
+
+/* XXX todo callback that unlinks and unrefs every element */
+static void container_destruct(void *c);
+
+/*
+ * A container is just an object, after all!
+ */
+struct container *
+astobj2_container_alloc(const uint n_buckets, astobj2_hash_fn hash_fn,
+ astobj2_callback_fn cmp_fn)
+{
+ /* compute the container size */
+ size_t container_size = sizeof (struct container)
+ + n_buckets * sizeof (struct astobj2_bucket_list *);
+
+ /* XXX must fix the destructor */
+ struct container *c = astobj2_obj_alloc(container_size, container_destruct);
+
+ if ( c == NULL )
+ return NULL;
+
+ /* init */
+ c->elements = 0;
+ c->n_buckets = n_buckets;
+ c->hash_fn = hash_fn;
+ c->cmp_fn = cmp_fn;
+
+ return c;
+}
+
+/* XXX better to keep a global count of elements */
+int astobj2_container_empty(struct container *c)
+{
+ return c->elements;
+}
+
+/*!
+ * link an object to a container
+ */
+void *astobj2_link(struct container *c, void *newobj)
+{
+ struct astobj2_bucket_list *list_pointer;
+ uint i = c->hash_fn( newobj, TRUE );
+
+ astobj2_lock(c);
+ i %= c->n_buckets;
+ list_pointer = calloc( 1, sizeof (struct astobj2_bucket_list) );
+
+ /* linking the object to head */
+ if (list_pointer != NULL) {
+ list_pointer->next = c->buckets[i];
+ list_pointer->obj = INTERNAL_OBJ(newobj);
+ c->buckets[i] = list_pointer;
+ list_pointer = newobj;
+ }
+ astobj2_unlock(c);
+ return list_pointer;
+}
+
+/*!
+ * \internal
+ * \brief Unlink an object from the list
+ * and destroy the associated * astobj2_bucket_list structure.
+ */
+static void obj_unlink(struct astobj2_bucket_list *prev_pointer)
+{
+ struct astobj2_bucket_list *to_delete = prev_pointer->next;
+
+ prev_pointer->next = to_delete->next;
+ free(to_delete);
+}
+
+/*!
+ * Browse the container using different stategies accoding the flags.
+ * \return Is a pointer to an object or to a list of object if OBJ_MULTIPLE is
+ * specified.
+ */
+void *astobj2_callback(struct container *c,
+ const enum search_flags flags,
+ astobj2_callback_fn cb_fn, void *arg)
+{
+ int i, last;
+ int match;
+ struct astobj2 *ret = NULL;
+
+ if ( (flags & (OBJ_SINGLE | OBJ_DATA)) == OBJ_DATA) {
+ ast_log(LOG_WARNING, "multiple data return not implemented yet");
+ return NULL;
+ }
+ /*
+ * XXX this can be optimized.
+ */
+ 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. */
+
+ if (i < 0) {
+ i = 0;
+ last = c->n_buckets;
+ } else {
+ last = i+1;
+ }
+
+ astobj2_lock(c);
+
+ for(; i < last ; i++) {
+ struct astobj2_bucket_list *prev = NULL, *cur = c->buckets[i];
+ while (cur) {
+ /* match by pointer or exec a function */
+ if ( flags & OBJ_POINTER )
+ match = ( cur->obj == INTERNAL_OBJ(arg) );
+ else
+ match = cb_fn(EXTERNAL_OBJ(cur->obj), arg, flags );
+
+ /* we found the object, performing operations according flags */
+ if (!match) {
+ prev = cur;
+ cur = cur->next;
+ continue;
+ }
+ if (flags & OBJ_DATA)
+ ret = cur->obj;
+ if (flags & OBJ_UNLINK) {
+ struct astobj2_bucket_list *x = cur;
+
+ if (prev == NULL)
+ c->buckets[i] = cur->next;
+ else
+ prev->next = cur->next;
+ cur = cur->next ;
+ free(x);
+ }
+
+ if (flags & OBJ_SINGLE) {
+ /* We found the only match we need */
+ i = last; /* force exit from outer loop */
+ break;
+ }
+ if (flags & OBJ_DATA) {
+#if 0 /* XXX to be completed */
+ /* here build a list of object pointers and increase
+ * the reference counter for each reference created */
+ struct astobj2_list *new_obj;
+ new_obj = calloc(1, sizeof(struct astobj2_list));
+ if ( new_obj == NULL ) {
+ ast_log(LOG_WARNING, "No list created, out of memory\n");
+ continue;
+ }
+ astobj2_ref(EXTERNAL_OBJ(list_pointer->obj), 1);
+ new_obj->next = (struct astobj2_list *)ret;
+ ret = new_obj;
+#endif
+ }
+ prev = cur;
+ cur = cur->next;
+ }
+ }
+ astobj2_unlock(c);
+
+ /* increase the reference counter, unlock the container and return */
+ if ( ret != NULL ) {
+ astobj2_ref(ret, 1);
+ ret = (void *)EXTERNAL_OBJ(ret);
+ }
+ return ret;
+}
+
+void *astobj2_find(struct container *c, void *p, enum search_flags flags)
+{
+ if (flags == 0)
+ flags = OBJ_SINGLE | OBJ_DATA; /* reasonable default */
+ ast_log(LOG_NOTICE, "astobj2_find\n");
+ return astobj2_callback(c, flags, c->cmp_fn, p);
+}
+
+void astobj2_iterator_init(struct container *c, struct astobj2_iterator *a)
+{
+ a->bucket = 0;
+ a->pos = 0;
+ a->c = c;
+ a->cur = NULL;
+}
+
+/*
+ * move to the next element in the container.
+ */
+void * astobj2_iterator_next(struct astobj2_iterator *a)
+{
+ int lim;
+ struct astobj2_bucket_list **bp;
+
+ if (a->cur)
+ astobj2_ref(EXTERNAL_OBJ(a->cur), -1);
+ else { /* search from the beginning */
+ a->bucket = 0;
+ a->pos = -1;
+ }
+
+ astobj2_lock(a->c);
+ lim = a->c->n_buckets;
+ bp = a->c->buckets;
+
+ /* we browse the buckets array, moving to the next
+ * buckets if we don't find the entry in the current one.
+ */
+ for ( ; a->bucket < lim;
+ /* move to next bucket */
+ a->bucket++, a->pos = -1) {
+ struct astobj2_bucket_list *p = bp[a->bucket], *cand = NULL;
+ int i;
+
+ if (p == NULL) /* empty bucket */
+ continue;
+
+ if (a->pos == -1) { /* found at the beginning of the bucket */
+ a->pos = 0;
+ a->cur = p->obj;
+ break;
+ }
+
+ /* we browse the buckets list for the current object,
+ * by address or by position.
+ * When we find it, record it in cand.
+ * The next element to return will be cand->next.
+ */
+ for (i = 0; p; i++, p = p->next) {
+ if (p->obj == a->cur) { /* found current element */
+ a->pos = i; /* mark new position */
+ cand = p;
+ break;
+ } else if (i == a->pos) { /* element not found, but this is a candidate */
+ cand = p;
+ }
+ }
+ if (cand == NULL || cand->next == NULL) /* not found, try next bucket */
+ continue;
+ /* ok, what we want is at cand->next */
+ a->pos++;
+ a->cur = cand->next->obj;
+ break;
+ }
+
+ if (a->bucket == lim) /* not found */
+ return NULL;
+ astobj2_ref(EXTERNAL_OBJ(a->cur), 1); /* inc refcount of returned object */
+
+ astobj2_unlock(a->c);
+ return EXTERNAL_OBJ(a->cur);
+}
+
+/* callback for destroying container.
+ * we can make it simple as we know what it does
+ */
+static int cd_cb(void *obj, void *arg, int flag)
+{
+ astobj2_ref(obj, -1);
+ return 0;
+}
+
+static void container_destruct(void *_c)
+{
+ struct container *c = _c;
+
+ astobj2_callback(c, OBJ_UNLINK, cd_cb, NULL);
+ astobj2_ref(c, -1);
+}
Propchange: team/rizzo/astobj2/main/astobj2.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/rizzo/astobj2/main/astobj2.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/rizzo/astobj2/main/astobj2.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the svn-commits
mailing list