Sat Aug 6 00:39:22 2011

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

Generated on Sat Aug 6 00:39:22 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7