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