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