Mon Aug 31 12:30:01 2015

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

Generated on 31 Aug 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1