Mon May 14 04:42:52 2007

Asterisk developer's documentation


astobj.h

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*
00020  * Object Model for Asterisk
00021  */
00022 
00023 #ifndef _ASTERISK_ASTOBJ_H
00024 #define _ASTERISK_ASTOBJ_H
00025 
00026 #include <string.h>
00027 
00028 #include "asterisk/lock.h"
00029 #include "asterisk/compiler.h"
00030 
00031 /*! \file
00032  * \brief A set of macros implementing objects and containers.
00033  * Macros are used for maximum performance, to support multiple inheritance,
00034  * and to be easily integrated into existing structures without additional
00035  * malloc calls, etc.
00036  *
00037  * These macros expect to operate on two different object types, ASTOBJs and
00038  * ASTOBJ_CONTAINERs.  These are not actual types, as any struct can be
00039  * converted into an ASTOBJ compatible object or container using the supplied
00040  * macros.
00041  *
00042  * <b>Sample Usage:</b>
00043  * \code
00044  * struct sample_object {
00045  *    ASTOBJ_COMPONENTS(struct sample_object);
00046  * };
00047  *
00048  * struct sample_container {
00049  *    ASTOBJ_CONTAINER_COMPONENTS(struct sample_object);
00050  * } super_container;
00051  *
00052  * void sample_object_destroy(struct sample_object *obj)
00053  * {
00054  *    free(obj);
00055  * }
00056  *
00057  * int init_stuff()
00058  * {
00059  *    struct sample_object *obj1;
00060  *    struct sample_object *found_obj;
00061  *
00062  *    obj1 = malloc(sizeof(struct sample_object));
00063  *
00064  *    ASTOBJ_CONTAINER_INIT(&super_container);
00065  *
00066  *    ASTOBJ_INIT(obj1);
00067  *    ASTOBJ_WRLOCK(obj1);
00068  *    ast_copy_string(obj1->name, "obj1", sizeof(obj1->name));
00069  *    ASTOBJ_UNLOCK(obj1);
00070  *
00071  *    ASTOBJ_CONTAINER_LINK(&super_container, obj1);
00072  *
00073  *    found_obj = ASTOBJ_CONTAINER_FIND(&super_container, "obj1");
00074  *
00075  *    if(found_obj) {
00076  *       printf("Found object: %s", found_obj->name); 
00077  *       ASTOBJ_UNREF(found_obj,sample_object_destroy);
00078  *    }
00079  *
00080  *    ASTOBJ_CONTAINER_DESTROYALL(&super_container,sample_object_destroy);
00081  *    ASTOBJ_CONTAINER_DESTROY(&super_container);
00082  * 
00083  *    return 0;
00084  * }
00085  * \endcode
00086  */
00087 
00088 #if defined(__cplusplus) || defined(c_plusplus)
00089 extern "C" {
00090 #endif
00091 
00092 #define ASTOBJ_DEFAULT_NAMELEN   80
00093 #define ASTOBJ_DEFAULT_BUCKETS   256
00094 #define ASTOBJ_DEFAULT_HASH      ast_strhash
00095 
00096 #define ASTOBJ_FLAG_MARKED (1 << 0)    /* Object has been marked for future operation */
00097 
00098 /* C++ is simply a syntactic crutch for those who cannot think for themselves
00099    in an object oriented way. */
00100 
00101 /*! \brief Lock an ASTOBJ for reading.
00102  */
00103 #define ASTOBJ_RDLOCK(object) ast_mutex_lock(&(object)->_lock)
00104 
00105 /*! \brief Lock an ASTOBJ for writing.
00106  */
00107 #define ASTOBJ_WRLOCK(object) ast_mutex_lock(&(object)->_lock)
00108 
00109 /*! \brief Unlock a locked object. */
00110 #define ASTOBJ_UNLOCK(object) ast_mutex_unlock(&(object)->_lock)
00111 
00112 #ifdef ASTOBJ_CONTAINER_HASHMODEL 
00113 #define __ASTOBJ_HASH(type,hashes) \
00114    type *next[hashes] 
00115 #else 
00116 #define __ASTOBJ_HASH(type,hashes) \
00117    type *next[1] 
00118 #endif   
00119 
00120 /*! \brief Add ASTOBJ components to a struct (without locking support).
00121  *
00122  * \param type The datatype of the object.
00123  * \param namelen The length to make the name char array.
00124  * \param hashes The number of containers the object can be present in.
00125  *
00126  * This macro adds components to a struct to make it an ASTOBJ.  This macro
00127  * differs from ASTOBJ_COMPONENTS_FULL in that it does not create a mutex for
00128  * locking.
00129  *
00130  * <b>Sample Usage:</b>
00131  * \code
00132  * struct sample_struct {
00133  *    ASTOBJ_COMPONENTS_NOLOCK_FULL(struct sample_struct,1,1);
00134  * };
00135  * \endcode
00136  */
00137 #define ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes) \
00138    char name[namelen]; \
00139    unsigned int refcount; \
00140    unsigned int objflags; \
00141    __ASTOBJ_HASH(type,hashes)
00142    
00143 /*! \brief Add ASTOBJ components to a struct (without locking support).
00144  *
00145  * \param type The datatype of the object.
00146  *
00147  * This macro works like #ASTOBJ_COMPONENTS_NOLOCK_FULL() except it only accepts a
00148  * type and uses default values for namelen and hashes.
00149  * 
00150  * <b>Sample Usage:</b>
00151  * \code
00152  * struct sample_struct_componets {
00153  *    ASTOBJ_COMPONENTS_NOLOCK(struct sample_struct);
00154  * };
00155  * \endcode
00156  */
00157 #define ASTOBJ_COMPONENTS_NOLOCK(type) \
00158    ASTOBJ_COMPONENTS_NOLOCK_FULL(type,ASTOBJ_DEFAULT_NAMELEN,1)
00159 
00160 /*! \brief Add ASTOBJ components to a struct (with locking support).
00161  *
00162  * \param type The datatype of the object.
00163  *
00164  * This macro works like #ASTOBJ_COMPONENTS_NOLOCK() except it includes locking
00165  * support.
00166  *
00167  * <b>Sample Usage:</b>
00168  * \code
00169  * struct sample_struct {
00170  *    ASTOBJ_COMPONENTS(struct sample_struct);
00171  * };
00172  * \endcode
00173  */
00174 #define ASTOBJ_COMPONENTS(type) \
00175    ASTOBJ_COMPONENTS_NOLOCK(type); \
00176    ast_mutex_t _lock; 
00177    
00178 /*! \brief Add ASTOBJ components to a struct (with locking support).
00179  *
00180  * \param type The datatype of the object.
00181  * \param namelen The length to make the name char array.
00182  * \param hashes The number of containers the object can be present in.
00183  *
00184  * This macro adds components to a struct to make it an ASTOBJ and includes
00185  * support for locking.
00186  *
00187  * <b>Sample Usage:</b>
00188  * \code
00189  * struct sample_struct {
00190  *    ASTOBJ_COMPONENTS_FULL(struct sample_struct,1,1);
00191  * };
00192  * \endcode
00193  */
00194 #define ASTOBJ_COMPONENTS_FULL(type,namelen,hashes) \
00195    ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes); \
00196    ast_mutex_t _lock; 
00197 
00198 /*! \brief Increment an object reference count.
00199  * \param object A pointer to the object to operate on.
00200  * \return The object.
00201  */
00202 #define ASTOBJ_REF(object) \
00203    ({ \
00204       ASTOBJ_WRLOCK(object); \
00205       (object)->refcount++; \
00206       ASTOBJ_UNLOCK(object); \
00207       (object); \
00208    })
00209    
00210 /*! \brief Decrement the reference count on an object.
00211  *
00212  * \param object A pointer the object to operate on.
00213  * \param destructor The destructor to call if the object is no longer referenced.  It will be passed the pointer as an argument.
00214  *
00215  * This macro unreferences an object and calls the specfied destructor if the
00216  * object is no longer referenced.  The destructor should free the object if it
00217  * was dynamically allocated.
00218  */
00219 #define ASTOBJ_UNREF(object,destructor) \
00220    do { \
00221       int newcount = 0; \
00222       ASTOBJ_WRLOCK(object); \
00223       if (__builtin_expect((object)->refcount > 0, 1)) \
00224          newcount = --((object)->refcount); \
00225       else \
00226          ast_log(LOG_WARNING, "Unreferencing unreferenced (object)!\n"); \
00227       ASTOBJ_UNLOCK(object); \
00228       if (newcount == 0) { \
00229          ast_mutex_destroy(&(object)->_lock); \
00230          destructor((object)); \
00231       } \
00232       (object) = NULL; \
00233    } while(0)
00234 
00235 /*! \brief Mark an ASTOBJ by adding the #ASTOBJ_FLAG_MARKED flag to its objflags mask. 
00236  * \param object A pointer to the object to operate on.
00237  *
00238  * This macro "marks" an object.  Marked objects can later be unlinked from a container using
00239  * #ASTOBJ_CONTAINER_PRUNE_MARKED().
00240  * 
00241  */
00242 #define ASTOBJ_MARK(object) \
00243    do { \
00244       ASTOBJ_WRLOCK(object); \
00245       (object)->objflags |= ASTOBJ_FLAG_MARKED; \
00246       ASTOBJ_UNLOCK(object); \
00247    } while(0)
00248    
00249 /*! \brief Unmark an ASTOBJ by subtracting the #ASTOBJ_FLAG_MARKED flag from its objflags mask.
00250  * \param object A pointer to the object to operate on.
00251  */
00252 #define ASTOBJ_UNMARK(object) \
00253    do { \
00254       ASTOBJ_WRLOCK(object); \
00255       (object)->objflags &= ~ASTOBJ_FLAG_MARKED; \
00256       ASTOBJ_UNLOCK(object); \
00257    } while(0)
00258 
00259 /*! \brief Initialize an object.
00260  * \param object A pointer to the object to operate on.
00261  *
00262  * \note This should only be used on objects that support locking (objects
00263  * created with #ASTOBJ_COMPONENTS() or #ASTOBJ_COMPONENTS_FULL())
00264  */
00265 #define ASTOBJ_INIT(object) \
00266    do { \
00267       ast_mutex_init(&(object)->_lock); \
00268       object->name[0] = '\0'; \
00269       object->refcount = 1; \
00270    } while(0)
00271 
00272 /* Containers for objects -- current implementation is linked lists, but
00273    should be able to be converted to hashes relatively easily */
00274 
00275 /*! \brief Lock an ASTOBJ_CONTAINER for reading.
00276  */
00277 #define ASTOBJ_CONTAINER_RDLOCK(container) ast_mutex_lock(&(container)->_lock)
00278 
00279 /*! \brief Lock an ASTOBJ_CONTAINER for writing. 
00280  */
00281 #define ASTOBJ_CONTAINER_WRLOCK(container) ast_mutex_lock(&(container)->_lock)
00282 
00283 /*! \brief Unlock an ASTOBJ_CONTAINER. */
00284 #define ASTOBJ_CONTAINER_UNLOCK(container) ast_mutex_unlock(&(container)->_lock)
00285 
00286 #ifdef ASTOBJ_CONTAINER_HASHMODEL
00287 #error "Hash model for object containers not yet implemented!"
00288 #else
00289 /* Linked lists */
00290 
00291 /*! \brief Create a container for ASTOBJs (without locking support).
00292  *
00293  * \param type The type of objects the container will hold.
00294  * \param hashes Currently unused.
00295  * \param buckets Currently unused.
00296  *
00297  * This macro is used to create a container for ASTOBJs without locking
00298  * support.
00299  *
00300  * <b>Sample Usage:</b>
00301  * \code
00302  * struct sample_struct_nolock_container {
00303  *    ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(struct sample_struct,1,1);
00304  * };
00305  * \endcode
00306  */
00307 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,hashes,buckets) \
00308    type *head
00309 
00310 /*! \brief Initialize a container.
00311  *
00312  * \param container A pointer to the container to initialize.
00313  * \param hashes Currently unused.
00314  * \param buckets Currently unused.
00315  *
00316  * This macro initializes a container.  It should only be used on containers
00317  * that support locking.
00318  * 
00319  * <b>Sample Usage:</b>
00320  * \code
00321  * struct sample_struct_container {
00322  *    ASTOBJ_CONTAINER_COMPONENTS_FULL(struct sample_struct,1,1);
00323  * } container;
00324  *
00325  * int func()
00326  * {
00327  *    ASTOBJ_CONTAINER_INIT_FULL(&container,1,1);
00328  * }
00329  * \endcode
00330  */
00331 #define ASTOBJ_CONTAINER_INIT_FULL(container,hashes,buckets) \
00332    do { \
00333       ast_mutex_init(&(container)->_lock); \
00334    } while(0)
00335    
00336 /*! \brief Destroy a container.
00337  *
00338  * \param container A pointer to the container to destroy.
00339  * \param hashes Currently unused.
00340  * \param buckets Currently unused.
00341  *
00342  * This macro frees up resources used by a container.  It does not operate on
00343  * the objects in the container.  To unlink the objects from the container use
00344  * #ASTOBJ_CONTAINER_DESTROYALL().
00345  *
00346  * \note This macro should only be used on containers with locking support.
00347  */
00348 #define ASTOBJ_CONTAINER_DESTROY_FULL(container,hashes,buckets) \
00349    do { \
00350       ast_mutex_destroy(&(container)->_lock); \
00351    } while(0)
00352 
00353 /*! \brief Iterate through the objects in a container.
00354  *
00355  * \param container A pointer to the container to traverse.
00356  * \param continue A condition to allow the traversal to continue.
00357  * \param eval A statement to evaluate in the iteration loop.
00358  *
00359  * This is macro is a little complicated, but it may help to think of it as a
00360  * loop.  Basically it iterates through the specfied containter as long as the
00361  * condition is met.  Two variables, iterator and next, are provided for use in
00362  * your \p eval statement.  See the sample code for an example.
00363  *
00364  * <b>Sample Usage:</b>
00365  * \code
00366  * ASTOBJ_CONTAINER_TRAVERSE(&sample_container,1, {
00367  *    ASTOBJ_RDLOCK(iterator);
00368  *    printf("Currently iterating over '%s'\n", iterator->name);
00369  *    ASTOBJ_UNLOCK(iterator);
00370  * } );
00371  * \endcode
00372  *
00373  * \code
00374  * ASTOBJ_CONTAINER_TRAVERSE(&sample_container,1, sample_func(iterator));
00375  * \endcode
00376  */
00377 #define ASTOBJ_CONTAINER_TRAVERSE(container,continue,eval) \
00378    do { \
00379       typeof((container)->head) iterator; \
00380       typeof((container)->head) next; \
00381       ASTOBJ_CONTAINER_RDLOCK(container); \
00382       next = (container)->head; \
00383       while((continue) && (iterator = next)) { \
00384          next = iterator->next[0]; \
00385          eval; \
00386       } \
00387       ASTOBJ_CONTAINER_UNLOCK(container); \
00388    } while(0)
00389 
00390 /*! \brief Find an object in a container.
00391  *
00392  * \param container A pointer to the container to search.
00393  * \param namestr The name to search for.
00394  *
00395  * Use this function to find an object with the specfied name in a container.
00396  *
00397  * \note When the returned object is no longer in use, #ASTOBJ_UNREF() should
00398  * be used to free the additional reference created by this macro.
00399  *
00400  * \return A new reference to the object located or NULL if nothing is found.
00401  */
00402 #define ASTOBJ_CONTAINER_FIND(container,namestr) \
00403    ({ \
00404       typeof((container)->head) found = NULL; \
00405       ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
00406          if (!(strcasecmp(iterator->name, (namestr)))) \
00407             found = ASTOBJ_REF(iterator); \
00408       } while (0)); \
00409       found; \
00410    })
00411 
00412 /*! \brief Find an object in a container.
00413  * 
00414  * \param container A pointer to the container to search.
00415  * \param data The data to search for.
00416  * \param field The field/member of the container's objects to search.
00417  * \param hashfunc The hash function to use, currently not implemented.
00418  * \param hashoffset The hash offset to use, currently not implemented.
00419  * \param comparefunc The function used to compare the field and data values.
00420  *
00421  * This macro iterates through a container passing the specified field and data
00422  * elements to the specified comparefunc.  The function should return 0 when a match is found.
00423  * 
00424  * \note When the returned object is no longer in use, #ASTOBJ_UNREF() should
00425  * be used to free the additional reference created by this macro.
00426  *
00427  * \return A pointer to the object located or NULL if nothing is found.
00428  */
00429 #define ASTOBJ_CONTAINER_FIND_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
00430    ({ \
00431       typeof((container)->head) found = NULL; \
00432       ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
00433          ASTOBJ_RDLOCK(iterator); \
00434          if (!(comparefunc(iterator->field, (data)))) { \
00435             found = ASTOBJ_REF(iterator); \
00436          } \
00437          ASTOBJ_UNLOCK(iterator); \
00438       } while (0)); \
00439       found; \
00440    })
00441 
00442 /*! \brief Empty a container.
00443  *
00444  * \param container A pointer to the container to operate on.
00445  * \param destructor A destructor function to call on each object.
00446  *
00447  * This macro loops through a container removing all the items from it using
00448  * #ASTOBJ_UNREF().  This does not destroy the container itself, use
00449  * #ASTOBJ_CONTAINER_DESTROY() for that.
00450  *
00451  * \note If any object in the container is only referenced by the container,
00452  * the destructor will be called for that object once it has been removed.
00453  */
00454 #define ASTOBJ_CONTAINER_DESTROYALL(container,destructor) \
00455    do { \
00456       typeof((container)->head) iterator; \
00457       ASTOBJ_CONTAINER_WRLOCK(container); \
00458       while((iterator = (container)->head)) { \
00459          (container)->head = (iterator)->next[0]; \
00460          ASTOBJ_UNREF(iterator,destructor); \
00461       } \
00462       ASTOBJ_CONTAINER_UNLOCK(container); \
00463    } while(0)
00464 
00465 /*! \brief Remove an object from a container.
00466  *
00467  * \param container A pointer to the container to operate on.
00468  * \param obj A pointer to the object to remove.
00469  *
00470  * This macro iterates through a container and removes the specfied object if
00471  * it exists in the container.
00472  *
00473  * \note This macro does not destroy any objects, it simply unlinks
00474  * them from the list.  No destructors are called.
00475  *
00476  * \return The container's reference to the removed object or NULL if no
00477  * matching object was found.
00478  */
00479 #define ASTOBJ_CONTAINER_UNLINK(container,obj) \
00480    ({ \
00481       typeof((container)->head) found = NULL; \
00482       typeof((container)->head) prev = NULL; \
00483       ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
00484          if (iterator == obj) { \
00485             found = iterator; \
00486             found->next[0] = NULL; \
00487             ASTOBJ_CONTAINER_WRLOCK(container); \
00488             if (prev) \
00489                prev->next[0] = next; \
00490             else \
00491                (container)->head = next; \
00492             ASTOBJ_CONTAINER_UNLOCK(container); \
00493          } \
00494          prev = iterator; \
00495       } while (0)); \
00496       found; \
00497    })
00498 
00499 /*! \brief Find and remove an object from a container.
00500  * 
00501  * \param container A pointer to the container to operate on.
00502  * \param namestr The name of the object to remove.
00503  *
00504  * This macro iterates through a container and removes the first object with
00505  * the specfied name from the container.
00506  *
00507  * \note This macro does not destroy any objects, it simply unlinks
00508  * them.  No destructors are called.
00509  *
00510  * \return The container's reference to the removed object or NULL if no
00511  * matching object was found.
00512  */
00513 #define ASTOBJ_CONTAINER_FIND_UNLINK(container,namestr) \
00514    ({ \
00515       typeof((container)->head) found = NULL; \
00516       typeof((container)->head) prev = NULL; \
00517       ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
00518          if (!(strcasecmp(iterator->name, (namestr)))) { \
00519             found = iterator; \
00520             found->next[0] = NULL; \
00521             ASTOBJ_CONTAINER_WRLOCK(container); \
00522             if (prev) \
00523                prev->next[0] = next; \
00524             else \
00525                (container)->head = next; \
00526             ASTOBJ_CONTAINER_UNLOCK(container); \
00527          } \
00528          prev = iterator; \
00529       } while (0)); \
00530       found; \
00531    })
00532 
00533 /*! \brief Find and remove an object in a container.
00534  * 
00535  * \param container A pointer to the container to search.
00536  * \param data The data to search for.
00537  * \param field The field/member of the container's objects to search.
00538  * \param hashfunc The hash function to use, currently not implemented.
00539  * \param hashoffset The hash offset to use, currently not implemented.
00540  * \param comparefunc The function used to compare the field and data values.
00541  *
00542  * This macro iterates through a container passing the specified field and data
00543  * elements to the specified comparefunc.  The function should return 0 when a match is found.
00544  * If a match is found it is removed from the list. 
00545  *
00546  * \note This macro does not destroy any objects, it simply unlinks
00547  * them.  No destructors are called.
00548  *
00549  * \return The container's reference to the removed object or NULL if no match
00550  * was found.
00551  */
00552 #define ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
00553    ({ \
00554       typeof((container)->head) found = NULL; \
00555       typeof((container)->head) prev = NULL; \
00556       ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
00557          ASTOBJ_RDLOCK(iterator); \
00558          if (!(comparefunc(iterator->field, (data)))) { \
00559             found = iterator; \
00560             found->next[0] = NULL; \
00561             ASTOBJ_CONTAINER_WRLOCK(container); \
00562             if (prev) \
00563                prev->next[0] = next; \
00564             else \
00565                (container)->head = next; \
00566             ASTOBJ_CONTAINER_UNLOCK(container); \
00567          } \
00568          ASTOBJ_UNLOCK(iterator); \
00569          prev = iterator; \
00570       } while (0)); \
00571       found; \
00572    })
00573 
00574 /*! \brief Add an object to the end of a container.
00575  *
00576  * \param container A pointer to the container to operate on.
00577  * \param newobj A pointer to the object to be added.
00578  *
00579  * This macro adds an object to the end of a container.
00580  */
00581 #define ASTOBJ_CONTAINER_LINK_END(container,newobj) \
00582    do { \
00583       typeof((container)->head) iterator; \
00584       typeof((container)->head) next; \
00585       typeof((container)->head) prev; \
00586       ASTOBJ_CONTAINER_RDLOCK(container); \
00587       prev = NULL; \
00588       next = (container)->head; \
00589       while((iterator = next)) { \
00590          next = iterator->next[0]; \
00591          prev = iterator; \
00592       } \
00593       if(prev) { \
00594          ASTOBJ_CONTAINER_WRLOCK((container)); \
00595          prev->next[0] = ASTOBJ_REF(newobj); \
00596          (newobj)->next[0] = NULL; \
00597          ASTOBJ_CONTAINER_UNLOCK((container)); \
00598       } else { \
00599          ASTOBJ_CONTAINER_LINK_START((container),(newobj)); \
00600       } \
00601       ASTOBJ_CONTAINER_UNLOCK((container)); \
00602    } while(0)
00603 
00604 /*! \brief Add an object to the front of a container.
00605  *
00606  * \param container A pointer to the container to operate on.
00607  * \param newobj A pointer to the object to be added.
00608  *
00609  * This macro adds an object to the start of a container.
00610  */
00611 #define ASTOBJ_CONTAINER_LINK_START(container,newobj) \
00612    do { \
00613       ASTOBJ_CONTAINER_WRLOCK(container); \
00614       (newobj)->next[0] = (container)->head; \
00615       (container)->head = ASTOBJ_REF(newobj); \
00616       ASTOBJ_CONTAINER_UNLOCK(container); \
00617    } while(0)
00618 
00619 /*! \brief Remove an object from the front of a container.
00620  *
00621  * \param container A pointer to the container to operate on.
00622  *
00623  * This macro removes the first object in a container.
00624  *
00625  * \note This macro does not destroy any objects, it simply unlinks
00626  * them from the list.  No destructors are called.
00627  *
00628  * \return The container's reference to the removed object or NULL if no
00629  * matching object was found.
00630  */
00631 #define ASTOBJ_CONTAINER_UNLINK_START(container) \
00632    ({ \
00633       typeof((container)->head) found = NULL; \
00634       ASTOBJ_CONTAINER_WRLOCK(container); \
00635       if((container)->head) { \
00636          found = (container)->head; \
00637          (container)->head = (container)->head->next[0]; \
00638          found->next[0] = NULL; \
00639       } \
00640       ASTOBJ_CONTAINER_UNLOCK(container); \
00641       found; \
00642    })
00643 
00644 /*! \brief Prune marked objects from a container.
00645  *
00646  * \param container A pointer to the container to prune.
00647  * \param destructor A destructor function to call on each marked object.
00648  * 
00649  * This macro iterates through the specfied container and prunes any marked
00650  * objects executing the specfied destructor if necessary.
00651  */
00652 #define ASTOBJ_CONTAINER_PRUNE_MARKED(container,destructor) \
00653    do { \
00654       typeof((container)->head) prev = NULL; \
00655       ASTOBJ_CONTAINER_TRAVERSE(container, 1, do { \
00656          ASTOBJ_RDLOCK(iterator); \
00657          if (iterator->objflags & ASTOBJ_FLAG_MARKED) { \
00658             ASTOBJ_CONTAINER_WRLOCK(container); \
00659             if (prev) \
00660                prev->next[0] = next; \
00661             else \
00662                (container)->head = next; \
00663             ASTOBJ_CONTAINER_UNLOCK(container); \
00664             ASTOBJ_UNLOCK(iterator); \
00665             ASTOBJ_UNREF(iterator,destructor); \
00666             continue; \
00667          } \
00668          ASTOBJ_UNLOCK(iterator); \
00669          prev = iterator; \
00670       } while (0)); \
00671    } while(0)
00672 
00673 /*! \brief Add an object to a container.
00674  *
00675  * \param container A pointer to the container to operate on.
00676  * \param newobj A pointer to the object to be added.
00677  * \param data Currently unused.
00678  * \param field Currently unused.
00679  * \param hashfunc Currently unused.
00680  * \param hashoffset Currently unused.
00681  * \param comparefunc Currently unused.
00682  *
00683  * Currently this function adds an object to the head of the list.  One day it
00684  * will support adding objects atthe position specified using the various
00685  * options this macro offers.
00686  */
00687 #define ASTOBJ_CONTAINER_LINK_FULL(container,newobj,data,field,hashfunc,hashoffset,comparefunc) \
00688    do { \
00689       ASTOBJ_CONTAINER_WRLOCK(container); \
00690       (newobj)->next[0] = (container)->head; \
00691       (container)->head = ASTOBJ_REF(newobj); \
00692       ASTOBJ_CONTAINER_UNLOCK(container); \
00693    } while(0)
00694 
00695 #endif /* List model */
00696 
00697 /* Common to hash and linked list models */
00698 
00699 /*! \brief Create a container for ASTOBJs (without locking support).
00700  *
00701  * \param type The type of objects the container will hold.
00702  *
00703  * This macro is used to create a container for ASTOBJs without locking
00704  * support.
00705  *
00706  * <b>Sample Usage:</b>
00707  * \code
00708  * struct sample_struct_nolock_container {
00709  *    ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(struct sample_struct);
00710  * };
00711  * \endcode
00712  */
00713 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) \
00714    ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,1,ASTOBJ_DEFAULT_BUCKETS)
00715 
00716 
00717 /*! \brief Create a container for ASTOBJs (with locking support).
00718  *
00719  * \param type The type of objects the container will hold.
00720  *
00721  * This macro is used to create a container for ASTOBJs with locking support.
00722  *
00723  * <b>Sample Usage:</b>
00724  * \code
00725  * struct sample_struct_container {
00726  *    ASTOBJ_CONTAINER_COMPONENTS(struct sample_struct);
00727  * };
00728  * \endcode
00729  */
00730 #define ASTOBJ_CONTAINER_COMPONENTS(type) \
00731    ast_mutex_t _lock; \
00732    ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type)
00733 
00734 /*! \brief Initialize a container.
00735  *
00736  * \param container A pointer to the container to initialize.
00737  *
00738  * This macro initializes a container.  It should only be used on containers
00739  * that support locking.
00740  * 
00741  * <b>Sample Usage:</b>
00742  * \code
00743  * struct sample_struct_container {
00744  *    ASTOBJ_CONTAINER_COMPONENTS(struct sample_struct);
00745  * } container;
00746  *
00747  * int func()
00748  * {
00749  *    ASTOBJ_CONTAINER_INIT(&container);
00750  * }
00751  * \endcode
00752  */
00753 #define ASTOBJ_CONTAINER_INIT(container) \
00754    ASTOBJ_CONTAINER_INIT_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
00755 
00756 /*! \brief Destroy a container.
00757  *
00758  * \param container A pointer to the container to destory.
00759  *
00760  * This macro frees up resources used by a container.  It does not operate on
00761  * the objects in the container.  To unlink the objects from the container use
00762  * #ASTOBJ_CONTAINER_DESTROYALL().
00763  *
00764  * \note This macro should only be used on containers with locking support.
00765  */
00766 #define ASTOBJ_CONTAINER_DESTROY(container) \
00767    ASTOBJ_CONTAINER_DESTROY_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
00768 
00769 /*! \brief Add an object to a container.
00770  *
00771  * \param container A pointer to the container to operate on.
00772  * \param newobj A pointer to the object to be added.
00773  *
00774  * Currently this macro adds an object to the head of a container.  One day it
00775  * should add an object in alphabetical order.
00776  */
00777 #define ASTOBJ_CONTAINER_LINK(container,newobj) \
00778    ASTOBJ_CONTAINER_LINK_FULL(container,newobj,(newobj)->name,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
00779 
00780 /*! \brief Mark all the objects in a container.
00781  * \param container A pointer to the container to operate on.
00782  */
00783 #define ASTOBJ_CONTAINER_MARKALL(container) \
00784    ASTOBJ_CONTAINER_TRAVERSE(container, 1, ASTOBJ_MARK(iterator))
00785 
00786 /*! \brief Unmark all the objects in a container.
00787  * \param container A pointer to the container to operate on.
00788  */
00789 #define ASTOBJ_CONTAINER_UNMARKALL(container) \
00790    ASTOBJ_CONTAINER_TRAVERSE(container, 1, ASTOBJ_UNMARK(iterator))
00791 
00792 /*! \brief Dump information about an object into a string.
00793  *
00794  * \param s A pointer to the string buffer to use.
00795  * \param slen The length of s.
00796  * \param obj A pointer to the object to dump.
00797  *
00798  * This macro dumps a text representation of the name, objectflags, and
00799  * refcount fields of an object to the specfied string buffer.
00800  */
00801 #define ASTOBJ_DUMP(s,slen,obj) \
00802    snprintf((s),(slen),"name: %s\nobjflags: %d\nrefcount: %d\n\n", (obj)->name, (obj)->objflags, (obj)->refcount);
00803 
00804 /*! \brief Dump information about all the objects in a container to a file descriptor.
00805  *
00806  * \param fd The file descriptor to write to.
00807  * \param s A string buffer, same as #ASTOBJ_DUMP().
00808  * \param slen The length of s, same as #ASTOBJ_DUMP().
00809  * \param container A pointer to the container to dump.
00810  *
00811  * This macro dumps a text representation of the name, objectflags, and
00812  * refcount fields of all the objects in a container to the specified file
00813  * descriptor.
00814  */
00815 #define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container) \
00816    ASTOBJ_CONTAINER_TRAVERSE(container, 1, do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, s); } while(0))
00817 
00818 #if defined(__cplusplus) || defined(c_plusplus)
00819 }
00820 #endif
00821 
00822 #endif /* _ASTERISK_ASTOBJ_H */

Generated on Mon May 14 04:42:52 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1