diff options
Diffstat (limited to 'include/asterisk')
-rw-r--r-- | include/asterisk/astobj2.h | 515 | ||||
-rw-r--r-- | include/asterisk/strings.h | 19 |
2 files changed, 534 insertions, 0 deletions
diff --git a/include/asterisk/astobj2.h b/include/asterisk/astobj2.h new file mode 100644 index 000000000..73c8ede99 --- /dev/null +++ b/include/asterisk/astobj2.h @@ -0,0 +1,515 @@ +/* + * 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 "asterisk/lock.h" + +/*! \file + * + * \brief Object Model implementing objects and containers. + +These functions implement an abstraction for objects (with +locks and reference counts) and containers for these user-defined objects, +supporting locking, reference counting and callbacks. + +The internal implementation of the container is 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. + +USAGE - OBJECTS + +An object is a block of memory that must be allocated with the +function ao2_alloc(), and for which the system keeps track (with +abit of help from the programmer) of the number of references around. +When an object has no more references, it is destroyed, by first +invoking whatever 'destructor' function the programmer specifies +(it can be NULL), and then freeing the memory. +This way objects can be shared without worrying who is in charge +of freeing them. + +Basically, creating an object requires the size of the object and +and a pointer to the destructor function: + + struct foo *o; + + o = ao2_alloc(sizeof(struct foo), my_destructor_fn); + +The object returned has a refcount = 1. +Note that the memory for the object is allocated and zeroed. +- We cannot realloc() the object itself. +- We cannot call free(o) to dispose of the object; rather we + tell the system that we do not need the reference anymore: + + ao2_ref(o, -1) + + causing the destructor to be called (and then memory freed) when + the refcount goes to 0. This is also available as ao2_unref(o), + and returns NULL as a convenience, so you can do things like + o = ao2_unref(o); + and clean the original pointer to prevent errors. + +- ao2_ref(o, +1) can be used to modify the refcount on the + object in case we want to pass it around. + + +- other calls on the object are ao2_lock(obj), ao2_unlock(), + ao2_trylock(), to manipulate the lock. + + +USAGE - CONTAINERS + +A containers is an abstract data structure where we can store +objects, search them (hopefully in an efficient way), and iterate +or apply a callback function to them. A container is just an object +itself. + +A container must first be allocated, specifying the initial +parameters. At the moment, this is done as follows: + + <b>Sample Usage:</b> + \code + + ao2_container *c; + + c = ao2_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 ao2_alloc() +All knowledge of the (user-defined) internals of the object +is left to the (user-supplied) functions passed as arguments +to ao2_container_alloc(). + +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 + + ao2_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 grabs the reference +to the object (which is now owned by the container) so we do not +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. + */ + +/*! + * Invoked just before freeing the memory for the object. + * It is passed a pointer to user data. + */ +typedef void (*ao2_destructor_fn)(void *); + +void ao2_bt(void); /* backtrace */ +/*! + * 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 ao2_ref(o, -1); + */ +void *ao2_alloc(const size_t data_size, ao2_destructor_fn destructor_fn); + +/*! + * Reference/unreference an object and return the old refcount. + * + * \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 The object must not be locked by the caller of this function, as + * it is invalid to try to unlock it after releasing the reference. + * + * \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 ao2_ref(void *o, int delta); + +/*! + * Lock an object. + * + * \param a A pointer to the object we want lock. + * \return 0 on success, other values on error. + */ +int ao2_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 ao2_unlock(void *a); + +/*! + * + * Containers + +containers are data structures meant to store several objects, +and perform various operations on them. +Internally, objects are stored in lists, hash tables or other +data structures depending on the needs. + +NOTA BENE: at the moment the only container we support is the +hash table and its degenerate form, the list. + +Operations on container include: + + c = ao2_container_alloc(size, cmp_fn, hash_fn) + allocate a container with desired size and default compare + and hash function + + ao2_find(c, arg, flags) + returns zero or more element matching a given criteria + (specified as arg). Flags indicate how many results we + want (only one or all matching entries), and whether we + should unlink the object from the container. + + ao2_callback(c, flags, fn, arg) + apply fn(obj, arg) to all objects in the container. + Similar to find. fn() can tell when to stop, and + do anything with the object including unlinking it. + Note that the entire operation is run with the container + locked, so noone else can change its content while we work on it. + However, we pay this with the fact that doing + anything blocking in the callback keeps the container + blocked. + The mechanism is very flexible because the callback function fn() + can do basically anything e.g. counting, deleting records, etc. + possibly using arg to store the results. + + iterate on a container + this is done with the following sequence + + ao2_container *c = ... // our container + ao2_iterator i; + void *o; + + i = ao2_iterator_init(c, flags); + + while ( (o = ao2_iterator_next(&i)) ) { + ... do something on o ... + ao2_ref(o, -1); + } + + The difference with the callback is that the control + on how to iterate is left to us. + + ao2_ref(c, -1) + dropping a reference to a container destroys it, very simple! + +Containers are astobj2 object themselves, and this is why their +implementation is simple too. + + */ + +/*! + * We can perform different operation on an object. We do this + * according the following flags. + */ +enum search_flags { + /*! unlink the object found */ + OBJ_UNLINK = (1 << 0), + /*! on match, don't return the object or increase its reference count. */ + OBJ_NODATA = (1 << 1), + /*! don't stop at the first match + * \note This is not fully implemented. */ + OBJ_MULTIPLE = (1 << 2), + /*! obj is an object of the same type as the one being searched for. + * This implies that it can be passed to the object's hash function + * for optimized searching. */ + OBJ_POINTER = (1 << 3), +}; + +/*! + * Type of a generic function to generate a hash value from an object. + * + */ +typedef int (*ao2_hash_fn)(const void *obj, const int flags); + +/*! + * 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 ao2_find) + * \param flags passed directly from ao2_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 ao2_callback() + * \param flags flags from ao2_callback() + * The return values are the same as a compare function. + * In fact, they are the same thing. + */ +typedef int (*ao2_callback_fn)(void *obj, void *arg, int flags); + +/*! + * Here start declarations of containers. + */ + +/*! + * This structure contains the total number of buckets + * and variable size array of object pointers. + * It is opaque, defined in astobj2.c, so we only need + * a type declaration. + */ +typedef struct __ao2_container ao2_container; + +/*! + * 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 my_hash_fn Pointer to a function computing a hash value. + * \param my_cmp_fn Pointer to a function comparating key-value + * with a string. (can be NULL) + * \return A pointer to a struct container. + * + * destructor is set implicitly. + */ +ao2_container *ao2_container_alloc(const uint n_buckets, + ao2_hash_fn hash_fn, ao2_callback_fn cmp_fn); + +/*! + * Returns the number of elements in a container. + */ +int ao2_container_count(ao2_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 *ao2_link(ao2_container *c, void *newobj); +void *ao2_unlink(ao2_container *c, void *newobj); + +/*! \struct Used as return value if the flag OBJ_MULTIPLE is set */ +struct ao2_list { + struct ao2_list *next; + void *obj; /* pointer to the user portion of the object */ +}; + +/*! + * ao2_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_NODATA on match, do return an object + * Callbacks use OBJ_NODATA as a default + * functions such as find() do + * OBJ_MULTIPLE return multiple matches + * Default for _find() is no. + * 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, ao2_ref() should + * be used to free the additional reference possibly created by this function. + */ +/* XXX order of arguments to find */ +void *ao2_find(ao2_container *c, void *arg, enum search_flags flags); +void *ao2_callback(ao2_container *c, + enum search_flags flags, + ao2_callback_fn cb_fn, void *arg); + +/*! + * + +When we need to walk through a container, we use +ao2_iterator to keep track of the current position. + +Because the navigation is typically done without holding the +lock on the container across the loop, +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. + +An iterator must be first initialized with ao2_iterator_init(), +then we can use o = ao2_iterator_next() to move from one +element to the next. Remember that the object returned by +ao2_iterator_next() has its refcount incremented, +and the reference must be explicitly released when done with it. +Example: + + \code + + ao2_container *c = ... // the container we want to iterate on + ao2_iterator i; + struct my_obj *o; + + i = ao2_iterator_init(c, flags); + + while ( (o = ao2_iterator_next(&i)) ) { + ... do something on o ... + ao2_ref(o, -1); + } + + \endcode + + */ + +/*! + * You are not supposed to know the internals of an iterator! + * We would like the iterator to be opaque, unfortunately + * its size needs to be known if we want to store it around + * without too much trouble. + * Anyways... + * The iterator has a pointer to the container, and a flags + * field specifying various things e.g. whether the container + * should be locked or not while navigating on it. + * The iterator "points" to the current object, which is identified + * by three values: + * - a bucket number; + * - the object_id, which is also the container version number + * when the object was inserted. This identifies the object + * univoquely, however reaching the desired object requires + * scanning a list. + * - a pointer, and a container version when we saved the pointer. + * If the container has not changed its version number, then we + * can safely follow the pointer to reach the object in constant time. + * Details are in the implementation of ao2_iterator_next() + * A freshly-initialized iterator has bucket=0, version = 0. + */ + +struct __ao2_iterator { + /*! the container */ + ao2_container *c; + /*! operation flags */ + int flags; +#define F_AO2I_DONTLOCK 1 /*!< don't lock when iterating */ + /*! current bucket */ + int bucket; + /*! container version */ + uint c_version; + /*! pointer to the current object */ + void *obj; + /*! container version when the object was created */ + uint version; +}; +typedef struct __ao2_iterator ao2_iterator; + +ao2_iterator ao2_iterator_init(ao2_container *c, int flags); + +void *ao2_iterator_next(ao2_iterator *a); + +#endif /* _ASTERISK_ASTOBJ2_H */ diff --git a/include/asterisk/strings.h b/include/asterisk/strings.h index 68ecb2048..2fff9c133 100644 --- a/include/asterisk/strings.h +++ b/include/asterisk/strings.h @@ -23,6 +23,7 @@ #ifndef _ASTERISK_STRINGS_H #define _ASTERISK_STRINGS_H +#include <stdlib.h> #include <string.h> #include <stdarg.h> @@ -263,4 +264,22 @@ struct ast_realloca { (ra)->ptr; \ }) +/*! + * \brief Compute a hash value on a string + * + * This famous hash algorithm was written by Dan Bernstein and is + * commonly used. + * + * http://www.cse.yorku.ca/~oz/hash.html + */ +static force_inline int ast_str_hash(const char *str) +{ + int hash = 5381; + + while (*str) + hash = hash * 33 ^ *str++; + + return abs(hash); +} + #endif /* _ASTERISK_STRINGS_H */ |