2 * astobj2 - replacement containers for asterisk data structures.
4 * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
19 * \brief Functions implementing astobj2 objects.
21 * \author Richard Mudgett <rmudgett@digium.com>
25 <support_level>core</support_level>
30 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32 #include "asterisk/_private.h"
33 #include "asterisk/astobj2.h"
34 #include "asterisk/dlinkedlists.h"
35 #include "asterisk/utils.h"
36 #include "asterisk/cli.h"
37 #define REF_FILE "/tmp/refs"
39 #if defined(TEST_FRAMEWORK)
40 /* We are building with the test framework enabled so enable AO2 debug tests as well. */
42 #endif /* defined(TEST_FRAMEWORK) */
45 * astobj2 objects are always preceded by this data structure,
46 * which contains a reference counter,
47 * option flags and a pointer to a destructor.
48 * The refcount is used to decide when it is time to
49 * invoke the destructor.
50 * The magic number is used for consistency check.
54 ao2_destructor_fn destructor_fn;
55 /*! User data size for stats */
57 /*! The ao2 object option flags */
59 /*! magic number. This is used to verify that a pointer passed in is a
64 #define AO2_MAGIC 0xa570b123
67 * What an astobj2 object looks like: fixed-size private data
68 * followed by variable-size user data.
71 struct __priv_data priv_data;
75 struct ao2_lock_priv {
79 /* AstObj2 with recursive lock. */
81 struct ao2_lock_priv mutex;
82 struct __priv_data priv_data;
86 struct ao2_rwlock_priv {
88 /*! Count of the number of threads holding a lock on this object. -1 if it is the write lock. */
92 /* AstObj2 with RW lock. */
93 struct astobj2_rwlock {
94 struct ao2_rwlock_priv rwlock;
95 struct __priv_data priv_data;
99 #if defined(AST_DEVMODE)
100 #define AO2_DEVMODE_STAT(stat) stat
102 #define AO2_DEVMODE_STAT(stat)
103 #endif /* defined(AST_DEVMODE) */
107 volatile int total_objects;
108 volatile int total_mem;
109 volatile int total_containers;
110 volatile int total_refs;
111 volatile int total_locked;
114 static struct ao2_stats ao2;
117 #ifndef HAVE_BKTR /* backtrace support */
120 #include <execinfo.h> /* for backtrace */
129 c = backtrace(addresses, N1);
130 strings = ast_bt_get_symbols(addresses,c);
131 ast_verbose("backtrace returned: %d\n", c);
132 for(i = 0; i < c; i++) {
133 ast_verbose("%d: %p %s\n", i, addresses[i], strings[i]);
139 #define INTERNAL_OBJ_MUTEX(user_data) \
140 ((struct astobj2_lock *) (((char *) (user_data)) - sizeof(struct astobj2_lock)))
142 #define INTERNAL_OBJ_RWLOCK(user_data) \
143 ((struct astobj2_rwlock *) (((char *) (user_data)) - sizeof(struct astobj2_rwlock)))
146 * \brief convert from a pointer _p to a user-defined object
148 * \return the pointer to the astobj2 structure
150 static inline struct astobj2 *INTERNAL_OBJ(void *user_data)
155 ast_log(LOG_ERROR, "user_data is NULL\n");
159 p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
160 if (AO2_MAGIC != p->priv_data.magic) {
161 if (p->priv_data.magic) {
162 ast_log(LOG_ERROR, "bad magic number 0x%x for object %p\n",
163 p->priv_data.magic, user_data);
166 "bad magic number for object %p. Object is likely destroyed.\n",
176 * \brief convert from a pointer _p to an astobj2 object
178 * \return the pointer to the user-defined portion.
180 #define EXTERNAL_OBJ(_p) ((_p) == NULL ? NULL : (_p)->user_data)
182 int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
184 struct astobj2 *obj = INTERNAL_OBJ(user_data);
185 struct astobj2_lock *obj_mutex;
186 struct astobj2_rwlock *obj_rwlock;
194 switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
195 case AO2_ALLOC_OPT_LOCK_MUTEX:
196 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
197 res = __ast_pthread_mutex_lock(file, line, func, var, &obj_mutex->mutex.lock);
200 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
204 case AO2_ALLOC_OPT_LOCK_RWLOCK:
205 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
207 case AO2_LOCK_REQ_MUTEX:
208 case AO2_LOCK_REQ_WRLOCK:
209 res = __ast_rwlock_wrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
211 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1);
213 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
217 case AO2_LOCK_REQ_RDLOCK:
218 res = __ast_rwlock_rdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
220 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1);
222 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
228 case AO2_ALLOC_OPT_LOCK_NOLOCK:
229 /* The ao2 object has no lock. */
232 ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
240 int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
242 struct astobj2 *obj = INTERNAL_OBJ(user_data);
243 struct astobj2_lock *obj_mutex;
244 struct astobj2_rwlock *obj_rwlock;
253 switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
254 case AO2_ALLOC_OPT_LOCK_MUTEX:
255 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
256 res = __ast_pthread_mutex_unlock(file, line, func, var, &obj_mutex->mutex.lock);
259 ast_atomic_fetchadd_int(&ao2.total_locked, -1);
263 case AO2_ALLOC_OPT_LOCK_RWLOCK:
264 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
266 current_value = ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1) - 1;
267 if (current_value < 0) {
268 /* It was a WRLOCK that we are unlocking. Fix the count. */
269 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -current_value);
271 res = __ast_rwlock_unlock(file, line, func, &obj_rwlock->rwlock.lock, var);
274 ast_atomic_fetchadd_int(&ao2.total_locked, -1);
278 case AO2_ALLOC_OPT_LOCK_NOLOCK:
279 /* The ao2 object has no lock. */
282 ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
290 int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
292 struct astobj2 *obj = INTERNAL_OBJ(user_data);
293 struct astobj2_lock *obj_mutex;
294 struct astobj2_rwlock *obj_rwlock;
302 switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
303 case AO2_ALLOC_OPT_LOCK_MUTEX:
304 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
305 res = __ast_pthread_mutex_trylock(file, line, func, var, &obj_mutex->mutex.lock);
308 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
312 case AO2_ALLOC_OPT_LOCK_RWLOCK:
313 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
315 case AO2_LOCK_REQ_MUTEX:
316 case AO2_LOCK_REQ_WRLOCK:
317 res = __ast_rwlock_trywrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
319 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1);
321 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
325 case AO2_LOCK_REQ_RDLOCK:
326 res = __ast_rwlock_tryrdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
328 ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1);
330 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
336 case AO2_ALLOC_OPT_LOCK_NOLOCK:
337 /* The ao2 object has no lock. */
340 ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
351 * \brief Adjust an object's lock to the requested level.
353 * \param user_data An ao2 object to adjust lock level.
354 * \param lock_how What level to adjust lock.
355 * \param keep_stronger TRUE if keep original lock level if it is stronger.
357 * \pre The ao2 object is already locked.
360 * An ao2 object with a RWLOCK will have its lock level adjusted
361 * to the specified level if it is not already there. An ao2
362 * object with a different type of lock is not affected.
364 * \return Original lock level.
366 static enum ao2_lock_req adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
368 struct astobj2 *obj = INTERNAL_OBJ(user_data);
369 struct astobj2_rwlock *obj_rwlock;
370 enum ao2_lock_req orig_lock;
372 switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
373 case AO2_ALLOC_OPT_LOCK_RWLOCK:
374 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
375 if (obj_rwlock->rwlock.num_lockers < 0) {
376 orig_lock = AO2_LOCK_REQ_WRLOCK;
378 orig_lock = AO2_LOCK_REQ_RDLOCK;
381 case AO2_LOCK_REQ_MUTEX:
382 lock_how = AO2_LOCK_REQ_WRLOCK;
384 case AO2_LOCK_REQ_WRLOCK:
385 if (lock_how != orig_lock) {
386 /* Switch from read lock to write lock. */
387 ao2_unlock(user_data);
388 ao2_wrlock(user_data);
391 case AO2_LOCK_REQ_RDLOCK:
392 if (!keep_stronger && lock_how != orig_lock) {
393 /* Switch from write lock to read lock. */
394 ao2_unlock(user_data);
395 ao2_rdlock(user_data);
401 ast_log(LOG_ERROR, "Invalid lock option on ao2 object %p\n", user_data);
403 case AO2_ALLOC_OPT_LOCK_NOLOCK:
404 case AO2_ALLOC_OPT_LOCK_MUTEX:
405 orig_lock = AO2_LOCK_REQ_MUTEX;
412 void *ao2_object_get_lockaddr(void *user_data)
414 struct astobj2 *obj = INTERNAL_OBJ(user_data);
415 struct astobj2_lock *obj_mutex;
422 switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
423 case AO2_ALLOC_OPT_LOCK_MUTEX:
424 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
425 return &obj_mutex->mutex.lock;
433 static int internal_ao2_ref(void *user_data, int delta, const char *file, int line, const char *func)
435 struct astobj2 *obj = INTERNAL_OBJ(user_data);
436 struct astobj2_lock *obj_mutex;
437 struct astobj2_rwlock *obj_rwlock;
446 /* if delta is 0, just return the refcount */
448 return obj->priv_data.ref_counter;
451 /* we modify with an atomic operation the reference counter */
452 ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
453 current_value = ret + delta;
456 ast_atomic_fetchadd_int(&ao2.total_refs, delta);
459 if (0 < current_value) {
460 /* The object still lives. */
464 /* this case must never happen */
465 if (current_value < 0) {
466 ast_log(__LOG_ERROR, file, line, func,
467 "Invalid refcount %d on ao2 object %p\n", current_value, user_data);
470 /* last reference, destroy the object */
471 if (obj->priv_data.destructor_fn != NULL) {
472 obj->priv_data.destructor_fn(user_data);
476 ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
477 ast_atomic_fetchadd_int(&ao2.total_objects, -1);
480 switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
481 case AO2_ALLOC_OPT_LOCK_MUTEX:
482 obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
483 ast_mutex_destroy(&obj_mutex->mutex.lock);
486 * For safety, zero-out the astobj2_lock header and also the
487 * first word of the user-data, which we make sure is always
490 memset(obj_mutex, '\0', sizeof(*obj_mutex) + sizeof(void *) );
493 case AO2_ALLOC_OPT_LOCK_RWLOCK:
494 obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
495 ast_rwlock_destroy(&obj_rwlock->rwlock.lock);
498 * For safety, zero-out the astobj2_rwlock header and also the
499 * first word of the user-data, which we make sure is always
502 memset(obj_rwlock, '\0', sizeof(*obj_rwlock) + sizeof(void *) );
503 ast_free(obj_rwlock);
505 case AO2_ALLOC_OPT_LOCK_NOLOCK:
507 * For safety, zero-out the astobj2 header and also the first
508 * word of the user-data, which we make sure is always
511 memset(obj, '\0', sizeof(*obj) + sizeof(void *) );
515 ast_log(__LOG_ERROR, file, line, func,
516 "Invalid lock option on ao2 object %p\n", user_data);
523 int __ao2_ref_debug(void *user_data, int delta, const char *tag, const char *file, int line, const char *func)
525 struct astobj2 *obj = INTERNAL_OBJ(user_data);
534 FILE *refo = fopen(REF_FILE, "a");
536 fprintf(refo, "%p %s%d %s:%d:%s (%s) [@%d]\n", user_data, (delta < 0 ? "" : "+"),
537 delta, file, line, func, tag, obj->priv_data.ref_counter);
541 if (obj->priv_data.ref_counter + delta == 0 && obj->priv_data.destructor_fn != NULL) { /* this isn't protected with lock; just for o/p */
542 FILE *refo = fopen(REF_FILE, "a");
544 fprintf(refo, "%p **call destructor** %s:%d:%s (%s)\n", user_data, file, line, func, tag);
548 return internal_ao2_ref(user_data, delta, file, line, func);
551 int __ao2_ref(void *user_data, int delta)
553 return internal_ao2_ref(user_data, delta, __FILE__, __LINE__, __FUNCTION__);
556 void __ao2_cleanup_debug(void *obj, const char *file, int line, const char *function)
559 __ao2_ref_debug(obj, -1, "ao2_cleanup", file, line, function);
563 void __ao2_cleanup(void *obj)
570 static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *file, int line, const char *func)
574 struct astobj2_lock *obj_mutex;
575 struct astobj2_rwlock *obj_rwlock;
577 if (data_size < sizeof(void *)) {
579 * We always alloc at least the size of a void *,
580 * for debugging purposes.
582 data_size = sizeof(void *);
585 switch (options & AO2_ALLOC_OPT_LOCK_MASK) {
586 case AO2_ALLOC_OPT_LOCK_MUTEX:
587 #if defined(__AST_DEBUG_MALLOC)
588 obj_mutex = __ast_calloc(1, sizeof(*obj_mutex) + data_size, file, line, func);
590 obj_mutex = ast_calloc(1, sizeof(*obj_mutex) + data_size);
592 if (obj_mutex == NULL) {
596 ast_mutex_init(&obj_mutex->mutex.lock);
597 obj = (struct astobj2 *) &obj_mutex->priv_data;
599 case AO2_ALLOC_OPT_LOCK_RWLOCK:
600 #if defined(__AST_DEBUG_MALLOC)
601 obj_rwlock = __ast_calloc(1, sizeof(*obj_rwlock) + data_size, file, line, func);
603 obj_rwlock = ast_calloc(1, sizeof(*obj_rwlock) + data_size);
605 if (obj_rwlock == NULL) {
609 ast_rwlock_init(&obj_rwlock->rwlock.lock);
610 obj = (struct astobj2 *) &obj_rwlock->priv_data;
612 case AO2_ALLOC_OPT_LOCK_NOLOCK:
613 #if defined(__AST_DEBUG_MALLOC)
614 obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, func);
616 obj = ast_calloc(1, sizeof(*obj) + data_size);
623 /* Invalid option value. */
624 ast_log(__LOG_DEBUG, file, line, func, "Invalid lock option requested\n");
628 /* Initialize common ao2 values. */
629 obj->priv_data.ref_counter = 1;
630 obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */
631 obj->priv_data.data_size = data_size;
632 obj->priv_data.options = options;
633 obj->priv_data.magic = AO2_MAGIC;
636 ast_atomic_fetchadd_int(&ao2.total_objects, 1);
637 ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
638 ast_atomic_fetchadd_int(&ao2.total_refs, 1);
641 /* return a pointer to the user data */
642 return EXTERNAL_OBJ(obj);
645 void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *tag,
646 const char *file, int line, const char *func, int ref_debug)
652 if ((obj = internal_ao2_alloc(data_size, destructor_fn, options, file, line, func)) == NULL) {
656 if (ref_debug && (refo = fopen(REF_FILE, "a"))) {
657 fprintf(refo, "%p =1 %s:%d:%s (%s)\n", obj, file, line, func, tag);
661 /* return a pointer to the user data */
665 void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options)
667 return internal_ao2_alloc(data_size, destructor_fn, options, __FILE__, __LINE__, __FUNCTION__);
671 void __ao2_global_obj_release(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name)
675 ast_log(LOG_ERROR, "Must be called with a global object!\n");
679 if (__ast_rwlock_wrlock(file, line, func, &holder->lock, name)) {
680 /* Could not get the write lock. */
685 /* Release the held ao2 object. */
687 __ao2_ref_debug(holder->obj, -1, tag, file, line, func);
691 __ast_rwlock_unlock(file, line, func, &holder->lock, name);
694 void *__ao2_global_obj_replace(struct ao2_global_obj *holder, void *obj, const char *tag, const char *file, int line, const char *func, const char *name)
700 ast_log(LOG_ERROR, "Must be called with a global object!\n");
704 if (__ast_rwlock_wrlock(file, line, func, &holder->lock, name)) {
705 /* Could not get the write lock. */
711 __ao2_ref_debug(obj, +1, tag, file, line, func);
713 obj_old = holder->obj;
716 __ast_rwlock_unlock(file, line, func, &holder->lock, name);
721 int __ao2_global_obj_replace_unref(struct ao2_global_obj *holder, void *obj, const char *tag, const char *file, int line, const char *func, const char *name)
725 obj_old = __ao2_global_obj_replace(holder, obj, tag, file, line, func, name);
727 __ao2_ref_debug(obj_old, -1, tag, file, line, func);
733 void *__ao2_global_obj_ref(struct ao2_global_obj *holder, const char *tag, const char *file, int line, const char *func, const char *name)
739 ast_log(LOG_ERROR, "Must be called with a global object!\n");
744 if (__ast_rwlock_rdlock(file, line, func, &holder->lock, name)) {
745 /* Could not get the read lock. */
752 __ao2_ref_debug(obj, +1, tag, file, line, func);
755 __ast_rwlock_unlock(file, line, func, &holder->lock, name);
760 enum ao2_callback_type {
761 AO2_CALLBACK_DEFAULT,
762 AO2_CALLBACK_WITH_DATA,
765 enum ao2_container_insert {
766 /*! The node was inserted into the container. */
767 AO2_CONTAINER_INSERT_NODE_INSERTED,
768 /*! The node object replaced an existing node object. */
769 AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED,
770 /*! The node was rejected (duplicate). */
771 AO2_CONTAINER_INSERT_NODE_REJECTED,
774 enum ao2_container_rtti {
775 /*! This is a hash container */
776 AO2_CONTAINER_RTTI_HASH,
777 /*! This is a red-black tree container */
778 AO2_CONTAINER_RTTI_RBTREE,
782 * \brief Generic container node.
784 * \details This is the base container node type that contains
785 * values common to all container nodes.
787 struct ao2_container_node {
788 /*! Stored object in node. */
790 /*! Container holding the node. (Does not hold a reference.) */
791 struct ao2_container *my_container;
792 /*! TRUE if the node is linked into the container. */
793 unsigned int is_linked:1;
797 * \brief Destroy this container.
799 * \param self Container to operate upon.
803 typedef void (*ao2_container_destroy_fn)(struct ao2_container *self);
806 * \brief Create an empty copy of this container.
808 * \param self Container to operate upon.
810 * \retval empty-container on success.
811 * \retval NULL on error.
813 typedef struct ao2_container *(*ao2_container_alloc_empty_clone_fn)(struct ao2_container *self);
816 * \brief Create an empty copy of this container. (Debug version)
818 * \param self Container to operate upon.
819 * \param tag used for debugging.
820 * \param file Debug file name invoked from
821 * \param line Debug line invoked from
822 * \param func Debug function name invoked from
823 * \param ref_debug TRUE if to output a debug reference message.
825 * \retval empty-container on success.
826 * \retval NULL on error.
828 typedef struct ao2_container *(*ao2_container_alloc_empty_clone_debug_fn)(struct ao2_container *self, const char *tag, const char *file, int line, const char *func, int ref_debug);
831 * \brief Create a new container node.
833 * \param self Container to operate upon.
834 * \param obj_new Object to put into the node.
835 * \param tag used for debugging.
836 * \param file Debug file name invoked from
837 * \param line Debug line invoked from
838 * \param func Debug function name invoked from
840 * \retval initialized-node on success.
841 * \retval NULL on error.
843 typedef struct ao2_container_node *(*ao2_container_new_node_fn)(struct ao2_container *self, void *obj_new, const char *tag, const char *file, int line, const char *func);
846 * \brief Insert a node into this container.
848 * \param self Container to operate upon.
849 * \param node Container node to insert into the container.
851 * \return enum ao2_container_insert value.
853 typedef enum ao2_container_insert (*ao2_container_insert_fn)(struct ao2_container *self, struct ao2_container_node *node);
856 * \brief Find the first container node in a traversal.
858 * \param self Container to operate upon.
859 * \param flags search_flags to control traversing the container
860 * \param arg Comparison callback arg parameter.
861 * \param v_state Traversal state to restart container traversal.
863 * \retval node-ptr of found node (Reffed).
864 * \retval NULL when no node found.
866 typedef struct ao2_container_node *(*ao2_container_find_first_fn)(struct ao2_container *self, enum search_flags flags, void *arg, void *v_state);
869 * \brief Find the next container node in a traversal.
871 * \param self Container to operate upon.
872 * \param v_state Traversal state to restart container traversal.
873 * \param prev Previous node returned by the traversal search functions.
874 * The ref ownership is passed back to this function.
876 * \retval node-ptr of found node (Reffed).
877 * \retval NULL when no node found.
879 typedef struct ao2_container_node *(*ao2_container_find_next_fn)(struct ao2_container *self, void *v_state, struct ao2_container_node *prev);
882 * \brief Cleanup the container traversal state.
884 * \param v_state Traversal state to cleanup.
888 typedef void (*ao2_container_find_cleanup_fn)(void *v_state);
891 * \brief Find the next non-empty iteration node in the container.
893 * \param self Container to operate upon.
894 * \param prev Previous node returned by the iterator.
895 * \param flags search_flags to control iterating the container.
896 * Only AO2_ITERATOR_DESCENDING is useful by the method.
898 * \note The container is already locked.
900 * \retval node on success.
901 * \retval NULL on error or no more nodes in the container.
903 typedef struct ao2_container_node *(*ao2_iterator_next_fn)(struct ao2_container *self, struct ao2_container_node *prev, enum ao2_iterator_flags flags);
906 * \brief Display contents of the specified container.
908 * \param self Container to dump.
909 * \param where User data needed by prnt to determine where to put output.
910 * \param prnt Print output callback function to use.
911 * \param prnt_obj Callback function to print the given object's key. (NULL if not available)
915 typedef void (*ao2_container_display)(struct ao2_container *self, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj);
918 * \brief Display statistics of the specified container.
920 * \param self Container to display statistics.
921 * \param where User data needed by prnt to determine where to put output.
922 * \param prnt Print output callback function to use.
924 * \note The container is already locked for reading.
928 typedef void (*ao2_container_statistics)(struct ao2_container *self, void *where, ao2_prnt_fn *prnt);
931 * \brief Perform an integrity check on the specified container.
933 * \param self Container to check integrity.
935 * \note The container is already locked for reading.
937 * \retval 0 on success.
938 * \retval -1 on error.
940 typedef int (*ao2_container_integrity)(struct ao2_container *self);
942 /*! Container virtual methods template. */
943 struct ao2_container_methods {
944 /*! Run Time Type Identification */
945 enum ao2_container_rtti type;
946 /*! Destroy this container. */
947 ao2_container_destroy_fn destroy;
948 /*! \brief Create an empty copy of this container. */
949 ao2_container_alloc_empty_clone_fn alloc_empty_clone;
950 /*! \brief Create an empty copy of this container. (Debug version) */
951 ao2_container_alloc_empty_clone_debug_fn alloc_empty_clone_debug;
952 /*! Create a new container node. */
953 ao2_container_new_node_fn new_node;
954 /*! Insert a node into this container. */
955 ao2_container_insert_fn insert;
956 /*! Traverse the container, find the first node. */
957 ao2_container_find_first_fn traverse_first;
958 /*! Traverse the container, find the next node. */
959 ao2_container_find_next_fn traverse_next;
960 /*! Traverse the container, cleanup state. */
961 ao2_container_find_cleanup_fn traverse_cleanup;
962 /*! Find the next iteration element in the container. */
963 ao2_iterator_next_fn iterator_next;
964 #if defined(AST_DEVMODE)
965 /*! Display container contents. (Method for debug purposes) */
966 ao2_container_display dump;
967 /*! Display container debug statistics. (Method for debug purposes) */
968 ao2_container_statistics stats;
969 /*! Perform an integrity check on the container. (Method for debug purposes) */
970 ao2_container_integrity integrity;
971 #endif /* defined(AST_DEVMODE) */
975 * \brief Generic container type.
977 * \details This is the base container type that contains values
978 * common to all container types.
980 * \todo Linking and unlinking container objects is typically
981 * expensive, as it involves a malloc()/free() of a small object
982 * which is very inefficient. To optimize this, we can allocate
983 * larger arrays of container nodes when we run out of them, and
984 * then manage our own freelist. This will be more efficient as
985 * we can do the freelist management while we hold the lock
986 * (that we need anyway).
988 struct ao2_container {
989 /*! Container virtual method table. */
990 const struct ao2_container_methods *v_table;
991 /*! Container sort function if the container is sorted. */
992 ao2_sort_fn *sort_fn;
993 /*! Container traversal matching function for ao2_find. */
994 ao2_callback_fn *cmp_fn;
995 /*! The container option flags */
997 /*! Number of elements in the container. */
999 #if defined(AST_DEVMODE)
1000 /*! Number of nodes in the container. */
1002 /*! Maximum number of empty nodes in the container. (nodes - elements) */
1003 int max_empty_nodes;
1004 #endif /* defined(AST_DEVMODE) */
1006 * \brief TRUE if the container is being destroyed.
1008 * \note The destruction traversal should override any requested
1009 * search order to do the most efficient order for destruction.
1011 * \note There should not be any empty nodes in the container
1012 * during destruction. If there are then an error needs to be
1013 * issued about container node reference leaks.
1015 unsigned int destroying:1;
1019 * return the number of elements in the container
1021 int ao2_container_count(struct ao2_container *c)
1023 return ast_atomic_fetchadd_int(&c->elements, 0);
1026 #if defined(AST_DEVMODE)
1027 static void hash_ao2_link_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node);
1028 static void hash_ao2_unlink_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node);
1029 #endif /* defined(AST_DEVMODE) */
1033 * \brief Link an object into this container. (internal)
1035 * \param self Container to operate upon.
1036 * \param obj_new Object to insert into the container.
1037 * \param flags search_flags to control linking the object. (OBJ_NOLOCK)
1038 * \param tag used for debugging.
1039 * \param file Debug file name invoked from
1040 * \param line Debug line invoked from
1041 * \param func Debug function name invoked from
1043 * \retval 0 on errors.
1044 * \retval 1 on success.
1046 static int internal_ao2_link(struct ao2_container *self, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
1049 enum ao2_lock_req orig_lock;
1050 struct ao2_container_node *node;
1052 if (!INTERNAL_OBJ(obj_new) || !INTERNAL_OBJ(self)
1053 || !self->v_table || !self->v_table->new_node || !self->v_table->insert) {
1054 /* Sanity checks. */
1059 if (flags & OBJ_NOLOCK) {
1060 orig_lock = adjust_lock(self, AO2_LOCK_REQ_WRLOCK, 1);
1063 orig_lock = AO2_LOCK_REQ_MUTEX;
1067 node = self->v_table->new_node(self, obj_new, tag, file, line, func);
1069 #if defined(AO2_DEBUG) && defined(AST_DEVMODE)
1070 switch (self->v_table->type) {
1071 case AO2_CONTAINER_RTTI_HASH:
1072 if (!self->sort_fn) {
1074 * XXX chan_iax2 plays games with the hash function so we cannot
1075 * routinely do an integrity check on this type of container.
1076 * chan_iax2 should be changed to not abuse the hash function.
1081 case AO2_CONTAINER_RTTI_RBTREE:
1082 if (ao2_container_check(self, OBJ_NOLOCK)) {
1083 ast_log(LOG_ERROR, "Container integrity failed before insert.\n");
1087 #endif /* defined(AO2_DEBUG) && defined(AST_DEVMODE) */
1088 /* Insert the new node. */
1089 switch (self->v_table->insert(self, node)) {
1090 case AO2_CONTAINER_INSERT_NODE_INSERTED:
1091 node->is_linked = 1;
1092 ast_atomic_fetchadd_int(&self->elements, 1);
1093 #if defined(AST_DEVMODE)
1094 AO2_DEVMODE_STAT(++self->nodes);
1095 switch (self->v_table->type) {
1096 case AO2_CONTAINER_RTTI_HASH:
1097 hash_ao2_link_node_stat(self, node);
1099 case AO2_CONTAINER_RTTI_RBTREE:
1102 #endif /* defined(AST_DEVMODE) */
1106 case AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED:
1109 case AO2_CONTAINER_INSERT_NODE_REJECTED:
1110 __ao2_ref(node, -1);
1113 #if defined(AO2_DEBUG) && defined(AST_DEVMODE)
1115 switch (self->v_table->type) {
1116 case AO2_CONTAINER_RTTI_HASH:
1117 if (!self->sort_fn) {
1119 * XXX chan_iax2 plays games with the hash function so we cannot
1120 * routinely do an integrity check on this type of container.
1121 * chan_iax2 should be changed to not abuse the hash function.
1126 case AO2_CONTAINER_RTTI_RBTREE:
1127 if (ao2_container_check(self, OBJ_NOLOCK)) {
1128 ast_log(LOG_ERROR, "Container integrity failed after insert.\n");
1133 #endif /* defined(AO2_DEBUG) && defined(AST_DEVMODE) */
1136 if (flags & OBJ_NOLOCK) {
1137 adjust_lock(self, orig_lock, 0);
1145 int __ao2_link_debug(struct ao2_container *c, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
1147 return internal_ao2_link(c, obj_new, flags, tag, file, line, func);
1150 int __ao2_link(struct ao2_container *c, void *obj_new, int flags)
1152 return internal_ao2_link(c, obj_new, flags, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__);
1156 * \brief another convenience function is a callback that matches on address
1158 int ao2_match_by_addr(void *user_data, void *arg, int flags)
1160 return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
1164 * Unlink an object from the container
1165 * and destroy the associated * bucket_entry structure.
1167 void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, int flags,
1168 const char *tag, const char *file, int line, const char *func)
1170 if (!INTERNAL_OBJ(user_data)) {
1171 /* Sanity checks. */
1176 flags |= (OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA);
1177 __ao2_callback_debug(c, flags, ao2_match_by_addr, user_data, tag, file, line, func);
1182 void *__ao2_unlink(struct ao2_container *c, void *user_data, int flags)
1184 if (!INTERNAL_OBJ(user_data)) {
1185 /* Sanity checks. */
1190 flags |= (OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA);
1191 __ao2_callback(c, flags, ao2_match_by_addr, user_data);
1197 * \brief special callback that matches all
1199 static int cb_true(void *user_data, void *arg, int flags)
1205 * \brief similar to cb_true, but is an ao2_callback_data_fn instead
1207 static int cb_true_data(void *user_data, void *arg, void *data, int flags)
1212 /*! Allow enough room for container specific traversal state structs */
1213 #define AO2_TRAVERSAL_STATE_SIZE 100
1217 * \brief Traverse the container. (internal)
1219 * \param self Container to operate upon.
1220 * \param flags search_flags to control traversing the container
1221 * \param cb_fn Comparison callback function.
1222 * \param arg Comparison callback arg parameter.
1223 * \param data Data comparison callback data parameter.
1224 * \param type Type of comparison callback cb_fn.
1225 * \param tag used for debugging.
1226 * \param file Debug file name invoked from
1227 * \param line Debug line invoked from
1228 * \param func Debug function name invoked from
1230 * \retval NULL on failure or no matching object found.
1232 * \retval object found if OBJ_MULTIPLE is not set in the flags
1235 * \retval ao2_iterator pointer if OBJ_MULTIPLE is set in the
1236 * flags parameter. The iterator must be destroyed with
1237 * ao2_iterator_destroy() when the caller no longer needs it.
1239 static void *internal_ao2_traverse(struct ao2_container *self, enum search_flags flags,
1240 void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
1241 const char *tag, const char *file, int line, const char *func)
1244 ao2_callback_fn *cb_default = NULL;
1245 ao2_callback_data_fn *cb_withdata = NULL;
1246 struct ao2_container_node *node;
1247 void *traversal_state;
1249 enum ao2_lock_req orig_lock;
1250 struct ao2_container *multi_container = NULL;
1251 struct ao2_iterator *multi_iterator = NULL;
1253 if (!INTERNAL_OBJ(self) || !self->v_table || !self->v_table->traverse_first
1254 || !self->v_table->traverse_next) {
1255 /* Sanity checks. */
1261 * This logic is used so we can support OBJ_MULTIPLE with OBJ_NODATA
1262 * turned off. This if statement checks for the special condition
1263 * where multiple items may need to be returned.
1265 if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) {
1266 /* we need to return an ao2_iterator with the results,
1267 * as there could be more than one. the iterator will
1268 * hold the only reference to a container that has all the
1269 * matching objects linked into it, so when the iterator
1270 * is destroyed, the container will be automatically
1271 * destroyed as well.
1273 multi_container = ao2_t_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL,
1274 NULL, "OBJ_MULTIPLE return container creation");
1275 if (!multi_container) {
1278 if (!(multi_iterator = ast_calloc(1, sizeof(*multi_iterator)))) {
1279 ao2_t_ref(multi_container, -1, "OBJ_MULTIPLE interator creation failed.");
1285 /* Match everything if no callback match function provided. */
1286 if (type == AO2_CALLBACK_WITH_DATA) {
1287 cb_withdata = cb_true_data;
1289 cb_default = cb_true;
1293 * We do this here to avoid the per object casting penalty (even
1294 * though that is probably optimized away anyway).
1296 if (type == AO2_CALLBACK_WITH_DATA) {
1297 cb_withdata = cb_fn;
1303 /* avoid modifications to the content */
1304 if (flags & OBJ_NOLOCK) {
1305 if (flags & OBJ_UNLINK) {
1306 orig_lock = adjust_lock(self, AO2_LOCK_REQ_WRLOCK, 1);
1308 orig_lock = adjust_lock(self, AO2_LOCK_REQ_RDLOCK, 1);
1311 orig_lock = AO2_LOCK_REQ_MUTEX;
1312 if (flags & OBJ_UNLINK) {
1319 /* Create a buffer for the traversal state. */
1320 traversal_state = alloca(AO2_TRAVERSAL_STATE_SIZE);
1323 for (node = self->v_table->traverse_first(self, flags, arg, traversal_state);
1325 node = self->v_table->traverse_next(self, traversal_state, node)) {
1328 /* Visit the current node. */
1329 match = (CMP_MATCH | CMP_STOP);
1330 if (type == AO2_CALLBACK_WITH_DATA) {
1331 match &= cb_withdata(node->obj, arg, data, flags);
1333 match &= cb_default(node->obj, arg, flags);
1336 /* no match, no stop, continue */
1339 if (match == CMP_STOP) {
1340 /* no match but stop, we are done */
1345 * CMP_MATCH is set here
1347 * we found the object, performing operations according to flags
1350 /* The object is still in the container. */
1351 if (!(flags & OBJ_NODATA)) {
1353 * We are returning the object, record the value. It is
1354 * important to handle this case before the unlink.
1356 if (multi_container) {
1358 * Link the object into the container that will hold the
1362 __ao2_link_debug(multi_container, node->obj, flags,
1363 tag, file, line, func);
1365 __ao2_link(multi_container, node->obj, flags);
1369 /* Returning a single object. */
1370 if (!(flags & OBJ_UNLINK)) {
1372 * Bump the ref count since we are not going to unlink and
1373 * transfer the container's object ref to the returned object.
1376 __ao2_ref_debug(ret, 1, tag, file, line, func);
1378 ao2_t_ref(ret, 1, "Traversal found object");
1384 if (flags & OBJ_UNLINK) {
1385 /* update number of elements */
1386 ast_atomic_fetchadd_int(&self->elements, -1);
1387 #if defined(AST_DEVMODE)
1389 int empty = self->nodes - self->elements;
1391 if (self->max_empty_nodes < empty) {
1392 self->max_empty_nodes = empty;
1395 switch (self->v_table->type) {
1396 case AO2_CONTAINER_RTTI_HASH:
1397 hash_ao2_unlink_node_stat(self, node);
1399 case AO2_CONTAINER_RTTI_RBTREE:
1402 #endif /* defined(AST_DEVMODE) */
1405 * - When unlinking and not returning the result, OBJ_NODATA is
1406 * set, the ref from the container must be decremented.
1408 * - When unlinking with a multi_container the ref from the
1409 * original container must be decremented. This is because the
1410 * result is returned in a new container that already holds its
1411 * own ref for the object.
1413 * If the ref from the original container is not accounted for
1414 * here a memory leak occurs.
1416 if (multi_container || (flags & OBJ_NODATA)) {
1418 __ao2_ref_debug(node->obj, -1, tag, file, line, func);
1420 ao2_t_ref(node->obj, -1, "Unlink container obj reference.");
1425 /* Unref the node from the container. */
1426 __ao2_ref(node, -1);
1430 if ((match & CMP_STOP) || !(flags & OBJ_MULTIPLE)) {
1431 /* We found our only (or last) match, so we are done */
1435 if (self->v_table->traverse_cleanup) {
1436 self->v_table->traverse_cleanup(traversal_state);
1439 /* Unref the node from self->v_table->traverse_first/traverse_next() */
1440 __ao2_ref(node, -1);
1443 if (flags & OBJ_NOLOCK) {
1444 adjust_lock(self, orig_lock, 0);
1449 /* if multi_container was created, we are returning multiple objects */
1450 if (multi_container) {
1451 *multi_iterator = ao2_iterator_init(multi_container,
1452 AO2_ITERATOR_UNLINK | AO2_ITERATOR_MALLOCD);
1453 ao2_t_ref(multi_container, -1,
1454 "OBJ_MULTIPLE for multiple objects traversal complete.");
1455 return multi_iterator;
1461 void *__ao2_callback_debug(struct ao2_container *c, enum search_flags flags,
1462 ao2_callback_fn *cb_fn, void *arg, const char *tag, const char *file, int line,
1465 return internal_ao2_traverse(c, flags, cb_fn, arg, NULL, AO2_CALLBACK_DEFAULT, tag, file, line, func);
1468 void *__ao2_callback(struct ao2_container *c, enum search_flags flags,
1469 ao2_callback_fn *cb_fn, void *arg)
1471 return internal_ao2_traverse(c, flags, cb_fn, arg, NULL, AO2_CALLBACK_DEFAULT, NULL, NULL, 0, NULL);
1474 void *__ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags,
1475 ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, const char *file,
1476 int line, const char *func)
1478 return internal_ao2_traverse(c, flags, cb_fn, arg, data, AO2_CALLBACK_WITH_DATA, tag, file, line, func);
1481 void *__ao2_callback_data(struct ao2_container *c, enum search_flags flags,
1482 ao2_callback_data_fn *cb_fn, void *arg, void *data)
1484 return internal_ao2_traverse(c, flags, cb_fn, arg, data, AO2_CALLBACK_WITH_DATA, NULL, NULL, 0, NULL);
1488 * the find function just invokes the default callback with some reasonable flags.
1490 void *__ao2_find_debug(struct ao2_container *c, const void *arg, enum search_flags flags,
1491 const char *tag, const char *file, int line, const char *func)
1493 void *arged = (void *) arg;/* Done to avoid compiler const warning */
1496 /* Sanity checks. */
1500 return __ao2_callback_debug(c, flags, c->cmp_fn, arged, tag, file, line, func);
1503 void *__ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags)
1505 void *arged = (void *) arg;/* Done to avoid compiler const warning */
1508 /* Sanity checks. */
1512 return __ao2_callback(c, flags, c->cmp_fn, arged);
1516 * initialize an iterator so we start from the first object
1518 struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
1520 struct ao2_iterator a = {
1525 ao2_t_ref(c, +1, "Init iterator with container.");
1530 void ao2_iterator_restart(struct ao2_iterator *iter)
1532 /* Release the last container node reference if we have one. */
1533 if (iter->last_node) {
1534 enum ao2_lock_req orig_lock;
1537 * Do a read lock in case the container node unref does not
1538 * destroy the node. If the container node is destroyed then
1539 * the lock will be upgraded to a write lock.
1541 if (iter->flags & AO2_ITERATOR_DONTLOCK) {
1542 orig_lock = adjust_lock(iter->c, AO2_LOCK_REQ_RDLOCK, 1);
1544 orig_lock = AO2_LOCK_REQ_MUTEX;
1545 ao2_rdlock(iter->c);
1548 __ao2_ref(iter->last_node, -1);
1549 iter->last_node = NULL;
1551 if (iter->flags & AO2_ITERATOR_DONTLOCK) {
1552 adjust_lock(iter->c, orig_lock, 0);
1554 ao2_unlock(iter->c);
1558 /* The iteration is no longer complete. */
1562 void ao2_iterator_destroy(struct ao2_iterator *iter)
1564 /* Release any last container node reference. */
1565 ao2_iterator_restart(iter);
1567 /* Release the iterated container reference. */
1568 ao2_t_ref(iter->c, -1, "Unref iterator in ao2_iterator_destroy");
1571 /* Free the malloced iterator. */
1572 if (iter->flags & AO2_ITERATOR_MALLOCD) {
1577 void ao2_iterator_cleanup(struct ao2_iterator *iter)
1580 ao2_iterator_destroy(iter);
1585 * move to the next element in the container.
1587 static void *internal_ao2_iterator_next(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func)
1589 enum ao2_lock_req orig_lock;
1590 struct ao2_container_node *node;
1593 if (!INTERNAL_OBJ(iter->c) || !iter->c->v_table || !iter->c->v_table->iterator_next) {
1594 /* Sanity checks. */
1599 if (iter->complete) {
1600 /* Don't return any more objects. */
1604 if (iter->flags & AO2_ITERATOR_DONTLOCK) {
1605 if (iter->flags & AO2_ITERATOR_UNLINK) {
1606 orig_lock = adjust_lock(iter->c, AO2_LOCK_REQ_WRLOCK, 1);
1608 orig_lock = adjust_lock(iter->c, AO2_LOCK_REQ_RDLOCK, 1);
1611 orig_lock = AO2_LOCK_REQ_MUTEX;
1612 if (iter->flags & AO2_ITERATOR_UNLINK) {
1613 ao2_wrlock(iter->c);
1615 ao2_rdlock(iter->c);
1619 node = iter->c->v_table->iterator_next(iter->c, iter->last_node, iter->flags);
1623 if (iter->flags & AO2_ITERATOR_UNLINK) {
1624 /* update number of elements */
1625 ast_atomic_fetchadd_int(&iter->c->elements, -1);
1626 #if defined(AST_DEVMODE)
1628 int empty = iter->c->nodes - iter->c->elements;
1630 if (iter->c->max_empty_nodes < empty) {
1631 iter->c->max_empty_nodes = empty;
1634 switch (iter->c->v_table->type) {
1635 case AO2_CONTAINER_RTTI_HASH:
1636 hash_ao2_unlink_node_stat(iter->c, node);
1638 case AO2_CONTAINER_RTTI_RBTREE:
1641 #endif /* defined(AST_DEVMODE) */
1643 /* Transfer the object ref from the container to the returned object. */
1646 /* Transfer the container's node ref to the iterator. */
1648 /* Bump ref of returned object */
1650 __ao2_ref_debug(ret, +1, tag, file, line, func);
1652 ao2_t_ref(ret, +1, "Next iterator object.");
1655 /* Bump the container's node ref for the iterator. */
1656 __ao2_ref(node, +1);
1659 /* The iteration has completed. */
1664 /* Replace the iterator's node */
1665 if (iter->last_node) {
1666 __ao2_ref(iter->last_node, -1);
1668 iter->last_node = node;
1670 if (iter->flags & AO2_ITERATOR_DONTLOCK) {
1671 adjust_lock(iter->c, orig_lock, 0);
1673 ao2_unlock(iter->c);
1679 void *__ao2_iterator_next_debug(struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func)
1681 return internal_ao2_iterator_next(iter, tag, file, line, func);
1684 void *__ao2_iterator_next(struct ao2_iterator *iter)
1686 return internal_ao2_iterator_next(iter, NULL, __FILE__, __LINE__, __PRETTY_FUNCTION__);
1689 static void container_destruct(void *_c)
1691 struct ao2_container *c = _c;
1693 /* Unlink any stored objects in the container. */
1695 __ao2_callback(c, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
1697 /* Perform any extra container cleanup. */
1698 if (c->v_table && c->v_table->destroy) {
1699 c->v_table->destroy(c);
1703 ast_atomic_fetchadd_int(&ao2.total_containers, -1);
1707 static void container_destruct_debug(void *_c)
1709 struct ao2_container *c = _c;
1711 /* Unlink any stored objects in the container. */
1713 __ao2_callback_debug(c, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL,
1714 "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
1716 /* Perform any extra container cleanup. */
1717 if (c->v_table && c->v_table->destroy) {
1718 c->v_table->destroy(c);
1722 ast_atomic_fetchadd_int(&ao2.total_containers, -1);
1728 * \brief Put obj into the arg container.
1731 * \param obj pointer to the (user-defined part) of an object.
1732 * \param arg callback argument from ao2_callback()
1733 * \param flags flags from ao2_callback()
1735 * \retval 0 on success.
1736 * \retval CMP_STOP|CMP_MATCH on error.
1738 static int dup_obj_cb(void *obj, void *arg, int flags)
1740 struct ao2_container *dest = arg;
1742 return __ao2_link(dest, obj, OBJ_NOLOCK) ? 0 : (CMP_MATCH | CMP_STOP);
1745 int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
1750 if (!(flags & OBJ_NOLOCK)) {
1754 obj = __ao2_callback(src, OBJ_NOLOCK, dup_obj_cb, dest);
1756 /* Failed to put this obj into the dest container. */
1757 ao2_t_ref(obj, -1, "Failed to put this object into the dest container.");
1759 /* Remove all items from the dest container. */
1760 __ao2_callback(dest, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL,
1764 if (!(flags & OBJ_NOLOCK)) {
1772 struct ao2_container *__ao2_container_clone(struct ao2_container *orig, enum search_flags flags)
1774 struct ao2_container *clone;
1777 /* Create the clone container with the same properties as the original. */
1778 if (!INTERNAL_OBJ(orig) || !orig->v_table || !orig->v_table->alloc_empty_clone) {
1779 /* Sanity checks. */
1783 clone = orig->v_table->alloc_empty_clone(orig);
1788 if (flags & OBJ_NOLOCK) {
1791 failed = ao2_container_dup(clone, orig, flags);
1792 if (flags & OBJ_NOLOCK) {
1796 /* Object copy into the clone container failed. */
1797 ao2_t_ref(clone, -1, "Clone creation failed.");
1803 struct ao2_container *__ao2_container_clone_debug(struct ao2_container *orig, enum search_flags flags, const char *tag, const char *file, int line, const char *func, int ref_debug)
1805 struct ao2_container *clone;
1808 /* Create the clone container with the same properties as the original. */
1809 if (!INTERNAL_OBJ(orig) || !orig->v_table || !orig->v_table->alloc_empty_clone_debug) {
1810 /* Sanity checks. */
1814 clone = orig->v_table->alloc_empty_clone_debug(orig, tag, file, line, func, ref_debug);
1819 if (flags & OBJ_NOLOCK) {
1822 failed = ao2_container_dup(clone, orig, flags);
1823 if (flags & OBJ_NOLOCK) {
1827 /* Object copy into the clone container failed. */
1829 __ao2_ref_debug(clone, -1, tag, file, line, func);
1831 ao2_t_ref(clone, -1, "Clone creation failed.");
1838 void ao2_container_dump(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj)
1840 if (!INTERNAL_OBJ(self) || !self->v_table) {
1841 prnt(where, "Invalid container\n");
1846 if (!(flags & OBJ_NOLOCK)) {
1850 prnt(where, "Container name: %s\n", name);
1852 #if defined(AST_DEVMODE)
1853 if (self->v_table->dump) {
1854 self->v_table->dump(self, where, prnt, prnt_obj);
1856 #endif /* defined(AST_DEVMODE) */
1858 prnt(where, "Container dump not available.\n");
1860 if (!(flags & OBJ_NOLOCK)) {
1865 void ao2_container_stats(struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt)
1867 if (!INTERNAL_OBJ(self) || !self->v_table) {
1868 prnt(where, "Invalid container\n");
1873 if (!(flags & OBJ_NOLOCK)) {
1877 prnt(where, "Container name: %s\n", name);
1879 prnt(where, "Number of objects: %d\n", self->elements);
1880 #if defined(AST_DEVMODE)
1881 prnt(where, "Number of nodes: %d\n", self->nodes);
1882 prnt(where, "Number of empty nodes: %d\n", self->nodes - self->elements);
1885 * If the max_empty_nodes count gets out of single digits you
1886 * likely have a code path where ao2_iterator_destroy() is not
1889 * Empty nodes do not harm the container but they do make
1890 * container operations less efficient.
1892 prnt(where, "Maximum empty nodes: %d\n", self->max_empty_nodes);
1893 if (self->v_table->stats) {
1894 self->v_table->stats(self, where, prnt);
1896 #endif /* defined(AST_DEVMODE) */
1897 if (!(flags & OBJ_NOLOCK)) {
1902 int ao2_container_check(struct ao2_container *self, enum search_flags flags)
1906 if (!INTERNAL_OBJ(self) || !self->v_table) {
1907 /* Sanity checks. */
1911 #if defined(AST_DEVMODE)
1912 if (!self->v_table->integrity) {
1913 /* No ingetrigy check available. Assume container is ok. */
1917 if (!(flags & OBJ_NOLOCK)) {
1920 res = self->v_table->integrity(self);
1921 if (!(flags & OBJ_NOLOCK)) {
1924 #endif /* defined(AST_DEVMODE) */
1929 * A structure to create a linked list of entries,
1930 * used within a bucket.
1932 struct hash_bucket_node {
1934 * \brief Items common to all container nodes.
1935 * \note Must be first in the specific node struct.
1937 struct ao2_container_node common;
1938 /*! Next node links in the list. */
1939 AST_DLLIST_ENTRY(hash_bucket_node) links;
1940 /*! Hash bucket holding the node. */
1944 struct hash_bucket {
1945 /*! List of objects held in the bucket. */
1946 AST_DLLIST_HEAD_NOLOCK(, hash_bucket_node) list;
1947 #if defined(AST_DEVMODE)
1948 /*! Number of elements currently in the bucket. */
1950 /*! Maximum number of elements in the bucket. */
1952 #endif /* defined(AST_DEVMODE) */
1956 * A hash container in addition to values common to all
1957 * container types, stores the hash callback function, the
1958 * number of hash buckets, and the hash bucket heads.
1960 struct ao2_container_hash {
1962 * \brief Items common to all containers.
1963 * \note Must be first in the specific container struct.
1965 struct ao2_container common;
1966 ao2_hash_fn *hash_fn;
1967 /*! Number of hash buckets in this container. */
1969 /*! Hash bucket array of n_buckets. Variable size. */
1970 struct hash_bucket buckets[0];
1975 * \brief Create an empty copy of this container.
1978 * \param self Container to operate upon.
1980 * \retval empty-clone-container on success.
1981 * \retval NULL on error.
1983 static struct ao2_container *hash_ao2_alloc_empty_clone(struct ao2_container_hash *self)
1985 struct astobj2 *orig_obj;
1986 unsigned int ao2_options;
1988 /* Get container ao2 options. */
1989 orig_obj = INTERNAL_OBJ(self);
1993 ao2_options = orig_obj->priv_data.options;
1995 return ao2_t_container_alloc_hash(ao2_options, self->common.options, self->n_buckets,
1996 self->hash_fn, self->common.sort_fn, self->common.cmp_fn, "Clone hash container");
2001 * \brief Create an empty copy of this container. (Debug version)
2004 * \param self Container to operate upon.
2005 * \param tag used for debugging.
2006 * \param file Debug file name invoked from
2007 * \param line Debug line invoked from
2008 * \param func Debug function name invoked from
2009 * \param ref_debug TRUE if to output a debug reference message.
2011 * \retval empty-clone-container on success.
2012 * \retval NULL on error.
2014 static struct ao2_container *hash_ao2_alloc_empty_clone_debug(struct ao2_container_hash *self, const char *tag, const char *file, int line, const char *func, int ref_debug)
2016 struct astobj2 *orig_obj;
2017 unsigned int ao2_options;
2019 /* Get container ao2 options. */
2020 orig_obj = INTERNAL_OBJ(self);
2024 ao2_options = orig_obj->priv_data.options;
2026 return __ao2_container_alloc_hash_debug(ao2_options, self->common.options,
2027 self->n_buckets, self->hash_fn, self->common.sort_fn, self->common.cmp_fn,
2028 tag, file, line, func, ref_debug);
2033 * \brief Destroy a hash container list node.
2036 * \param v_doomed Container node to destroy.
2039 * The container node unlinks itself from the container as part
2040 * of its destruction. The node must be destroyed while the
2041 * container is already locked.
2043 * \note The container must be locked when the node is
2048 static void hash_ao2_node_destructor(void *v_doomed)
2050 struct hash_bucket_node *doomed = v_doomed;
2052 if (doomed->common.is_linked) {
2053 struct ao2_container_hash *my_container;
2054 struct hash_bucket *bucket;
2057 * Promote to write lock if not already there. Since
2058 * adjust_lock() can potentially release and block waiting for a
2059 * write lock, care must be taken to ensure that node references
2060 * are released before releasing the container references.
2062 * Node references held by an iterator can only be held while
2063 * the iterator also holds a reference to the container. These
2064 * node references must be unreferenced before the container can
2065 * be unreferenced to ensure that the node will not get a
2066 * negative reference and the destructor called twice for the
2069 my_container = (struct ao2_container_hash *) doomed->common.my_container;
2070 adjust_lock(my_container, AO2_LOCK_REQ_WRLOCK, 1);
2072 #if defined(AO2_DEBUG) && defined(AST_DEVMODE)
2074 * XXX chan_iax2 plays games with the hash function so we cannot
2075 * routinely do an integrity check on this type of container.
2076 * chan_iax2 should be changed to not abuse the hash function.
2078 if (!my_container->common.destroying
2079 && my_container->common.sort_fn
2080 && ao2_container_check(doomed->common.my_container, OBJ_NOLOCK)) {
2081 ast_log(LOG_ERROR, "Container integrity failed before node deletion.\n");
2083 #endif /* defined(AO2_DEBUG) && defined(AST_DEVMODE) */
2084 bucket = &my_container->buckets[doomed->my_bucket];
2085 AST_DLLIST_REMOVE(&bucket->list, doomed, links);
2086 AO2_DEVMODE_STAT(--my_container->common.nodes);
2090 * We could have an object in the node if the container is being
2091 * destroyed or the node had not been linked in yet.
2093 if (doomed->common.obj) {
2094 ao2_t_ref(doomed->common.obj, -1, "Container node destruction");
2095 doomed->common.obj = NULL;
2101 * \brief Create a new container node.
2104 * \param self Container to operate upon.
2105 * \param obj_new Object to put into the node.
2106 * \param tag used for debugging.
2107 * \param file Debug file name invoked from
2108 * \param line Debug line invoked from
2109 * \param func Debug function name invoked from
2111 * \retval initialized-node on success.
2112 * \retval NULL on error.
2114 static struct hash_bucket_node *hash_ao2_new_node(struct ao2_container_hash *self, void *obj_new, const char *tag, const char *file, int line, const char *func)
2116 struct hash_bucket_node *node;
2119 node = __ao2_alloc(sizeof(*node), hash_ao2_node_destructor, AO2_ALLOC_OPT_LOCK_NOLOCK);
2124 i = abs(self->hash_fn(obj_new, OBJ_POINTER));
2125 i %= self->n_buckets;
2128 __ao2_ref_debug(obj_new, +1, tag, file, line, func);
2130 ao2_t_ref(obj_new, +1, "Container node creation");
2132 node->common.obj = obj_new;
2133 node->common.my_container = (struct ao2_container *) self;
2134 node->my_bucket = i;
2141 * \brief Insert a node into this container.
2144 * \param self Container to operate upon.
2145 * \param node Container node to insert into the container.
2147 * \return enum ao2_container_insert value.
2149 static enum ao2_container_insert hash_ao2_insert_node(struct ao2_container_hash *self, struct hash_bucket_node *node)
2152 struct hash_bucket *bucket;
2153 struct hash_bucket_node *cur;
2154 ao2_sort_fn *sort_fn;
2157 bucket = &self->buckets[node->my_bucket];
2158 sort_fn = self->common.sort_fn;
2159 options = self->common.options;
2161 if (options & AO2_CONTAINER_ALLOC_OPT_INSERT_BEGIN) {
2163 AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_BEGIN(&bucket->list, cur, links) {
2164 cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_POINTER);
2169 AST_DLLIST_INSERT_AFTER_CURRENT(node, links);
2170 return AO2_CONTAINER_INSERT_NODE_INSERTED;
2172 switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
2174 case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
2176 case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
2177 /* Reject all objects with the same key. */
2178 return AO2_CONTAINER_INSERT_NODE_REJECTED;
2179 case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
2180 if (cur->common.obj == node->common.obj) {
2181 /* Reject inserting the same object */
2182 return AO2_CONTAINER_INSERT_NODE_REJECTED;
2185 case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
2186 SWAP(cur->common.obj, node->common.obj);
2187 return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED;
2190 AST_DLLIST_TRAVERSE_BACKWARDS_SAFE_END;
2192 AST_DLLIST_INSERT_HEAD(&bucket->list, node, links);
2195 AST_DLLIST_TRAVERSE_SAFE_BEGIN(&bucket->list, cur, links) {
2196 cmp = sort_fn(cur->common.obj, node->common.obj, OBJ_POINTER);
2201 AST_DLLIST_INSERT_BEFORE_CURRENT(node, links);
2202 return AO2_CONTAINER_INSERT_NODE_INSERTED;
2204 switch (options & AO2_CONTAINER_ALLOC_OPT_DUPS_MASK) {
2206 case AO2_CONTAINER_ALLOC_OPT_DUPS_ALLOW:
2208 case AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT:
2209 /* Reject all objects with the same key. */
2210 return AO2_CONTAINER_INSERT_NODE_REJECTED;
2211 case AO2_CONTAINER_ALLOC_OPT_DUPS_OBJ_REJECT:
2212 if (cur->common.obj == node->common.obj) {
2213 /* Reject inserting the same object */
2214 return AO2_CONTAINER_INSERT_NODE_REJECTED;
2217 case AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE:
2218 SWAP(cur->common.obj, node->common.obj);
2219 return AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED;
2222 AST_DLLIST_TRAVERSE_SAFE_END;
2224 AST_DLLIST_INSERT_TAIL(&bucket->list, node, links);
2226 return AO2_CONTAINER_INSERT_NODE_INSERTED;
2229 /*! Traversal state to restart a hash container traversal. */
2230 struct hash_traversal_state {
2231 /*! Active sort function in the traversal if not NULL. */
2232 ao2_sort_fn *sort_fn;
2233 /*! Node returned in the sorted starting hash bucket if OBJ_CONTINUE flag set. (Reffed) */
2234 struct hash_bucket_node *first_node;
2235 /*! Saved comparison callback arg pointer. */
2237 /*! Starting hash bucket */
2239 /*! Stopping hash bucket */
2241 /*! Saved search flags to control traversing the container. */
2242 enum search_flags flags;
2243 /*! TRUE if it is a descending search */
2244 unsigned int descending:1;
2245 /*! TRUE if the starting bucket needs to be rechecked because of sorting skips. */
2246 unsigned int recheck_starting_bucket:1;
2249 struct hash_traversal_state_check {
2251 * If we have a division by zero compile error here then there
2252 * is not enough room for the state. Increase AO2_TRAVERSAL_STATE_SIZE.
2254 char check[1 / (AO2_TRAVERSAL_STATE_SIZE / sizeof(struct hash_traversal_state))];
2259 * \brief Find the first hash container node in a traversal.
2262 * \param self Container to operate upon.
2263 * \param flags search_flags to control traversing the container
2264 * \param arg Comparison callback arg parameter.
2265 * \param state Traversal state to restart hash container traversal.
2267 * \retval node-ptr of found node (Reffed).
2268 * \retval NULL when no node found.
2270 static struct hash_bucket_node *hash_ao2_find_first(struct ao2_container_hash *self, enum search_flags flags, void *arg, struct hash_traversal_state *state)
2272 struct hash_bucket_node *node;
2276 memset(state, 0, sizeof(*state));
2278 state->flags = flags;
2280 /* Determine traversal order. */
2281 switch (flags & OBJ_ORDER_MASK) {
2282 case OBJ_ORDER_POST:
2283 case OBJ_ORDER_DESCENDING:
2284 state->descending = 1;
2287 case OBJ_ORDER_ASCENDING:
2293 * If lookup by pointer or search key, run the hash and optional
2294 * sort functions. Otherwise, traverse the whole container.
2296 if (flags & (OBJ_POINTER | OBJ_KEY)) {
2297 /* we know hash can handle this case */
2298 bucket_cur = abs(self->hash_fn(arg, flags & (OBJ_POINTER | OBJ_KEY)));
2299 bucket_cur %= self->n_buckets;
2300 state->sort_fn = self->common.sort_fn;
2302 /* don't know, let's scan all buckets */
2304 state->sort_fn = (flags & OBJ_PARTIAL_KEY) ? self->common.sort_fn : NULL;
2307 if (state->descending) {
2309 * Determine the search boundaries of a descending traversal.
2311 * bucket_cur downto state->bucket_last
2313 if (bucket_cur < 0) {
2314 bucket_cur = self->n_buckets - 1;
2315 state->bucket_last = 0;
2317 state->bucket_last = bucket_cur;
2319 if (flags & OBJ_CONTINUE) {
2320 state->bucket_last = 0;
2321 if (state->sort_fn) {
2322 state->recheck_starting_bucket = 1;
2325 state->bucket_start = bucket_cur;
2327 /* For each bucket */
2328 for (; state->bucket_last <= bucket_cur; --bucket_cur) {
2329 /* For each node in the bucket. */
2330 for (node = AST_DLLIST_LAST(&self->buckets[bucket_cur].list);
2332 node = AST_DLLIST_PREV(node, links)) {
2333 if (!node->common.obj) {
2338 if (state->sort_fn) {
2339 /* Filter node through the sort_fn */
2340 cmp = state->sort_fn(node->common.obj, arg,
2341 flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
2345 if (flags & OBJ_CONTINUE) {
2346 /* Remember first node when we wrap around. */
2347 __ao2_ref(node, +1);
2348 state->first_node = node;
2350 /* From now on all nodes are matching */
2351 state->sort_fn = NULL;
2352 } else if (cmp < 0) {
2353 /* No more nodes in this bucket are possible to match. */
2358 /* We have the first traversal node */
2359 __ao2_ref(node, +1);
2363 /* Was this the starting bucket? */
2364 if (bucket_cur == state->bucket_start
2365 && (flags & OBJ_CONTINUE)
2366 && (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
2367 /* In case the bucket was empty or none of the nodes matched. */
2368 state->sort_fn = NULL;
2371 /* Was this the first container bucket? */
2373 && (flags & OBJ_CONTINUE)
2374 && (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
2375 /* Move to the end to ensure we check every bucket */
2376 bucket_cur = self->n_buckets;
2377 state->bucket_last = state->bucket_start + 1;
2378 if (state->recheck_starting_bucket) {
2380 * We have to recheck the first part of the starting bucket
2381 * because of sorting skips.
2383 state->recheck_starting_bucket = 0;
2384 --state->bucket_last;
2390 * Determine the search boundaries of an ascending traversal.
2392 * bucket_cur to state->bucket_last-1
2394 if (bucket_cur < 0) {
2396 state->bucket_last = self->n_buckets;
2398 state->bucket_last = bucket_cur + 1;
2400 if (flags & OBJ_CONTINUE) {
2401 state->bucket_last = self->n_buckets;
2402 if (state->sort_fn) {
2403 state->recheck_starting_bucket = 1;
2406 state->bucket_start = bucket_cur;
2408 /* For each bucket */
2409 for (; bucket_cur < state->bucket_last; ++bucket_cur) {
2410 /* For each node in the bucket. */
2411 for (node = AST_DLLIST_FIRST(&self->buckets[bucket_cur].list);
2413 node = AST_DLLIST_NEXT(node, links)) {
2414 if (!node->common.obj) {
2419 if (state->sort_fn) {
2420 /* Filter node through the sort_fn */
2421 cmp = state->sort_fn(node->common.obj, arg,
2422 flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
2426 if (flags & OBJ_CONTINUE) {
2427 /* Remember first node when we wrap around. */
2428 __ao2_ref(node, +1);
2429 state->first_node = node;
2431 /* From now on all nodes are matching */
2432 state->sort_fn = NULL;
2433 } else if (cmp > 0) {
2434 /* No more nodes in this bucket are possible to match. */
2439 /* We have the first traversal node */
2440 __ao2_ref(node, +1);
2444 /* Was this the starting bucket? */
2445 if (bucket_cur == state->bucket_start
2446 && (flags & OBJ_CONTINUE)
2447 && (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
2448 /* In case the bucket was empty or none of the nodes matched. */
2449 state->sort_fn = NULL;
2452 /* Was this the last container bucket? */
2453 if (bucket_cur == self->n_buckets - 1
2454 && (flags & OBJ_CONTINUE)
2455 && (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
2456 /* Move to the beginning to ensure we check every bucket */
2458 state->bucket_last = state->bucket_start;
2459 if (state->recheck_starting_bucket) {
2461 * We have to recheck the first part of the starting bucket
2462 * because of sorting skips.
2464 state->recheck_starting_bucket = 0;
2465 ++state->bucket_last;
2476 * \brief Find the next hash container node in a traversal.
2479 * \param self Container to operate upon.
2480 * \param state Traversal state to restart hash container traversal.
2481 * \param prev Previous node returned by the traversal search functions.
2482 * The ref ownership is passed back to this function.
2484 * \retval node-ptr of found node (Reffed).
2485 * \retval NULL when no node found.
2487 static struct hash_bucket_node *hash_ao2_find_next(struct ao2_container_hash *self, struct hash_traversal_state *state, struct hash_bucket_node *prev)
2489 struct hash_bucket_node *node;
2491 enum search_flags flags;
2496 flags = state->flags;
2497 bucket_cur = prev->my_bucket;
2501 * This function is structured the same as hash_ao2_find_first()
2502 * intentionally. We are resuming the search loops from
2503 * hash_ao2_find_first() in order to find the next node. The
2504 * search loops must be resumed where hash_ao2_find_first()
2505 * returned with the first node.
2507 if (state->descending) {
2508 goto hash_descending_resume;
2510 /* For each bucket */
2511 for (; state->bucket_last <= bucket_cur; --bucket_cur) {
2512 /* For each node in the bucket. */
2513 for (node = AST_DLLIST_LAST(&self->buckets[bucket_cur].list);
2515 node = AST_DLLIST_PREV(node, links)) {
2516 if (node == state->first_node) {
2517 /* We have wrapped back to the starting point. */
2518 __ao2_ref(prev, -1);
2521 if (!node->common.obj) {
2526 if (state->sort_fn) {
2527 /* Filter node through the sort_fn */
2528 cmp = state->sort_fn(node->common.obj, arg,
2529 flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
2534 /* No more nodes in this bucket are possible to match. */
2539 /* We have the next traversal node */
2540 __ao2_ref(node, +1);
2543 * Dereferencing the prev node may result in our next node
2544 * object being removed by another thread. This could happen if
2545 * the container uses RW locks and the container was read
2548 __ao2_ref(prev, -1);
2549 if (node->common.obj) {
2554 hash_descending_resume:;
2557 /* Was this the first container bucket? */
2559 && (flags & OBJ_CONTINUE)
2560 && (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
2561 /* Move to the end to ensure we check every bucket */
2562 bucket_cur = self->n_buckets;
2563 state->bucket_last = state->bucket_start + 1;
2564 if (state->recheck_starting_bucket) {
2566 * We have to recheck the first part of the starting bucket
2567 * because of sorting skips.
2569 state->recheck_starting_bucket = 0;
2570 --state->bucket_last;
2575 goto hash_ascending_resume;
2577 /* For each bucket */
2578 for (; bucket_cur < state->bucket_last; ++bucket_cur) {
2579 /* For each node in the bucket. */
2580 for (node = AST_DLLIST_FIRST(&self->buckets[bucket_cur].list);
2582 node = AST_DLLIST_NEXT(node, links)) {
2583 if (node == state->first_node) {
2584 /* We have wrapped back to the starting point. */
2585 __ao2_ref(prev, -1);
2588 if (!node->common.obj) {
2593 if (state->sort_fn) {
2594 /* Filter node through the sort_fn */
2595 cmp = state->sort_fn(node->common.obj, arg,
2596 flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY));
2601 /* No more nodes in this bucket are possible to match. */
2606 /* We have the next traversal node */
2607 __ao2_ref(node, +1);
2610 * Dereferencing the prev node may result in our next node
2611 * object being removed by another thread. This could happen if
2612 * the container uses RW locks and the container was read
2615 __ao2_ref(prev, -1);
2616 if (node->common.obj) {
2621 hash_ascending_resume:;
2624 /* Was this the last container bucket? */
2625 if (bucket_cur == self->n_buckets - 1
2626 && (flags & OBJ_CONTINUE)
2627 && (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY))) {
2628 /* Move to the beginning to ensure we check every bucket */
2630 state->bucket_last = state->bucket_start;
2631 if (state->recheck_starting_bucket) {
2633 * We have to recheck the first part of the starting bucket
2634 * because of sorting skips.
2636 state->recheck_starting_bucket = 0;
2637 ++state->bucket_last;
2643 /* No more nodes in the container left to traverse. */
2644 __ao2_ref(prev, -1);
2650 * \brief Cleanup the hash container traversal state.
2653 * \param state Traversal state to cleanup.
2657 static void hash_ao2_find_cleanup(struct hash_traversal_state *state)
2659 if (state->first_node) {
2660 __ao2_ref(state->first_node, -1);
2666 * \brief Find the next non-empty iteration node in the container.
2669 * \param self Container to operate upon.
2670 * \param node Previous node returned by the iterator.
2671 * \param flags search_flags to control iterating the container.
2672 * Only AO2_ITERATOR_DESCENDING is useful by the method.
2674 * \note The container is already locked.
2676 * \retval node on success.
2677 * \retval NULL on error or no more nodes in the container.
2679 static struct hash_bucket_node *hash_ao2_iterator_next(struct ao2_container_hash *self, struct hash_bucket_node *node, enum ao2_iterator_flags flags)
2683 if (flags & AO2_ITERATOR_DESCENDING) {
2685 cur_bucket = node->my_bucket;
2687 /* Find next non-empty node. */
2689 node = AST_DLLIST_PREV(node, links);
2693 if (node->common.obj) {
2694 /* Found a non-empty node. */
2699 /* Find first non-empty node. */
2700 cur_bucket = self->n_buckets;
2703 /* Find a non-empty node in the remaining buckets */
2704 while (0 <= --cur_bucket) {
2705 node = AST_DLLIST_LAST(&self->buckets[cur_bucket].list);
2707 if (node->common.obj) {
2708 /* Found a non-empty node. */
2711 node = AST_DLLIST_PREV(node, links);
2716 cur_bucket = node->my_bucket;
2718 /* Find next non-empty node. */
2720 node = AST_DLLIST_NEXT(node, links);
2724 if (node->common.obj) {
2725 /* Found a non-empty node. */
2730 /* Find first non-empty node. */
2734 /* Find a non-empty node in the remaining buckets */
2735 while (++cur_bucket < self->n_buckets) {
2736 node = AST_DLLIST_FIRST(&self->buckets[cur_bucket].list);
2738 if (node->common.obj) {
2739 /* Found a non-empty node. */
2742 node = AST_DLLIST_NEXT(node, links);
2747 /* No more nodes to visit in the container. */
2751 #if defined(AST_DEVMODE)
2754 * \brief Increment the hash container linked object statistic.
2757 * \param hash Container to operate upon.
2758 * \param hash_node Container node linking object to.
2762 static void hash_ao2_link_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node)
2764 struct ao2_container_hash *self = (struct ao2_container_hash *) hash;
2765 struct hash_bucket_node *node = (struct hash_bucket_node *) hash_node;
2766 int i = node->my_bucket;
2768 ++self->buckets[i].elements;
2769 if (self->buckets[i].max_elements < self->buckets[i].elements) {
2770 self->buckets[i].max_elements = self->buckets[i].elements;
2773 #endif /* defined(AST_DEVMODE) */
2775 #if defined(AST_DEVMODE)
2778 * \brief Decrement the hash container linked object statistic.
2781 * \param hash Container to operate upon.
2782 * \param hash_node Container node unlinking object from.
2786 static void hash_ao2_unlink_node_stat(struct ao2_container *hash, struct ao2_container_node *hash_node)
2788 struct ao2_container_hash *self = (struct ao2_container_hash *) hash;
2789 struct hash_bucket_node *node = (struct hash_bucket_node *) hash_node;
2791 --self->buckets[node->my_bucket].elements;
2793 #endif /* defined(AST_DEVMODE) */
2798 * \brief Destroy this container.
2801 * \param self Container to operate upon.
2805 static void hash_ao2_destroy(struct ao2_container_hash *self)
2809 /* Check that the container no longer has any nodes */
2810 for (idx = self->n_buckets; idx--;) {
2811 if (!AST_DLLIST_EMPTY(&self->buckets[idx].list)) {
2812 ast_log(LOG_ERROR, "Node ref leak. Hash container still has nodes!\n");
2819 #if defined(AST_DEVMODE)
2822 * \brief Display contents of the specified container.
2825 * \param self Container to dump.
2826 * \param where User data needed by prnt to determine where to put output.
2827 * \param prnt Print output callback function to use.
2828 * \param prnt_obj Callback function to print the given object's key. (NULL if not available)
2832 static void hash_ao2_dump(struct ao2_container_hash *self, void *where, ao2_prnt_fn *prnt, ao2_prnt_obj_fn *prnt_obj)
2834 #define FORMAT "%6s, %16s, %16s, %16s, %16s, %s\n"
2835 #define FORMAT2 "%6d, %16p, %16p, %16p, %16p, "
2838 int suppressed_buckets = 0;
2839 struct hash_bucket_node *node;
2841 prnt(where, "Number of buckets: %d\n\n", self->n_buckets);
2843 prnt(where, FORMAT, "Bucket", "Node", "Prev", "Next", "Obj", "Key");
2844 for (bucket = 0; bucket < self->n_buckets; ++bucket) {
2845 node = AST_DLLIST_FIRST(&self->buckets[bucket].list);
2847 suppressed_buckets = 0;
2849 prnt(where, FORMAT2,
2852 AST_DLLIST_PREV(node, links),
2853 AST_DLLIST_NEXT(node, links),
2855 if (node->common.obj && prnt_obj) {
2856 prnt_obj(node->common.obj, where, prnt);
2860 node = AST_DLLIST_NEXT(node, links);
2862 } else if (!suppressed_buckets) {
2863 suppressed_buckets = 1;
2864 prnt(where, "...\n");
2871 #endif /* defined(AST_DEVMODE) */
2873 #if defined(AST_DEVMODE)
2876 * \brief Display statistics of the specified container.
2879 * \param self Container to display statistics.
2880 * \param where User data needed by prnt to determine where to put output.
2881 * \param prnt Print output callback function to use.
2883 * \note The container is already locked for reading.
2887 static void hash_ao2_stats(struct ao2_container_hash *self, void *where, ao2_prnt_fn *prnt)
2889 #define FORMAT "%10.10s %10.10s %10.10s\n"
2890 #define FORMAT2 "%10d %10d %10d\n"
2893 int suppressed_buckets = 0;
2895 prnt(where, "Number of buckets: %d\n\n", self->n_buckets);
2897 prnt(where, FORMAT, "Bucket", "Objects", "Max");
2898 for (bucket = 0; bucket < self->n_buckets; ++bucket) {
2899 if (self->buckets[bucket].max_elements) {
2900 suppressed_buckets = 0;
2901 prnt(where, FORMAT2, bucket, self->buckets[bucket].elements,
2902 self->buckets[bucket].max_elements);
2903 } else if (!suppressed_buckets) {
2904 suppressed_buckets = 1;
2905 prnt(where, "...\n");
2912 #endif /* defined(AST_DEVMODE) */
2914 #if defined(AST_DEVMODE)
2917 * \brief Perform an integrity check on the specified container.
2920 * \param self Container to check integrity.
2922 * \note The container is already locked for reading.
2924 * \retval 0 on success.
2925 * \retval -1 on error.
2927 static int hash_ao2_integrity(struct ao2_container_hash *self)
2932 int count_total_obj;
2933 int count_total_node;
2935 struct hash_bucket_node *node;
2936 struct hash_bucket_node *prev;
2937 struct hash_bucket_node *next;
2939 count_total_obj = 0;
2940 count_total_node = 0;
2942 /* For each bucket in the container. */
2943 for (bucket = 0; bucket < self->n_buckets; ++bucket) {
2944 if (!AST_DLLIST_FIRST(&self->buckets[bucket].list)
2945 && !AST_DLLIST_LAST(&self->buckets[bucket].list)) {
2946 /* The bucket list is empty. */
2953 /* Check bucket list links and nodes. */
2954 node = AST_DLLIST_LAST(&self->buckets[bucket].list);
2956 ast_log(LOG_ERROR, "Bucket %d list tail is NULL when it should not be!\n",
2960 if (AST_DLLIST_NEXT(node, links)) {
2961 ast_log(LOG_ERROR, "Bucket %d list tail node is not the last node!\n",
2965 node = AST_DLLIST_FIRST(&self->buckets[bucket].list);
2967 ast_log(LOG_ERROR, "Bucket %d list head is NULL when it should not be!\n",
2971 if (AST_DLLIST_PREV(node, links)) {
2972 ast_log(LOG_ERROR, "Bucket %d list head node is not the first node!\n",
2976 for (; node; node = next) {
2977 /* Check backward link. */
2978 prev = AST_DLLIST_PREV(node, links);
2981 ast_log(LOG_ERROR, "Bucket %d list node's prev pointer points to itself!\n",
2985 if (node != AST_DLLIST_NEXT(prev, links)) {
2986 ast_log(LOG_ERROR, "Bucket %d list node's prev node does not link back!\n",
2990 } else if (node != AST_DLLIST_FIRST(&self->buckets[bucket].list)) {
2991 ast_log(LOG_ERROR, "Bucket %d backward list chain is broken!\n",
2996 /* Check forward link. */
2997 next = AST_DLLIST_NEXT(node, links);
3000 ast_log(LOG_ERROR, "Bucket %d list node's next pointer points to itself!\n",
3004 if (node != AST_DLLIST_PREV(next, links)) {
3005 ast_log(LOG_ERROR, "Bucket %d list node's next node does not link back!\n",
3009 } else if (node != AST_DLLIST_LAST(&self->buckets[bucket].list)) {
3010 ast_log(LOG_ERROR, "Bucket %d forward list chain is broken!\n",
3015 if (bucket != node->my_bucket) {
3016 ast_log(LOG_ERROR, "Bucket %d node claims to be in bucket %d!\n",
3017 bucket, node->my_bucket);
3022 if (!node->common.obj) {
3023 /* Node is empty. */
3028 /* Check container hash key for expected bucket. */
3029 bucket_exp = abs(self->hash_fn(node->common.obj, OBJ_POINTER));
3030 bucket_exp %= self->n_buckets;
3031 if (bucket != bucket_exp) {
3032 ast_log(LOG_ERROR, "Bucket %d node hashes to bucket %d!\n",
3033 bucket, bucket_exp);
3037 /* Check sort if configured. */
3038 if (self->common.sort_fn) {
3040 && self->common.sort_fn(obj_last, node->common.obj, OBJ_POINTER) > 0) {
3041 ast_log(LOG_ERROR, "Bucket %d nodes out of sorted order!\n",
3045 obj_last = node->common.obj;
3049 /* Check bucket obj count statistic. */
3050 if (count_obj != self->buckets[bucket].elements) {
3051 ast_log(LOG_ERROR, "Bucket %d object count of %d does not match stat of %d!\n",
3052 bucket, count_obj, self->buckets[bucket].elements);
3056 /* Accumulate found object counts. */
3057 count_total_obj += count_obj;
3060 /* Check total obj count. */
3061 if (count_total_obj != ao2_container_count(&self->common)) {
3063 "Total object count of %d does not match ao2_container_count() of %d!\n",
3064 count_total_obj, ao2_container_count(&self->common));
3068 /* Check total node count. */
3069 if (count_total_node != self->common.nodes) {
3070 ast_log(LOG_ERROR, "Total node count of %d does not match stat of %d!\n",
3071 count_total_node, self->common.nodes);
3077 #endif /* defined(AST_DEVMODE) */
3079 /*! Hash container virtual method table. */
3080 static const struct ao2_container_methods v_table_hash = {
3081 .type = AO2_CONTAINER_RTTI_HASH,
3082 .alloc_empty_clone = (ao2_container_alloc_empty_clone_fn) hash_ao2_alloc_empty_clone,
3083 .alloc_empty_clone_debug =
3084 (ao2_container_alloc_empty_clone_debug_fn) hash_ao2_alloc_empty_clone_debug,
3085 .new_node = (ao2_container_new_node_fn) hash_ao2_new_node,
3086 .insert = (ao2_container_insert_fn) hash_ao2_insert_node,
3087 .traverse_first = (ao2_container_find_first_fn) hash_ao2_find_first,
3088 .traverse_next = (ao2_container_find_next_fn) hash_ao2_find_next,
3089 .traverse_cleanup = (ao2_container_find_cleanup_fn) hash_ao2_find_cleanup,
3090 .iterator_next = (ao2_iterator_next_fn) hash_ao2_iterator_next,
3091 .destroy = (ao2_container_destroy_fn) hash_ao2_destroy,
3092 #if defined(AST_DEVMODE)
3093 .dump = (ao2_container_display) hash_ao2_dump,
3094 .stats = (ao2_container_statistics) hash_ao2_stats,
3095 .integrity = (ao2_container_integrity) hash_ao2_integrity,
3096 #endif /* defined(AST_DEVMODE) */
3100 * \brief always zero hash function
3102 * it is convenient to have a hash function that always returns 0.
3103 * This is basically used when we want to have a container that is
3104 * a simple linked list.
3108 static int hash_zero(const void *user_obj, const int flags)
3114 * \brief Initialize a hash container with the desired number of buckets.
3116 * \param self Container to initialize.
3117 * \param options Container behaviour options (See enum ao2_container_opts)
3118 * \param n_buckets Number of buckets for hash
3119 * \param hash_fn Pointer to a function computing a hash value.
3120 * \param sort_fn Pointer to a sort function.
3121 * \param cmp_fn Pointer to a compare function used by ao2_find.
3123 * \return A pointer to a struct container.
3125 static struct ao2_container *hash_ao2_container_init(
3126 struct ao2_container_hash *self, unsigned int options, unsigned int n_buckets,
3127 ao2_hash_fn *hash_fn, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
3133 self->common.v_table = &v_table_hash;
3134 self->common.sort_fn = sort_fn;
3135 self->common.cmp_fn = cmp_fn;
3136 self->common.options = options;
3137 self->hash_fn = hash_fn ? hash_fn : hash_zero;
3138 self->n_buckets = n_buckets;
3141 ast_atomic_fetchadd_int(&ao2.total_containers, 1);
3144 return (struct ao2_container *) self;
3147 struct ao2_container *__ao2_container_alloc_hash(unsigned int ao2_options,
3148 unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
3149 ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)
3151 unsigned int num_buckets;
3152 size_t container_size;
3153 struct ao2_container_hash *self;
3155 num_buckets = hash_fn ? n_buckets : 1;
3156 container_size = sizeof(struct ao2_container_hash) + num_buckets * sizeof(struct hash_bucket);
3158 self = ao2_t_alloc_options(container_size, container_destruct, ao2_options,
3159 "New hash container");
3160 return hash_ao2_container_init(self, container_options, num_buckets,
3161 hash_fn, sort_fn, cmp_fn);
3164 struct ao2_container *__ao2_container_alloc_hash_debug(unsigned int ao2_options,
3165 unsigned int container_options, unsigned int n_buckets, ao2_hash_fn *hash_fn,
3166 ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn,
3167 const char *tag, const char *file, int line, const char *func, int ref_debug)
3169 unsigned int num_buckets;
3170 size_t container_size;
3171 struct ao2_container_hash *self;
3173 num_buckets = hash_fn ? n_buckets : 1;
3174 container_size = sizeof(struct ao2_container_hash) + num_buckets * sizeof(struct hash_bucket);
3176 self = __ao2_alloc_debug(container_size, container_destruct_debug, ao2_options,
3177 tag, file, line, func, ref_debug);
3178 return hash_ao2_container_init(self, container_options, num_buckets, hash_fn,
3182 struct ao2_container *__ao2_container_alloc_list(unsigned int ao2_options,
3183 unsigned int container_options, ao2_sort_fn *sort_fn, ao2_callback_fn *cmp_fn)