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 */