2 * Asterisk -- A telephony toolkit for Linux.
4 * Object Model for Asterisk
6 * Copyright (C) 2004 - 2005, Digium, Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
14 #ifndef _ASTERISK_ASTOBJ_H
15 #define _ASTERISK_ASTOBJ_H
18 #include "asterisk/lock.h"
21 * \brief A set of macros implementing objects and containers.
22 * Macros are used for maximum performance, to support multiple inheritance,
23 * and to be easily integrated into existing structures without additional
26 * These macros expect to operate on two different object types, ASTOBJs and
27 * ASTOBJ_CONTAINERs. These are not actual types, as any struct can be
28 * converted into an ASTOBJ compatible object or container using the supplied
31 * <b>Sample Usage:</b>
33 * struct sample_object {
34 * ASTOBJ_COMPONENTS(struct sample_object);
37 * struct sample_container {
38 * ASTOBJ_CONTAINER_COMPONENTS(struct sample_object);
41 * void sample_object_destroy(struct sample_object *obj)
48 * struct sample_object *obj1;
49 * struct sample_object *found_obj;
51 * obj1 = malloc(sizeof(struct sample_object));
53 * ASTOBJ_CONTAINER_INIT(&super_container);
56 * ASTOBJ_WRLOCK(obj1);
57 * ast_copy_string(obj1->name, "obj1", sizeof(obj1->name));
58 * ASTOBJ_UNLOCK(obj1);
60 * ASTOBJ_CONTAINER_LINK(&super_container, obj1);
62 * found_obj = ASTOBJ_CONTAINER_FIND(&super_container, "obj1");
65 * printf("Found object: %s", found_obj->name);
66 * ASTOBJ_UNREF(found_obj,sample_object_destroy);
69 * ASTOBJ_CONTAINER_DESTROYALL(&super_container,sample_object_destroy);
70 * ASTOBJ_CONTAINER_DESTROY(&super_container);
77 #if defined(__cplusplus) || defined(c_plusplus)
81 #define ASTOBJ_DEFAULT_NAMELEN 80
82 #define ASTOBJ_DEFAULT_BUCKETS 256
83 #define ASTOBJ_DEFAULT_HASH ast_strhash
85 #define ASTOBJ_FLAG_MARKED (1 << 0) /* Object has been marked for future operation */
87 #if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
88 #define __builtin_expect(exp, c) (exp)
91 /* C++ is simply a syntactic crutch for those who cannot think for themselves
92 in an object oriented way. */
94 /*! \brief Lock an ASTOBJ for reading.
96 #define ASTOBJ_RDLOCK(object) ast_mutex_lock(&(object)->_lock)
98 /*! \brief Lock an ASTOBJ for writing.
100 #define ASTOBJ_WRLOCK(object) ast_mutex_lock(&(object)->_lock)
102 /*! \brief Unlock a locked object. */
103 #define ASTOBJ_UNLOCK(object) ast_mutex_unlock(&(object)->_lock)
105 #ifdef ASTOBJ_CONTAINER_HASHMODEL
106 #define __ASTOBJ_HASH(type,hashes) \
109 #define __ASTOBJ_HASH(type,hashes) \
113 /*! \brief Add ASTOBJ components to a struct (without locking support).
115 * \param type The datatype of the object.
116 * \param namelen The length to make the name char array.
117 * \param hashes The number of containers the object can be present in.
119 * This macro adds components to a struct to make it an ASTOBJ. This macro
120 * differs from ASTOBJ_COMPONENTS_FULL in that it does not create a mutex for
123 * <b>Sample Usage:</b>
125 * struct sample_struct {
126 * ASTOBJ_COMPONENTS_NOLOCK_FULL(struct sample_struct,1,1);
130 #define ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes) \
131 char name[namelen]; \
134 __ASTOBJ_HASH(type,hashes)
136 /*! \brief Add ASTOBJ components to a struct (without locking support).
138 * \param type The datatype of the object.
140 * This macro works like #ASTOBJ_COMPONENTS_NOLOCK_FULL() except it only accepts a
141 * type and uses default values for namelen and hashes.
143 * <b>Sample Usage:</b>
145 * struct sample_struct_componets {
146 * ASTOBJ_COMPONENTS_NOLOCK(struct sample_struct);
150 #define ASTOBJ_COMPONENTS_NOLOCK(type) \
151 ASTOBJ_COMPONENTS_NOLOCK_FULL(type,ASTOBJ_DEFAULT_NAMELEN,1)
153 /*! \brief Add ASTOBJ components to a struct (with locking support).
155 * \param type The datatype of the object.
157 * This macro works like #ASTOBJ_COMPONENTS_NOLOCK() except it includes locking
160 * <b>Sample Usage:</b>
162 * struct sample_struct {
163 * ASTOBJ_COMPONENTS(struct sample_struct);
167 #define ASTOBJ_COMPONENTS(type) \
168 ASTOBJ_COMPONENTS_NOLOCK(type); \
171 /*! \brief Add ASTOBJ components to a struct (with locking support).
173 * \param type The datatype of the object.
174 * \param namelen The length to make the name char array.
175 * \param hashes The number of containers the object can be present in.
177 * This macro adds components to a struct to make it an ASTOBJ and includes
178 * support for locking.
180 * <b>Sample Usage:</b>
182 * struct sample_struct {
183 * ASTOBJ_COMPONENTS_FULL(struct sample_struct,1,1);
187 #define ASTOBJ_COMPONENTS_FULL(type,namelen,hashes) \
188 ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes); \
191 /*! \brief Increment an object reference count.
192 * \param object A pointer to the object to operate on.
193 * \return The object.
195 #define ASTOBJ_REF(object) \
197 ASTOBJ_WRLOCK(object); \
198 (object)->refcount++; \
199 ASTOBJ_UNLOCK(object); \
203 /*! \brief Decrement the reference count on an object.
205 * \param object A pointer the object to operate on.
206 * \param destructor The destructor to call if the object is no longer referenced. It will be passed the pointer as an argument.
208 * This macro unreferences an object and calls the specfied destructor if the
209 * object is no longer referenced. The destructor should free the object if it
210 * was dynamically allocated.
212 #define ASTOBJ_UNREF(object,destructor) \
215 ASTOBJ_WRLOCK(object); \
216 if (__builtin_expect((object)->refcount, 1)) \
217 newcount = --((object)->refcount); \
219 ast_log(LOG_WARNING, "Unreferencing unreferenced (object)!\n"); \
220 ASTOBJ_UNLOCK(object); \
221 if (newcount == 0) { \
222 ast_mutex_destroy(&(object)->_lock); \
223 destructor((object)); \
228 /*! \brief Mark an ASTOBJ by adding the #ASTOBJ_FLAG_MARKED flag to its objflags mask.
229 * \param object A pointer to the object to operate on.
231 * This macro "marks" an object. Marked objects can later be unlinked from a container using
232 * #ASTOBJ_CONTAINER_PRUNE_MARKED().
235 #define ASTOBJ_MARK(object) \
237 ASTOBJ_WRLOCK(object); \
238 (object)->objflags |= ASTOBJ_FLAG_MARKED; \
239 ASTOBJ_UNLOCK(object); \
242 /*! \brief Unmark an ASTOBJ by subtracting the #ASTOBJ_FLAG_MARKED flag from its objflags mask.
243 * \param object A pointer to the object to operate on.
245 #define ASTOBJ_UNMARK(object) \
247 ASTOBJ_WRLOCK(object); \
248 (object)->objflags &= ~ASTOBJ_FLAG_MARKED; \
249 ASTOBJ_UNLOCK(object); \
252 /*! \brief Initialize an object.
253 * \param object A pointer to the object to operate on.
255 * \note This should only be used on objects that support locking (objects
256 * created with #ASTOBJ_COMPONENTS() or #ASTOBJ_COMPONENTS_FULL())
258 #define ASTOBJ_INIT(object) \
260 ast_mutex_init(&(object)->_lock); \
261 object->name[0] = '\0'; \
262 object->refcount = 1; \
265 /* Containers for objects -- current implementation is linked lists, but
266 should be able to be converted to hashes relatively easily */
268 /*! \brief Lock an ASTOBJ_CONTAINER for reading.
270 #define ASTOBJ_CONTAINER_RDLOCK(container) ast_mutex_lock(&(container)->_lock)
272 /*! \brief Lock an ASTOBJ_CONTAINER for writing.
274 #define ASTOBJ_CONTAINER_WRLOCK(container) ast_mutex_lock(&(container)->_lock)
276 /*! \brief Unlock an ASTOBJ_CONTAINER. */
277 #define ASTOBJ_CONTAINER_UNLOCK(container) ast_mutex_unlock(&(container)->_lock)
279 #ifdef ASTOBJ_CONTAINER_HASHMODEL
280 #error "Hash model for object containers not yet implemented!"
284 /*! \brief Create a container for ASTOBJs (without locking support).
286 * \param type The type of objects the container will hold.
287 * \param hashes Currently unused.
288 * \param buckets Currently unused.
290 * This macro is used to create a container for ASTOBJs without locking
293 * <b>Sample Usage:</b>
295 * struct sample_struct_nolock_container {
296 * ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(struct sample_struct,1,1);
300 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,hashes,buckets) \
303 /*! \brief Initialize a container.
305 * \param container A pointer to the container to initialize.
306 * \param hashes Currently unused.
307 * \param buckets Currently unused.
309 * This macro initializes a container. It should only be used on containers
310 * that support locking.
312 * <b>Sample Usage:</b>
314 * struct sample_struct_container {
315 * ASTOBJ_CONTAINER_COMPONENTS_FULL(struct sample_struct,1,1);
320 * ASTOBJ_CONTAINER_INIT_FULL(&container,1,1);
324 #define ASTOBJ_CONTAINER_INIT_FULL(container,hashes,buckets) \
326 ast_mutex_init(&(container)->_lock); \
329 /*! \brief Destroy a container.
331 * \param container A pointer to the container to destroy.
332 * \param hashes Currently unused.
333 * \param buckets Currently unused.
335 * This macro frees up resources used by a container. It does not operate on
336 * the objects in the container. To unlink the objects from the container use
337 * #ASTOBJ_CONTAINER_DESTROYALL().
339 * \note This macro should only be used on containers with locking support.
341 #define ASTOBJ_CONTAINER_DESTROY_FULL(container,hashes,buckets) \
343 ast_mutex_destroy(&(container)->_lock); \
346 /*! \brief Iterate through the objects in a container.
348 * \param container A pointer to the container to traverse.
349 * \param continue A condition to allow the traversal to continue.
350 * \param eval A statement to evaluate in the iteration loop.
352 * This is macro is a little complicated, but it may help to think of it as a
353 * loop. Basically it iterates through the specfied containter as long as the
354 * condition is met. Two variables, iterator and next, are provided for use in
355 * your \p eval statement. See the sample code for an example.
357 * <b>Sample Usage:</b>
359 * ASTOBJ_CONTAINER_TRAVERSE(&sample_container,1, {
360 * ASTOBJ_RDLOCK(iterator);
361 * printf("Currently iterating over '%s'\n", iterator->name);
362 * ASTOBJ_UNLOCK(iterator);
367 * ASTOBJ_CONTAINER_TRAVERSE(&sample_container,1, sample_func(iterator));
370 #define ASTOBJ_CONTAINER_TRAVERSE(container,continue,eval) \
372 typeof((container)->head) iterator; \
373 typeof((container)->head) next; \
374 ASTOBJ_CONTAINER_RDLOCK(container); \
375 next = (container)->head; \
376 while((continue) && (iterator = next)) { \
377 next = iterator->next[0]; \
380 ASTOBJ_CONTAINER_UNLOCK(container); \
383 /*! \brief Find an object in a container.
385 * \param container A pointer to the container to search.
386 * \param namestr The name to search for.
388 * Use this function to find an object with the specfied name in a container.
390 * \note When the returned object is no longer in use, #ASTOBJ_UNREF() should
391 * be used to free the additional reference created by this macro.
393 * \return A new reference to the object located or NULL if nothing is found.
395 #define ASTOBJ_CONTAINER_FIND(container,namestr) \
397 typeof((container)->head) found = NULL; \
398 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
399 if (!(strcasecmp(iterator->name, (namestr)))) \
400 found = ASTOBJ_REF(iterator); \
405 /*! \brief Find an object in a container.
407 * \param container A pointer to the container to search.
408 * \param data The data to search for.
409 * \param field The field/member of the container's objects to search.
410 * \param hashfunc The hash function to use, currently not implemented.
411 * \param hashoffset The hash offset to use, currently not implemented.
412 * \param comparefunc The function used to compare the field and data values.
414 * This macro iterates through a container passing the specified field and data
415 * elements to the specified comparefunc. The function should return 0 when a match is found.
417 * \note When the returned object is no longer in use, #ASTOBJ_UNREF() should
418 * be used to free the additional reference created by this macro.
420 * \return A pointer to the object located or NULL if nothing is found.
422 #define ASTOBJ_CONTAINER_FIND_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
424 typeof((container)->head) found = NULL; \
425 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
426 ASTOBJ_RDLOCK(iterator); \
427 if (!(comparefunc(iterator->field, (data)))) { \
428 found = ASTOBJ_REF(iterator); \
430 ASTOBJ_UNLOCK(iterator); \
435 /*! \brief Empty a container.
437 * \param container A pointer to the container to operate on.
438 * \param destructor A destructor function to call on each object.
440 * This macro loops through a container removing all the items from it using
441 * #ASTOBJ_UNREF(). This does not destroy the container itself, use
442 * #ASTOBJ_CONTAINER_DESTROY() for that.
444 * \note If any object in the container is only referenced by the container,
445 * the destructor will be called for that object once it has been removed.
447 #define ASTOBJ_CONTAINER_DESTROYALL(container,destructor) \
449 typeof((container)->head) iterator; \
450 ASTOBJ_CONTAINER_WRLOCK(container); \
451 while((iterator = (container)->head)) { \
452 (container)->head = (iterator)->next[0]; \
453 ASTOBJ_UNREF(iterator,destructor); \
455 ASTOBJ_CONTAINER_UNLOCK(container); \
458 /*! \brief Remove an object from a container.
460 * \param container A pointer to the container to operate on.
461 * \param obj A pointer to the object to remove.
463 * This macro iterates through a container and removes the specfied object if
464 * it exists in the container.
466 * \note This macro does not destroy any objects, it simply unlinks
467 * them from the list. No destructors are called.
469 * \return The object unlinked or NULL if no matching object was found.
471 #define ASTOBJ_CONTAINER_UNLINK(container,obj) \
473 typeof((container)->head) found = NULL; \
474 typeof((container)->head) prev = NULL; \
475 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
476 if (iterator == obj) { \
478 found->next[0] = NULL; \
479 ASTOBJ_CONTAINER_WRLOCK(container); \
481 prev->next[0] = next; \
483 (container)->head = next; \
484 ASTOBJ_CONTAINER_UNLOCK(container); \
491 /*! \brief Find and remove an object from a container.
493 * \param container A pointer to the container to operate on.
494 * \param namestr The name of the object to remove.
496 * This macro iterates through a container and removes the first object with
497 * the specfied name from the container.
499 * \note This macro does not destroy any objects, it simply unlinks
500 * them. No destructors are called.
502 * \return The container's reference to the removed object or NULL if no
503 * matching object was found.
505 #define ASTOBJ_CONTAINER_FIND_UNLINK(container,namestr) \
507 typeof((container)->head) found = NULL; \
508 typeof((container)->head) prev = NULL; \
509 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
510 if (!(strcasecmp(iterator->name, (namestr)))) { \
512 found->next[0] = NULL; \
513 ASTOBJ_CONTAINER_WRLOCK(container); \
515 prev->next[0] = next; \
517 (container)->head = next; \
518 ASTOBJ_CONTAINER_UNLOCK(container); \
525 /*! \brief Find and remove an object in a container.
527 * \param container A pointer to the container to search.
528 * \param data The data to search for.
529 * \param field The field/member of the container's objects to search.
530 * \param hashfunc The hash function to use, currently not implemented.
531 * \param hashoffset The hash offset to use, currently not implemented.
532 * \param comparefunc The function used to compare the field and data values.
534 * This macro iterates through a container passing the specified field and data
535 * elements to the specified comparefunc. The function should return 0 when a match is found.
536 * If a match is found it is removed from the list.
538 * \note This macro does not destroy any objects, it simply unlinks
539 * them. No destructors are called.
541 * \return The container's reference to the removed object or NULL if no match
544 #define ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
546 typeof((container)->head) found = NULL; \
547 typeof((container)->head) prev = NULL; \
548 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
549 ASTOBJ_RDLOCK(iterator); \
550 if (!(comparefunc(iterator->field, (data)))) { \
552 found->next[0] = NULL; \
553 ASTOBJ_CONTAINER_WRLOCK(container); \
555 prev->next[0] = next; \
557 (container)->head = next; \
558 ASTOBJ_CONTAINER_UNLOCK(container); \
560 ASTOBJ_UNLOCK(iterator); \
566 /*! \brief Prune marked objects from a container.
568 * \param container A pointer to the container to prune.
569 * \param destructor A destructor function to call on each marked object.
571 * This macro iterates through the specfied container and prunes any marked
572 * objects executing the specfied destructor if necessary.
574 #define ASTOBJ_CONTAINER_PRUNE_MARKED(container,destructor) \
576 typeof((container)->head) prev = NULL; \
577 ASTOBJ_CONTAINER_TRAVERSE(container, 1, do { \
578 ASTOBJ_RDLOCK(iterator); \
579 if (iterator->objflags & ASTOBJ_FLAG_MARKED) { \
580 ASTOBJ_CONTAINER_WRLOCK(container); \
582 prev->next[0] = next; \
584 (container)->head = next; \
585 ASTOBJ_CONTAINER_UNLOCK(container); \
586 ASTOBJ_UNLOCK(iterator); \
587 ASTOBJ_UNREF(iterator,destructor); \
590 ASTOBJ_UNLOCK(iterator); \
595 /*! \brief Add an object to a container.
597 * \param container A pointer to the container to operate on.
598 * \param newobj A pointer to the object to be added.
599 * \param data Currently unused.
600 * \param field Currently unused.
601 * \param hashfunc Currently unused.
602 * \param hashoffset Currently unused.
603 * \param comparefunc Currently unused.
605 * Currently this function adds an object to the head of the list. One day it
606 * will support adding objects atthe position specified using the various
607 * options this macro offers.
609 #define ASTOBJ_CONTAINER_LINK_FULL(container,newobj,data,field,hashfunc,hashoffset,comparefunc) \
611 ASTOBJ_CONTAINER_WRLOCK(container); \
612 (newobj)->next[0] = (container)->head; \
613 (container)->head = ASTOBJ_REF(newobj); \
614 ASTOBJ_CONTAINER_UNLOCK(container); \
617 #endif /* List model */
619 /* Common to hash and linked list models */
621 /*! \brief Create a container for ASTOBJs (without locking support).
623 * \param type The type of objects the container will hold.
625 * This macro is used to create a container for ASTOBJs without locking
628 * <b>Sample Usage:</b>
630 * struct sample_struct_nolock_container {
631 * ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(struct sample_struct);
635 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) \
636 ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,1,ASTOBJ_DEFAULT_BUCKETS)
639 /*! \brief Create a container for ASTOBJs (with locking support).
641 * \param type The type of objects the container will hold.
643 * This macro is used to create a container for ASTOBJs with locking support.
645 * <b>Sample Usage:</b>
647 * struct sample_struct_container {
648 * ASTOBJ_CONTAINER_COMPONENTS(struct sample_struct);
652 #define ASTOBJ_CONTAINER_COMPONENTS(type) \
654 ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type)
656 /*! \brief Initialize a container.
658 * \param container A pointer to the container to initialize.
660 * This macro initializes a container. It should only be used on containers
661 * that support locking.
663 * <b>Sample Usage:</b>
665 * struct sample_struct_container {
666 * ASTOBJ_CONTAINER_COMPONENTS(struct sample_struct);
671 * ASTOBJ_CONTAINER_INIT(&container);
675 #define ASTOBJ_CONTAINER_INIT(container) \
676 ASTOBJ_CONTAINER_INIT_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
678 /*! \brief Destroy a container.
680 * \param container A pointer to the container to destory.
682 * This macro frees up resources used by a container. It does not operate on
683 * the objects in the container. To unlink the objects from the container use
684 * #ASTOBJ_CONTAINER_DESTROYALL().
686 * \note This macro should only be used on containers with locking support.
688 #define ASTOBJ_CONTAINER_DESTROY(container) \
689 ASTOBJ_CONTAINER_DESTROY_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
691 /*! \brief Add an object to a container.
693 * \param container A pointer to the container to operate on.
694 * \param newobj A pointer to the object to be added.
696 * Currently this macro adds an object to the head of a container. One day it
697 * should add an object in alphabetical order.
699 #define ASTOBJ_CONTAINER_LINK(container,newobj) \
700 ASTOBJ_CONTAINER_LINK_FULL(container,newobj,(newobj)->name,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
702 /*! \brief Mark all the objects in a container.
703 * \param container A pointer to the container to operate on.
705 #define ASTOBJ_CONTAINER_MARKALL(container) \
706 ASTOBJ_CONTAINER_TRAVERSE(container, 1, ASTOBJ_MARK(iterator))
708 /*! \brief Unmark all the objects in a container.
709 * \param container A pointer to the container to operate on.
711 #define ASTOBJ_CONTAINER_UNMARKALL(container) \
712 ASTOBJ_CONTAINER_TRAVERSE(container, 1, ASTOBJ_UNMARK(iterator))
714 /*! \brief Dump information about an object into a string.
716 * \param s A pointer to the string buffer to use.
717 * \param slen The length of s.
718 * \param obj A pointer to the object to dump.
720 * This macro dumps a text representation of the name, objectflags, and
721 * refcount fields of an object to the specfied string buffer.
723 #define ASTOBJ_DUMP(s,slen,obj) \
724 snprintf((s),(slen),"name: %s\nobjflags: %d\nrefcount: %d\n\n", (obj)->name, (obj)->objflags, (obj)->refcount);
726 /*! \brief Dump information about all the objects in a container to a file descriptor.
728 * \param fd The file descriptor to write to.
729 * \param s A string buffer, same as #ASTOBJ_DUMP().
730 * \param slen The length of s, same as #ASTOBJ_DUMP().
731 * \param container A pointer to the container to dump.
733 * This macro dumps a text representation of the name, objectflags, and
734 * refcount fields of all the objects in a container to the specified file
737 #define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container) \
738 ASTOBJ_CONTAINER_TRAVERSE(container, 1, do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, s); } while(0))
740 #if defined(__cplusplus) || defined(c_plusplus)