Index: include/asterisk/astobj.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/astobj.h,v retrieving revision 1.13 diff -u -u -r1.13 astobj.h --- include/asterisk/astobj.h 1 May 2005 18:08:14 -0000 1.13 +++ include/asterisk/astobj.h 3 May 2005 20:23:40 -0000 @@ -17,13 +17,55 @@ #include #include "asterisk/lock.h" -/*! - \file astobj.h - \brief A set of macros implementing the asterisk object and container. Macros - are used for maximum performance, to support multiple inheritance, and - to be easily integrated into existing structures without additional - malloc calls, etc. -*/ +/*! \file + * \brief A set of macros implementing the asterisk object and container. + * Macros are used for maximum performance, to support multiple inheritance, + * and to be easily integrated into existing structures without additional + * malloc calls, etc. + * + * These macros expect to operate on two different object types, ASTOBJs and + * ASTOBJ_CONTAINERs. These are not actual types, as any struct can be + * converted into an ASTOBJ compatible object or container using the supplied + * macros. + * + * Sample Usage: + * \code + * struct sample_object { + * ASTOBJ_COMPONENTS(struct sample_object); + * }; + * + * struct sample_container { + * ASTOBJ_CONTAINER_COMPONENTS(struct sample_object); + * } super_container; + * + * int init_stuff() + * { + * struct sample_object obj1; + * struct sample_object *found_obj; + * + * ASTOBJ_CONTAINER_INIT(&super_container); + * + * ASTOBJ_INIT(&obj1); + * ASTOBJ_WRLOCK(&obj1); + * strncpy(obj1.name, "obj1", sizeof(obj1.name)); + * ASTOBJ_UNLOCK(&obj1); + * + * ASTOBJ_CONTAINER_LINK(&super_container, &obj1); + * + * found_obj = ASTOBJ_CONTAINER_FIND(&super_container, "obj1"); + * + * if(found_obj) { + * printf("Found object: %s", found_obj->name); + * ASTOBJ_UNREF(found_obj,); + * } + * + * ASTOBJ_CONTAINER_DESTROYALL(&super_container,); + * ASTOBJ_CONTAINER_DESTROY(&super_container); + * + * return 0; + * } + * \endcode + */ #if defined(__cplusplus) || defined(c_plusplus) extern "C" { @@ -42,8 +84,17 @@ /* C++ is simply a syntactic crutch for those who cannot think for themselves in an object oriented way. */ +/*! \brief Lock an ASTOBJ for reading. + * \note The current implmentation does not afford locking an object for + * reading and writing at the same time. This will cause a deadlock. + */ #define ASTOBJ_RDLOCK(object) ast_mutex_lock(&(object)->_lock) +/*! \brief Lock an ASTOBJ for writing. + * \note The current implmentation does not afford locking an object for + * reading and writing at the same time. This will cause a deadlock. + */ #define ASTOBJ_WRLOCK(object) ast_mutex_lock(&(object)->_lock) +/*! \brief Unlock a locked object. */ #define ASTOBJ_UNLOCK(object) ast_mutex_unlock(&(object)->_lock) #ifdef ASTOBJ_CONTAINER_HASHMODEL @@ -54,23 +105,88 @@ type *next[1] #endif +/*! \brief Add ASTOBJ components to a struct (without locking support). + * + * \param type The datatype of the struct. + * \param namelen The length to make the name char array. + * \param hashes The number of hashes to generate if using the ASTOBJ_CONTAINER_HASHMODEL. + * + * This macro adds components to a struct to make it an ASTOBJ. This macro + * differs from ASTOBJ_COMPONENTS_FULL in that it does not create a mutex for + * locking. + * + * Sample Usage: + * \code + * struct sample_struct { + * ASTOBJ_COMPONENTS_NOLOCK_FULL(struct sample_struct,1,1); + * }; + * \endcode + */ #define ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes) \ char name[namelen]; \ int refcount; \ int objflags; \ __ASTOBJ_HASH(type,hashes) +/*! \brief Add ASTOBJ components to a struct (without locking support). + * + * \param type The datatype of the struct. + * + * This macro works like #ASTOBJ_COMPONENTS_NOLOCK_FULL() except it only accepts a + * type and uses default values for namelen and hashes. + * + * Sample Usage: + * \code + * struct sample_struct_componets { + * ASTOBJ_COMPONENTS_NOLOCK(struct sample_struct); + * }; + * \endcode + */ #define ASTOBJ_COMPONENTS_NOLOCK(type) \ ASTOBJ_COMPONENTS_NOLOCK_FULL(type,ASTOBJ_DEFAULT_NAMELEN,1) +/*! \brief Add ASTOBJ components to a struct (with locking support). + * + * \param type The datatype of the struct. + * + * This macro works like #ASTOBJ_COMPONENTS_NOLOCK() accept it includes locking + * support. + * + * Sample Usage: + * \code + * struct sample_struct { + * ASTOBJ_COMPONENTS(struct sample_struct); + * }; + * \endcode + */ #define ASTOBJ_COMPONENTS(type) \ ASTOBJ_COMPONENTS_NOLOCK(type); \ ast_mutex_t _lock; +/*! \brief Add ASTOBJ components to a struct (with locking support). + * + * \param type The datatype of the struct. + * \param namelen The length to make the name char array. + * \param hashes The number of hashes to generate if using the ASTOBJ_CONTAINER_HASHMODEL. + * + * This macro adds components to a struct to make it an ASTOBJ and includes + * support for locking. + * + * Sample Usage: + * \code + * struct sample_struct { + * ASTOBJ_COMPONENTS_FULL(struct sample_struct,1,1); + * }; + * \endcode + */ #define ASTOBJ_COMPONENTS_FULL(type,namelen,hashes) \ ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes); \ ast_mutex_t _lock; +/*! \brief Increment an object reference count. + * \param object A pointer to the object to operate on. + * \return The object. + */ #define ASTOBJ_REF(object) \ ({ \ ASTOBJ_WRLOCK(object); \ @@ -79,6 +195,14 @@ (object); \ }) +/*! \brief Decrement the reference count on an object. + * + * \param object A pointer the object to operate on. + * \param destructor The destructor to call if the object is nolonger referenced. It will be passed the pointer as an argument. + * + * This macro unreferences and object and calls the specfied destructor if the + * object is no longer referenced. + */ #define ASTOBJ_UNREF(object,destructor) \ do { \ int newcount = 0; \ @@ -95,6 +219,13 @@ (object) = NULL; \ } while(0) +/*! \brief Mark an ASTOBJ by adding the #ASTOBJ_FLAG_MARKED flag to its objflags mask. + * \param object A pointer to the object to operate on. + * + * This macro "marks" and object. Marked objects can later be deleted using + * #ASTOBJ_CONTAINER_PRUNE_MARKED(). + * + */ #define ASTOBJ_MARK(object) \ do { \ ASTOBJ_WRLOCK(object); \ @@ -102,6 +233,9 @@ ASTOBJ_UNLOCK(object); \ } while(0) +/*! \brief Unmark an ASTOBJ by subtracting the #ASTOBJ_FLAG_MARKED flag from its objflags mask. + * \param object A pointer to the object to operate on. + */ #define ASTOBJ_UNMARK(object) \ do { \ ASTOBJ_WRLOCK(object); \ @@ -109,6 +243,12 @@ ASTOBJ_UNLOCK(object); \ } while(0) +/*! \brief Initilize an object. + * \param object A pointer to the object to operate on. + * + * \note This should only be used on objects that support locking (objects + * created with #ASTOBJ_COMPONENTS() or #ASTOBJ_COMPONENTS_FULL()) + */ #define ASTOBJ_INIT(object) \ do { \ ast_mutex_init(&(object)->_lock); \ @@ -119,27 +259,110 @@ /* Containers for objects -- current implementation is linked lists, but should be able to be converted to hashes relatively easily */ +/*! \brief Lock an ASTOBJ_CONTAINER for reading. + * \note The current implmentation does not afford locking an object for + * reading and writing at the same time. This will cause a deadlock. + */ #define ASTOBJ_CONTAINER_RDLOCK(container) ast_mutex_lock(&(container)->_lock) +/*! \brief Lock an ASTOBJ_CONTAINER for writing. + * \note The current implmentation does not afford locking an object for + * reading and writing at the same time. This will cause a deadlock. + */ #define ASTOBJ_CONTAINER_WRLOCK(container) ast_mutex_lock(&(container)->_lock) +/*! \brief Unlock an ASTOBJ_CONTAINER. */ #define ASTOBJ_CONTAINER_UNLOCK(container) ast_mutex_unlock(&(container)->_lock) #ifdef ASTOBJ_CONTAINER_HASHMODEL #error "Hash model for object containers not yet implemented!" #else /* Linked lists */ + +/*! \brief Create a container for ASTOBJs (without locking support). + * + * \param type The type of objects the container will hold. + * \param hashes Currently unused. + * \param buckets Currently unused. + * + * This macro is used to create a container for ASTOBJs without locking + * support. + * + * Sample Usage: + * \code + * struct sample_struct_nolock_container { + * ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(struct sample_struct,1,1); + * }; + * \endcode + */ #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,hashes,buckets) \ type *head +/*! \brief Initilize a container. + * + * \param container A pointer to the container to initilize. + * \param hashes Currently unused. + * \param buckets Currently unused. + * + * This macro initilizes a container. It should only be used on containers + * that support locking. + * + * Sample Usage: + * \code + * struct sample_struct_container { + * ASTOBJ_CONTAINER_COMPONENTS_FULL(struct sample_struct,1,1); + * } container; + * + * int func() + * { + * ASTOBJ_CONTAINER_INIT_FULL(&container,1,1); + * } + * \endcode + */ #define ASTOBJ_CONTAINER_INIT_FULL(container,hashes,buckets) \ do { \ ast_mutex_init(&(container)->_lock); \ } while(0) +/*! \brief Destroy a container. + * + * \param container A pointer to the container to destory. + * \param hashes Currently unused. + * \param buckets Currently unused. + * + * This macro frees up resources used by a container. It does not operate on + * the objects in the container. To destroy the objects in the container use + * #ASTOBJ_CONTAINER_DESTROYALL(). + * + * \note This macro should only be used on containers with locking support. + */ #define ASTOBJ_CONTAINER_DESTROY_FULL(container,hashes,buckets) \ do { \ ast_mutex_destroy(&(container)->_lock); \ } while(0) +/*! \brief Iterate through the elements in a container. + * + * \param container A pointer to the container to traverse. + * \param continue A condition to abort the loop on. + * \param eval A statement to evaluate in the iteration loop. + * + * This is marco is a little complicated, but it may help to think of it as a + * loop. Basically it iterates through the specfied containter until the + * condition is met. Two variables, iterator and next are provided for use in + * your \p eval statement. See the sample code for an example. + * + * Sample Usage: + * \code + * ASTOBJ_CONTAINER_TRAVERSE(&sample_container,1, { + * ASTOBJ_RDLOCK(iterator); + * printf("Currently iterating over '%s'\n", iterator->name); + * ASTOBJ_UNLOCK(iterator); + * } ); + * \endcode + * + * \code + * ASTOBJ_CONTAINER_TRAVERSE(&sample_container,1, sample_func(iterator)); + * \endcode + */ #define ASTOBJ_CONTAINER_TRAVERSE(container,continue,eval) \ do { \ typeof((container)->head) iterator; \ @@ -153,6 +376,18 @@ ASTOBJ_CONTAINER_UNLOCK(container); \ } while(0) +/*! \brief Find an object in a container. + * + * \param container A pointer to the container to search. + * \param namestr The name to search for. + * + * Use this function to find an object in a container with the specfied name. + * + * \note When the returned object is no longer in use, #ASTOBJ_UNREF() should + * be used to free its resources. + * + * \return A pointer to the object located or NULL if nothing is found. + */ #define ASTOBJ_CONTAINER_FIND(container,namestr) \ ({ \ typeof((container)->head) found = NULL; \ @@ -163,6 +398,24 @@ found; \ }) +/*! \brief Find an object in a container. + * + * \param container A pointer to the container to search. + * \param data The data to search for. + * \param field The field/member of the container's objects to search. + * \param hashfunc The hash function to use, currently not implemented. + * \param hashoffset The hash offset to use, currently not implemented. + * \param comparefunc The function used to compare the field and data values. + * + * This macro iterates through a container passing the specfied field and data + * elements to the specfied comparefunc. The function should return 0 on + * success when a match is found. + * + * \note When the returned object is no longer in use, #ASTOBJ_UNREF() should + * be used to free its resources. + * + * \return A pointer to the object located or NULL if nothing is found. + */ #define ASTOBJ_CONTAINER_FIND_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \ ({ \ typeof((container)->head) found = NULL; \ @@ -176,6 +429,18 @@ found; \ }) +/*! \brief Empty a container. + * + * \param container A pointer to the container to operate on. + * \param destructor A destructor function to call on each object. + * + * This macro loops through a container removing all the items from it using + * #ASTOBJ_UNREF(). This does not destroy the container it self, use + * #ASTOBJ_CONTAINER_DESTROY() for that. + * + * \note If the objects in the container are refrenced more than once their + * destructors will not be called. + */ #define ASTOBJ_CONTAINER_DESTROYALL(container,destructor) \ do { \ typeof((container)->head) iterator; \ @@ -187,6 +452,19 @@ ASTOBJ_CONTAINER_UNLOCK(container); \ } while(0) +/*! \brief Remove an object from a container. + * + * \param container A pointer to the container to operate on. + * \param obj A pointer to the object to remove. + * + * This macro iterates through a container and removes the specfied object if + * it exists in the container. + * + * \note This macro does not destroy any objects, it simply removes/unlinks + * them from the list. No destructors are call. + * + * \return The object unlinked or NULL if no matching object was found. + */ #define ASTOBJ_CONTAINER_UNLINK(container,obj) \ ({ \ typeof((container)->head) found = NULL; \ @@ -207,6 +485,18 @@ found; \ }) +/*! \brief Remove an object from a container. + * + * \param container A pointer to the container to operate on. + * \param namestr The name of the object to remove. + * + * This macro iterates through a container and removes the first object with the specfied name from the container. + * + * \note This macro does not destroy any objects, it simply removes/unlinks + * them. No destructors are called. + * + * \return The object removed or NULL if no matching object was found. + */ #define ASTOBJ_CONTAINER_FIND_UNLINK(container,namestr) \ ({ \ typeof((container)->head) found = NULL; \ @@ -227,6 +517,25 @@ found; \ }) +/*! \brief Find an object in a container. + * + * \param container A pointer to the container to search. + * \param data The data to search for. + * \param field The field/member of the container's objects to search. + * \param hashfunc The hash function to use, currently not implemented. + * \param hashoffset The hash offset to use, currently not implemented. + * \param comparefunc The function used to compare the field and data values. + * + * This macro iterates through a container passing the specfied field and data + * elements to the specfied comparefunc. The function should return 0 on + * success when a match is found. If a match is found it is removed from the + * list. + * + * \note This macro does not destroy any objects, it simply removes/unlinks + * them. No destructors are called. + * + * \return A pointer to the removed object or NULL if no match was found. + */ #define ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \ ({ \ typeof((container)->head) found = NULL; \ @@ -249,6 +558,14 @@ found; \ }) +/*! \brief Prune marked objects from a container. + * + * \param container A pointer to the container to prune. + * \param destructor A destructor function to call on each marked object. + * + * This macro iterates through the specfied container and prunes any marked + * objects executing the specfied destructor if necessary. + */ #define ASTOBJ_CONTAINER_PRUNE_MARKED(container,destructor) \ do { \ typeof((container)->head) prev = NULL; \ @@ -270,6 +587,20 @@ } while (0)); \ } while(0) +/*! \brief Add an object to a container. + * + * \param container A pointer to the container to operate on. + * \param newobj A pointer to the object to to add. + * \param data Currently unused. + * \param field Currently unused. + * \param hashfunc Currently unused. + * \param hashoffset Currently unused. + * \param comparefunc Currently unused. + * + * Currently this function adds an object to the head of the list. One day it + * will support adding object to the position specfied using the various + * options this macro offers. + */ #define ASTOBJ_CONTAINER_LINK_FULL(container,newobj,data,field,hashfunc,hashoffset,comparefunc) \ do { \ ASTOBJ_CONTAINER_WRLOCK(container); \ @@ -281,31 +612,123 @@ #endif /* List model */ /* Common to hash and linked list models */ + +/*! \brief Create a container for ASTOBJs (without locking support). + * + * \param type The type of objects the container will hold. + * + * This macro is used to create a container for ASTOBJs without locking + * support. + * + * Sample Usage: + * \code + * struct sample_struct_nolock_container { + * ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(struct sample_struct); + * }; + * \endcode + */ #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) \ ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,1,ASTOBJ_DEFAULT_BUCKETS) + +/*! \brief Create a container for ASTOBJs (with locking support). + * + * \param type The type of objects the container will hold. + * + * This macro is used to create a container for ASTOBJs with locking support. + * + * Sample Usage: + * \code + * struct sample_struct_container { + * ASTOBJ_CONTAINER_COMPONENTS(struct sample_struct); + * }; + * \endcode + */ #define ASTOBJ_CONTAINER_COMPONENTS(type) \ ast_mutex_t _lock; \ ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) +/*! \brief Initilize a container. + * + * \param container A pointer to the container to initilize. + * + * This macro initilizes a container. It should only be used on containers + * that support locking. + * + * Sample Usage: + * \code + * struct sample_struct_container { + * ASTOBJ_CONTAINER_COMPONENTS(struct sample_struct); + * } container; + * + * int func() + * { + * ASTOBJ_CONTAINER_INIT(&container); + * } + * \endcode + */ #define ASTOBJ_CONTAINER_INIT(container) \ ASTOBJ_CONTAINER_INIT_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS) +/*! \brief Destroy a container. + * + * \param container A pointer to the container to destory. + * + * This macro frees up resources used by a container. It does not operate on + * the objects in the container. To destroy the objects in teh container use + * #ASTOBJ_CONTAINER_DESTROYALL(). + * + * \note This macro should only be used on containers with locking support. + */ #define ASTOBJ_CONTAINER_DESTROY(container) \ ASTOBJ_CONTAINER_DESTROY_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS) +/*! \brief Add an object to a container. + * + * \param container A pointer to the container to operate on. + * \param newobj A pointer to the object to to add. + * + * Currently this macro adds an object to the head of a container. One day it + * should add an object in alphabetical order. + */ #define ASTOBJ_CONTAINER_LINK(container,newobj) \ ASTOBJ_CONTAINER_LINK_FULL(container,newobj,(newobj)->name,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp) +/*! \brief Mark all the objects in a container. + * \param container A pointer to the container to operate on. + */ #define ASTOBJ_CONTAINER_MARKALL(container) \ ASTOBJ_CONTAINER_TRAVERSE(container, 1, ASTOBJ_MARK(iterator)) +/*! \brief Unmark all the objects in a container. + * \param container A pointer to the container to operate on. + */ #define ASTOBJ_CONTAINER_UNMARKALL(container) \ ASTOBJ_CONTAINER_TRAVERSE(container, 1, ASTOBJ_UNMARK(iterator)) +/*! \brief Dump information about an object into a string. + * + * \param s A pointer to the string to use. + * \param slen The length of s. + * \param obj A pointer to the object to dump. + * + * This macro dumps a text representation of the name, objectflags, and + * refcount fields of an object to the specfied string. + */ #define ASTOBJ_DUMP(s,slen,obj) \ snprintf((s),(slen),"name: %s\nobjflags: %d\nrefcount: %d\n\n", (obj)->name, (obj)->objflags, (obj)->refcount); +/*!\brief Dump information about all the objects in a container to a file descriptor. + * + * \param fd The file descriptor to write to. + * \param s A string, same as #ASTOBJ_DUMP(). + * \param slen The length of s, same as #ASTOBJ_DUMP(). + * \param container A pointer to the container to dump. + * + * This macro dumps a text representation of the name, objectflags, and + * refcount fields of all the objects in a container to the specfied file + * descriptor. + */ #define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container) \ ASTOBJ_CONTAINER_TRAVERSE(container, 1, do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, s); } while(0))