dfdb55b644e5044289d8aa2a52f15ef5fff6caa7
[asterisk/asterisk.git] / include / asterisk / astobj.h
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*
20  * Object Model for Asterisk
21  */
22
23 #ifndef _ASTERISK_ASTOBJ_H
24 #define _ASTERISK_ASTOBJ_H
25
26 #include "asterisk/lock.h"
27
28 /*! \file
29  * \brief A set of macros implementing objects and containers.
30  * Macros are used for maximum performance, to support multiple inheritance,
31  * and to be easily integrated into existing structures without additional
32  * malloc calls, etc.
33  *
34  * These macros expect to operate on two different object types, ASTOBJs and
35  * ASTOBJ_CONTAINERs.  These are not actual types, as any struct can be
36  * converted into an ASTOBJ compatible object or container using the supplied
37  * macros.
38  *
39  * <b>Sample Usage:</b>
40  * \code
41  * struct sample_object {
42  *    ASTOBJ_COMPONENTS(struct sample_object);
43  * };
44  *
45  * struct sample_container {
46  *    ASTOBJ_CONTAINER_COMPONENTS(struct sample_object);
47  * } super_container;
48  *
49  * void sample_object_destroy(struct sample_object *obj)
50  * {
51  *    free(obj);
52  * }
53  *
54  * int init_stuff()
55  * {
56  *    struct sample_object *obj1;
57  *    struct sample_object *found_obj;
58  *
59  *    obj1 = malloc(sizeof(struct sample_object));
60  *
61  *    ASTOBJ_CONTAINER_INIT(&super_container);
62  *
63  *    ASTOBJ_INIT(obj1);
64  *    ASTOBJ_WRLOCK(obj1);
65  *    ast_copy_string(obj1->name, "obj1", sizeof(obj1->name));
66  *    ASTOBJ_UNLOCK(obj1);
67  *
68  *    ASTOBJ_CONTAINER_LINK(&super_container, obj1);
69  *
70  *    found_obj = ASTOBJ_CONTAINER_FIND(&super_container, "obj1");
71  *
72  *    if(found_obj) {
73  *       printf("Found object: %s", found_obj->name); 
74  *       ASTOBJ_UNREF(found_obj,sample_object_destroy);
75  *    }
76  *
77  *    ASTOBJ_CONTAINER_DESTROYALL(&super_container,sample_object_destroy);
78  *    ASTOBJ_CONTAINER_DESTROY(&super_container);
79  * 
80  *    return 0;
81  * }
82  * \endcode
83  */
84
85 #if defined(__cplusplus) || defined(c_plusplus)
86 extern "C" {
87 #endif
88
89 #define ASTOBJ_DEFAULT_NAMELEN  80
90 #define ASTOBJ_DEFAULT_BUCKETS  256
91 #define ASTOBJ_DEFAULT_HASH             ast_strhash
92
93 #define ASTOBJ_FLAG_MARKED      (1 << 0)                /* Object has been marked for future operation */
94
95 /* C++ is simply a syntactic crutch for those who cannot think for themselves
96    in an object oriented way. */
97
98 /*! \brief Lock an ASTOBJ for reading.
99  */
100 #define ASTOBJ_RDLOCK(object) ast_mutex_lock(&(object)->_lock)
101
102 /*! \brief Lock an ASTOBJ for writing.
103  */
104 #define ASTOBJ_WRLOCK(object) ast_mutex_lock(&(object)->_lock)
105
106 /*! \brief Unlock a locked object. */
107 #define ASTOBJ_UNLOCK(object) ast_mutex_unlock(&(object)->_lock)
108
109 #ifdef ASTOBJ_CONTAINER_HASHMODEL 
110 #define __ASTOBJ_HASH(type,hashes) \
111         type *next[hashes] 
112 #else 
113 #define __ASTOBJ_HASH(type,hashes) \
114         type *next[1] 
115 #endif  
116
117 /*! \brief Add ASTOBJ components to a struct (without locking support).
118  *
119  * \param type The datatype of the object.
120  * \param namelen The length to make the name char array.
121  * \param hashes The number of containers the object can be present in.
122  *
123  * This macro adds components to a struct to make it an ASTOBJ.  This macro
124  * differs from ASTOBJ_COMPONENTS_FULL in that it does not create a mutex for
125  * locking.
126  *
127  * <b>Sample Usage:</b>
128  * \code
129  * struct sample_struct {
130  *    ASTOBJ_COMPONENTS_NOLOCK_FULL(struct sample_struct,1,1);
131  * };
132  * \endcode
133  */
134 #define ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes) \
135         char name[namelen]; \
136         unsigned int refcount; \
137         unsigned int objflags; \
138         __ASTOBJ_HASH(type,hashes)
139         
140 /*! \brief Add ASTOBJ components to a struct (without locking support).
141  *
142  * \param type The datatype of the object.
143  *
144  * This macro works like #ASTOBJ_COMPONENTS_NOLOCK_FULL() except it only accepts a
145  * type and uses default values for namelen and hashes.
146  * 
147  * <b>Sample Usage:</b>
148  * \code
149  * struct sample_struct_componets {
150  *    ASTOBJ_COMPONENTS_NOLOCK(struct sample_struct);
151  * };
152  * \endcode
153  */
154 #define ASTOBJ_COMPONENTS_NOLOCK(type) \
155         ASTOBJ_COMPONENTS_NOLOCK_FULL(type,ASTOBJ_DEFAULT_NAMELEN,1)
156
157 /*! \brief Add ASTOBJ components to a struct (with locking support).
158  *
159  * \param type The datatype of the object.
160  *
161  * This macro works like #ASTOBJ_COMPONENTS_NOLOCK() except it includes locking
162  * support.
163  *
164  * <b>Sample Usage:</b>
165  * \code
166  * struct sample_struct {
167  *    ASTOBJ_COMPONENTS(struct sample_struct);
168  * };
169  * \endcode
170  */
171 #define ASTOBJ_COMPONENTS(type) \
172         ASTOBJ_COMPONENTS_NOLOCK(type); \
173         ast_mutex_t _lock; 
174         
175 /*! \brief Add ASTOBJ components to a struct (with locking support).
176  *
177  * \param type The datatype of the object.
178  * \param namelen The length to make the name char array.
179  * \param hashes The number of containers the object can be present in.
180  *
181  * This macro adds components to a struct to make it an ASTOBJ and includes
182  * support for locking.
183  *
184  * <b>Sample Usage:</b>
185  * \code
186  * struct sample_struct {
187  *    ASTOBJ_COMPONENTS_FULL(struct sample_struct,1,1);
188  * };
189  * \endcode
190  */
191 #define ASTOBJ_COMPONENTS_FULL(type,namelen,hashes) \
192         ASTOBJ_COMPONENTS_NOLOCK_FULL(type,namelen,hashes); \
193         ast_mutex_t _lock; 
194
195 /*! \brief Increment an object reference count.
196  * \param object A pointer to the object to operate on.
197  * \return The object.
198  */
199 #define ASTOBJ_REF(object) \
200         ({ \
201                 ASTOBJ_WRLOCK(object); \
202                 (object)->refcount++; \
203                 ASTOBJ_UNLOCK(object); \
204                 (object); \
205         })
206         
207 /*! \brief Decrement the reference count on an object.
208  *
209  * \param object A pointer the object to operate on.
210  * \param destructor The destructor to call if the object is no longer referenced.  It will be passed the pointer as an argument.
211  *
212  * This macro unreferences an object and calls the specfied destructor if the
213  * object is no longer referenced.  The destructor should free the object if it
214  * was dynamically allocated.
215  */
216 #define ASTOBJ_UNREF(object,destructor) \
217         do { \
218                 int newcount = 0; \
219                 ASTOBJ_WRLOCK(object); \
220                 if (__builtin_expect((object)->refcount > 0, 1)) \
221                         newcount = --((object)->refcount); \
222                 else \
223                         ast_log(AST_LOG_WARNING, "Unreferencing unreferenced (object)!\n"); \
224                 ASTOBJ_UNLOCK(object); \
225                 if (newcount == 0) { \
226                         ast_mutex_destroy(&(object)->_lock); \
227                         destructor((object)); \
228                 } \
229                 (object) = NULL; \
230         } while(0)
231
232 /*! \brief Mark an ASTOBJ by adding the #ASTOBJ_FLAG_MARKED flag to its objflags mask. 
233  * \param object A pointer to the object to operate on.
234  *
235  * This macro "marks" an object.  Marked objects can later be unlinked from a container using
236  * #ASTOBJ_CONTAINER_PRUNE_MARKED().
237  * 
238  */
239 #define ASTOBJ_MARK(object) \
240         do { \
241                 ASTOBJ_WRLOCK(object); \
242                 (object)->objflags |= ASTOBJ_FLAG_MARKED; \
243                 ASTOBJ_UNLOCK(object); \
244         } while(0)
245         
246 /*! \brief Unmark an ASTOBJ by subtracting the #ASTOBJ_FLAG_MARKED flag from its objflags mask.
247  * \param object A pointer to the object to operate on.
248  */
249 #define ASTOBJ_UNMARK(object) \
250         do { \
251                 ASTOBJ_WRLOCK(object); \
252                 (object)->objflags &= ~ASTOBJ_FLAG_MARKED; \
253                 ASTOBJ_UNLOCK(object); \
254         } while(0)
255
256 /*! \brief Initialize an object.
257  * \param object A pointer to the object to operate on.
258  *
259  * \note This should only be used on objects that support locking (objects
260  * created with #ASTOBJ_COMPONENTS() or #ASTOBJ_COMPONENTS_FULL())
261  */
262 #define ASTOBJ_INIT(object) \
263         do { \
264                 ast_mutex_init(&(object)->_lock); \
265                 object->name[0] = '\0'; \
266                 object->refcount = 1; \
267         } while(0)
268
269 /* Containers for objects -- current implementation is linked lists, but
270    should be able to be converted to hashes relatively easily */
271
272 /*! \brief Lock an ASTOBJ_CONTAINER for reading.
273  */
274 #define ASTOBJ_CONTAINER_RDLOCK(container) ast_mutex_lock(&(container)->_lock)
275
276 /*! \brief Lock an ASTOBJ_CONTAINER for writing. 
277  */
278 #define ASTOBJ_CONTAINER_WRLOCK(container) ast_mutex_lock(&(container)->_lock)
279
280 /*! \brief Unlock an ASTOBJ_CONTAINER. */
281 #define ASTOBJ_CONTAINER_UNLOCK(container) ast_mutex_unlock(&(container)->_lock)
282
283 #ifdef ASTOBJ_CONTAINER_HASHMODEL
284 #error "Hash model for object containers not yet implemented!"
285 #else
286 /* Linked lists */
287
288 /*! \brief Create a container for ASTOBJs (without locking support).
289  *
290  * \param type The type of objects the container will hold.
291  * \param hashes Currently unused.
292  * \param buckets Currently unused.
293  *
294  * This macro is used to create a container for ASTOBJs without locking
295  * support.
296  *
297  * <b>Sample Usage:</b>
298  * \code
299  * struct sample_struct_nolock_container {
300  *    ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(struct sample_struct,1,1);
301  * };
302  * \endcode
303  */
304 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,hashes,buckets) \
305         type *head
306
307 /*! \brief Initialize a container.
308  *
309  * \param container A pointer to the container to initialize.
310  * \param hashes Currently unused.
311  * \param buckets Currently unused.
312  *
313  * This macro initializes a container.  It should only be used on containers
314  * that support locking.
315  * 
316  * <b>Sample Usage:</b>
317  * \code
318  * struct sample_struct_container {
319  *    ASTOBJ_CONTAINER_COMPONENTS_FULL(struct sample_struct,1,1);
320  * } container;
321  *
322  * int func()
323  * {
324  *    ASTOBJ_CONTAINER_INIT_FULL(&container,1,1);
325  * }
326  * \endcode
327  */
328 #define ASTOBJ_CONTAINER_INIT_FULL(container,hashes,buckets) \
329         do { \
330                 ast_mutex_init(&(container)->_lock); \
331         } while(0)
332         
333 /*! \brief Destroy a container.
334  *
335  * \param container A pointer to the container to destroy.
336  * \param hashes Currently unused.
337  * \param buckets Currently unused.
338  *
339  * This macro frees up resources used by a container.  It does not operate on
340  * the objects in the container.  To unlink the objects from the container use
341  * #ASTOBJ_CONTAINER_DESTROYALL().
342  *
343  * \note This macro should only be used on containers with locking support.
344  */
345 #define ASTOBJ_CONTAINER_DESTROY_FULL(container,hashes,buckets) \
346         do { \
347                 ast_mutex_destroy(&(container)->_lock); \
348         } while(0)
349
350 /*! \brief Iterate through the objects in a container.
351  *
352  * \param container A pointer to the container to traverse.
353  * \param continue A condition to allow the traversal to continue.
354  * \param eval A statement to evaluate in the iteration loop.
355  *
356  * This is macro is a little complicated, but it may help to think of it as a
357  * loop.  Basically it iterates through the specfied containter as long as the
358  * condition is met.  Two variables, iterator and next, are provided for use in
359  * your \p eval statement.  See the sample code for an example.
360  *
361  * <b>Sample Usage:</b>
362  * \code
363  * ASTOBJ_CONTAINER_TRAVERSE(&sample_container,1, {
364  *    ASTOBJ_RDLOCK(iterator);
365  *    printf("Currently iterating over '%s'\n", iterator->name);
366  *    ASTOBJ_UNLOCK(iterator);
367  * } );
368  * \endcode
369  *
370  * \code
371  * ASTOBJ_CONTAINER_TRAVERSE(&sample_container,1, sample_func(iterator));
372  * \endcode
373  */
374 #define ASTOBJ_CONTAINER_TRAVERSE(container,continue,eval) \
375         do { \
376                 typeof((container)->head) iterator; \
377                 typeof((container)->head) next; \
378                 ASTOBJ_CONTAINER_RDLOCK(container); \
379                 next = (container)->head; \
380                 while((continue) && (iterator = next)) { \
381                         next = iterator->next[0]; \
382                         eval; \
383                 } \
384                 ASTOBJ_CONTAINER_UNLOCK(container); \
385         } while(0)
386
387 /*! \brief Find an object in a container.
388  *
389  * \param container A pointer to the container to search.
390  * \param namestr The name to search for.
391  *
392  * Use this function to find an object with the specfied name in a container.
393  *
394  * \note When the returned object is no longer in use, #ASTOBJ_UNREF() should
395  * be used to free the additional reference created by this macro.
396  *
397  * \return A new reference to the object located or NULL if nothing is found.
398  */
399 #define ASTOBJ_CONTAINER_FIND(container,namestr) \
400         ({ \
401                 typeof((container)->head) found = NULL; \
402                 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
403                         if (!(strcasecmp(iterator->name, (namestr)))) \
404                                 found = ASTOBJ_REF(iterator); \
405                 } while (0)); \
406                 found; \
407         })
408
409 /*! \brief Find an object in a container.
410  * 
411  * \param container A pointer to the container to search.
412  * \param data The data to search for.
413  * \param field The field/member of the container's objects to search.
414  * \param hashfunc The hash function to use, currently not implemented.
415  * \param hashoffset The hash offset to use, currently not implemented.
416  * \param comparefunc The function used to compare the field and data values.
417  *
418  * This macro iterates through a container passing the specified field and data
419  * elements to the specified comparefunc.  The function should return 0 when a match is found.
420  * 
421  * \note When the returned object is no longer in use, #ASTOBJ_UNREF() should
422  * be used to free the additional reference created by this macro.
423  *
424  * \return A pointer to the object located or NULL if nothing is found.
425  */
426 #define ASTOBJ_CONTAINER_FIND_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
427         ({ \
428                 typeof((container)->head) found = NULL; \
429                 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
430                         ASTOBJ_RDLOCK(iterator); \
431                         if (!(comparefunc(iterator->field, (data)))) { \
432                                 found = ASTOBJ_REF(iterator); \
433                         } \
434                         ASTOBJ_UNLOCK(iterator); \
435                 } while (0)); \
436                 found; \
437         })
438
439 /*! \brief Empty a container.
440  *
441  * \param container A pointer to the container to operate on.
442  * \param destructor A destructor function to call on each object.
443  *
444  * This macro loops through a container removing all the items from it using
445  * #ASTOBJ_UNREF().  This does not destroy the container itself, use
446  * #ASTOBJ_CONTAINER_DESTROY() for that.
447  *
448  * \note If any object in the container is only referenced by the container,
449  * the destructor will be called for that object once it has been removed.
450  */
451 #define ASTOBJ_CONTAINER_DESTROYALL(container,destructor) \
452         do { \
453                 typeof((container)->head) iterator; \
454                 ASTOBJ_CONTAINER_WRLOCK(container); \
455                 while((iterator = (container)->head)) { \
456                         (container)->head = (iterator)->next[0]; \
457                         ASTOBJ_UNREF(iterator,destructor); \
458                 } \
459                 ASTOBJ_CONTAINER_UNLOCK(container); \
460         } while(0)
461
462 /*! \brief Remove an object from a container.
463  *
464  * \param container A pointer to the container to operate on.
465  * \param obj A pointer to the object to remove.
466  *
467  * This macro iterates through a container and removes the specfied object if
468  * it exists in the container.
469  *
470  * \note This macro does not destroy any objects, it simply unlinks
471  * them from the list.  No destructors are called.
472  *
473  * \return The container's reference to the removed object or NULL if no
474  * matching object was found.
475  */
476 #define ASTOBJ_CONTAINER_UNLINK(container,obj) \
477         ({ \
478                 typeof((container)->head) found = NULL; \
479                 typeof((container)->head) prev = NULL; \
480                 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
481                         if (iterator == obj) { \
482                                 found = iterator; \
483                                 found->next[0] = NULL; \
484                                 ASTOBJ_CONTAINER_WRLOCK(container); \
485                                 if (prev) \
486                                         prev->next[0] = next; \
487                                 else \
488                                         (container)->head = next; \
489                                 ASTOBJ_CONTAINER_UNLOCK(container); \
490                         } \
491                         prev = iterator; \
492                 } while (0)); \
493                 found; \
494         })
495
496 /*! \brief Find and remove an object from a container.
497  * 
498  * \param container A pointer to the container to operate on.
499  * \param namestr The name of the object to remove.
500  *
501  * This macro iterates through a container and removes the first object with
502  * the specfied name from the container.
503  *
504  * \note This macro does not destroy any objects, it simply unlinks
505  * them.  No destructors are called.
506  *
507  * \return The container's reference to the removed object or NULL if no
508  * matching object was found.
509  */
510 #define ASTOBJ_CONTAINER_FIND_UNLINK(container,namestr) \
511         ({ \
512                 typeof((container)->head) found = NULL; \
513                 typeof((container)->head) prev = NULL; \
514                 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
515                         if (!(strcasecmp(iterator->name, (namestr)))) { \
516                                 found = iterator; \
517                                 found->next[0] = NULL; \
518                                 ASTOBJ_CONTAINER_WRLOCK(container); \
519                                 if (prev) \
520                                         prev->next[0] = next; \
521                                 else \
522                                         (container)->head = next; \
523                                 ASTOBJ_CONTAINER_UNLOCK(container); \
524                         } \
525                         prev = iterator; \
526                 } while (0)); \
527                 found; \
528         })
529
530 /*! \brief Find and remove an object in a container.
531  * 
532  * \param container A pointer to the container to search.
533  * \param data The data to search for.
534  * \param field The field/member of the container's objects to search.
535  * \param hashfunc The hash function to use, currently not implemented.
536  * \param hashoffset The hash offset to use, currently not implemented.
537  * \param comparefunc The function used to compare the field and data values.
538  *
539  * This macro iterates through a container passing the specified field and data
540  * elements to the specified comparefunc.  The function should return 0 when a match is found.
541  * If a match is found it is removed from the list. 
542  *
543  * \note This macro does not destroy any objects, it simply unlinks
544  * them.  No destructors are called.
545  *
546  * \return The container's reference to the removed object or NULL if no match
547  * was found.
548  */
549 #define ASTOBJ_CONTAINER_FIND_UNLINK_FULL(container,data,field,hashfunc,hashoffset,comparefunc) \
550         ({ \
551                 typeof((container)->head) found = NULL; \
552                 typeof((container)->head) prev = NULL; \
553                 ASTOBJ_CONTAINER_TRAVERSE(container, !found, do { \
554                         ASTOBJ_RDLOCK(iterator); \
555                         if (!(comparefunc(iterator->field, (data)))) { \
556                                 found = iterator; \
557                                 found->next[0] = NULL; \
558                                 ASTOBJ_CONTAINER_WRLOCK(container); \
559                                 if (prev) \
560                                         prev->next[0] = next; \
561                                 else \
562                                         (container)->head = next; \
563                                 ASTOBJ_CONTAINER_UNLOCK(container); \
564                         } \
565                         ASTOBJ_UNLOCK(iterator); \
566                         prev = iterator; \
567                 } while (0)); \
568                 found; \
569         })
570
571 /*! \brief Add an object to the end of a container.
572  *
573  * \param container A pointer to the container to operate on.
574  * \param newobj A pointer to the object to be added.
575  *
576  * This macro adds an object to the end of a container.
577  */
578 #define ASTOBJ_CONTAINER_LINK_END(container,newobj) \
579         do { \
580                 typeof((container)->head) iterator; \
581                 typeof((container)->head) next; \
582                 typeof((container)->head) prev; \
583                 ASTOBJ_CONTAINER_RDLOCK(container); \
584                 prev = NULL; \
585                 next = (container)->head; \
586                 while((iterator = next)) { \
587                         next = iterator->next[0]; \
588                         prev = iterator; \
589                 } \
590                 if(prev) { \
591                         ASTOBJ_CONTAINER_WRLOCK((container)); \
592                         prev->next[0] = ASTOBJ_REF(newobj); \
593                         (newobj)->next[0] = NULL; \
594                         ASTOBJ_CONTAINER_UNLOCK((container)); \
595                 } else { \
596                         ASTOBJ_CONTAINER_LINK_START((container),(newobj)); \
597                 } \
598                 ASTOBJ_CONTAINER_UNLOCK((container)); \
599         } while(0)
600
601 /*! \brief Add an object to the front of a container.
602  *
603  * \param container A pointer to the container to operate on.
604  * \param newobj A pointer to the object to be added.
605  *
606  * This macro adds an object to the start of a container.
607  */
608 #define ASTOBJ_CONTAINER_LINK_START(container,newobj) \
609         do { \
610                 ASTOBJ_CONTAINER_WRLOCK(container); \
611                 (newobj)->next[0] = (container)->head; \
612                 (container)->head = ASTOBJ_REF(newobj); \
613                 ASTOBJ_CONTAINER_UNLOCK(container); \
614         } while(0)
615
616 /*! \brief Remove an object from the front of a container.
617  *
618  * \param container A pointer to the container to operate on.
619  *
620  * This macro removes the first object in a container.
621  *
622  * \note This macro does not destroy any objects, it simply unlinks
623  * them from the list.  No destructors are called.
624  *
625  * \return The container's reference to the removed object or NULL if no
626  * matching object was found.
627  */
628 #define ASTOBJ_CONTAINER_UNLINK_START(container) \
629         ({ \
630                 typeof((container)->head) found = NULL; \
631                 ASTOBJ_CONTAINER_WRLOCK(container); \
632                 if((container)->head) { \
633                         found = (container)->head; \
634                         (container)->head = (container)->head->next[0]; \
635                         found->next[0] = NULL; \
636                 } \
637                 ASTOBJ_CONTAINER_UNLOCK(container); \
638                 found; \
639         })
640
641 /*! \brief Prune marked objects from a container.
642  *
643  * \param container A pointer to the container to prune.
644  * \param destructor A destructor function to call on each marked object.
645  * 
646  * This macro iterates through the specfied container and prunes any marked
647  * objects executing the specfied destructor if necessary.
648  */
649 #define ASTOBJ_CONTAINER_PRUNE_MARKED(container,destructor) \
650         do { \
651                 typeof((container)->head) prev = NULL; \
652                 ASTOBJ_CONTAINER_TRAVERSE(container, 1, do { \
653                         ASTOBJ_RDLOCK(iterator); \
654                         if (iterator->objflags & ASTOBJ_FLAG_MARKED) { \
655                                 ASTOBJ_CONTAINER_WRLOCK(container); \
656                                 if (prev) \
657                                         prev->next[0] = next; \
658                                 else \
659                                         (container)->head = next; \
660                                 ASTOBJ_CONTAINER_UNLOCK(container); \
661                                 ASTOBJ_UNLOCK(iterator); \
662                                 ASTOBJ_UNREF(iterator,destructor); \
663                                 continue; \
664                         } \
665                         ASTOBJ_UNLOCK(iterator); \
666                         prev = iterator; \
667                 } while (0)); \
668         } while(0)
669
670 /*! \brief Add an object to a container.
671  *
672  * \param container A pointer to the container to operate on.
673  * \param newobj A pointer to the object to be added.
674  * \param data Currently unused.
675  * \param field Currently unused.
676  * \param hashfunc Currently unused.
677  * \param hashoffset Currently unused.
678  * \param comparefunc Currently unused.
679  *
680  * Currently this function adds an object to the head of the list.  One day it
681  * will support adding objects atthe position specified using the various
682  * options this macro offers.
683  */
684 #define ASTOBJ_CONTAINER_LINK_FULL(container,newobj,data,field,hashfunc,hashoffset,comparefunc) \
685         do { \
686                 ASTOBJ_CONTAINER_WRLOCK(container); \
687                 (newobj)->next[0] = (container)->head; \
688                 (container)->head = ASTOBJ_REF(newobj); \
689                 ASTOBJ_CONTAINER_UNLOCK(container); \
690         } while(0)
691
692 #endif /* List model */
693
694 /* Common to hash and linked list models */
695
696 /*! \brief Create a container for ASTOBJs (without locking support).
697  *
698  * \param type The type of objects the container will hold.
699  *
700  * This macro is used to create a container for ASTOBJs without locking
701  * support.
702  *
703  * <b>Sample Usage:</b>
704  * \code
705  * struct sample_struct_nolock_container {
706  *    ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(struct sample_struct);
707  * };
708  * \endcode
709  */
710 #define ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type) \
711         ASTOBJ_CONTAINER_COMPONENTS_NOLOCK_FULL(type,1,ASTOBJ_DEFAULT_BUCKETS)
712
713
714 /*! \brief Create a container for ASTOBJs (with locking support).
715  *
716  * \param type The type of objects the container will hold.
717  *
718  * This macro is used to create a container for ASTOBJs with locking support.
719  *
720  * <b>Sample Usage:</b>
721  * \code
722  * struct sample_struct_container {
723  *    ASTOBJ_CONTAINER_COMPONENTS(struct sample_struct);
724  * };
725  * \endcode
726  */
727 #define ASTOBJ_CONTAINER_COMPONENTS(type) \
728         ast_mutex_t _lock; \
729         ASTOBJ_CONTAINER_COMPONENTS_NOLOCK(type)
730
731 /*! \brief Initialize a container.
732  *
733  * \param container A pointer to the container to initialize.
734  *
735  * This macro initializes a container.  It should only be used on containers
736  * that support locking.
737  * 
738  * <b>Sample Usage:</b>
739  * \code
740  * struct sample_struct_container {
741  *    ASTOBJ_CONTAINER_COMPONENTS(struct sample_struct);
742  * } container;
743  *
744  * int func()
745  * {
746  *    ASTOBJ_CONTAINER_INIT(&container);
747  * }
748  * \endcode
749  */
750 #define ASTOBJ_CONTAINER_INIT(container) \
751         ASTOBJ_CONTAINER_INIT_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
752
753 /*! \brief Destroy a container.
754  *
755  * \param container A pointer to the container to destory.
756  *
757  * This macro frees up resources used by a container.  It does not operate on
758  * the objects in the container.  To unlink the objects from the container use
759  * #ASTOBJ_CONTAINER_DESTROYALL().
760  *
761  * \note This macro should only be used on containers with locking support.
762  */
763 #define ASTOBJ_CONTAINER_DESTROY(container) \
764         ASTOBJ_CONTAINER_DESTROY_FULL(container,1,ASTOBJ_DEFAULT_BUCKETS)
765
766 /*! \brief Add an object to a container.
767  *
768  * \param container A pointer to the container to operate on.
769  * \param newobj A pointer to the object to be added.
770  *
771  * Currently this macro adds an object to the head of a container.  One day it
772  * should add an object in alphabetical order.
773  */
774 #define ASTOBJ_CONTAINER_LINK(container,newobj) \
775         ASTOBJ_CONTAINER_LINK_FULL(container,newobj,(newobj)->name,name,ASTOBJ_DEFAULT_HASH,0,strcasecmp)
776
777 /*! \brief Mark all the objects in a container.
778  * \param container A pointer to the container to operate on.
779  */
780 #define ASTOBJ_CONTAINER_MARKALL(container) \
781         ASTOBJ_CONTAINER_TRAVERSE(container, 1, ASTOBJ_MARK(iterator))
782
783 /*! \brief Unmark all the objects in a container.
784  * \param container A pointer to the container to operate on.
785  */
786 #define ASTOBJ_CONTAINER_UNMARKALL(container) \
787         ASTOBJ_CONTAINER_TRAVERSE(container, 1, ASTOBJ_UNMARK(iterator))
788
789 /*! \brief Dump information about an object into a string.
790  *
791  * \param s A pointer to the string buffer to use.
792  * \param slen The length of s.
793  * \param obj A pointer to the object to dump.
794  *
795  * This macro dumps a text representation of the name, objectflags, and
796  * refcount fields of an object to the specfied string buffer.
797  */
798 #define ASTOBJ_DUMP(s,slen,obj) \
799         snprintf((s),(slen),"name: %s\nobjflags: %d\nrefcount: %d\n\n", (obj)->name, (obj)->objflags, (obj)->refcount);
800
801 /*! \brief Dump information about all the objects in a container to a file descriptor.
802  *
803  * \param fd The file descriptor to write to.
804  * \param s A string buffer, same as #ASTOBJ_DUMP().
805  * \param slen The length of s, same as #ASTOBJ_DUMP().
806  * \param container A pointer to the container to dump.
807  *
808  * This macro dumps a text representation of the name, objectflags, and
809  * refcount fields of all the objects in a container to the specified file
810  * descriptor.
811  */
812 #define ASTOBJ_CONTAINER_DUMP(fd,s,slen,container) \
813         ASTOBJ_CONTAINER_TRAVERSE(container, 1, do { ASTOBJ_DUMP(s,slen,iterator); ast_cli(fd, "%s", s); } while(0))
814
815 #if defined(__cplusplus) || defined(c_plusplus)
816 }
817 #endif
818
819 #endif /* _ASTERISK_ASTOBJ_H */