Asterisk - The Open Source Telephony Project  GIT-master-e8cda4b
Functions
astobj2_container.c File Reference

Functions implementing astobj2 objects. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/astobj2.h"
#include "astobj2_private.h"
#include "astobj2_container_private.h"
#include "asterisk/cli.h"

Go to the source code of this file.

Functions

void * __ao2_callback (struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg, const char *tag, const char *file, int line, const char *func)
 
void * __ao2_callback_data (struct ao2_container *c, enum search_flags flags, ao2_callback_data_fn *cb_fn, void *arg, void *data, const char *tag, const char *file, int line, const char *func)
 
struct ao2_container__ao2_container_clone (struct ao2_container *orig, enum search_flags flags, const char *tag, const char *file, int line, const char *func)
 Create a clone/copy of the given container. More...
 
void * __ao2_find (struct ao2_container *c, const void *arg, enum search_flags flags, const char *tag, const char *file, int line, const char *func)
 
void * __ao2_iterator_next (struct ao2_iterator *iter, const char *tag, const char *file, int line, const char *func)
 
int __ao2_link (struct ao2_container *self, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
 
void * __ao2_unlink (struct ao2_container *c, void *user_data, int flags, const char *tag, const char *file, int line, const char *func)
 
void * __ao2_weakproxy_find (struct ao2_container *c, const void *arg, enum search_flags flags, const char *tag, const char *file, int line, const char *func)
 
int __container_unlink_node_debug (struct ao2_container_node *node, uint32_t flags, const char *tag, const char *file, int line, const char *func)
 
int ao2_container_check (struct ao2_container *self, enum search_flags flags)
 Perform an integrity check on the specified container. More...
 
int ao2_container_count (struct ao2_container *c)
 Returns the number of elements in a container. More...
 
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)
 Display contents of the specified container. More...
 
int ao2_container_dup (struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
 Copy all object references in the src container into the dest container. More...
 
int ao2_container_dup_weakproxy_objs (struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
 Copy object references associated with src container weakproxies into the dest container. More...
 
int ao2_container_register (const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj)
 Register a container for CLI stats and integrity check. More...
 
void ao2_container_stats (struct ao2_container *self, enum search_flags flags, const char *name, void *where, ao2_prnt_fn *prnt)
 Display statistics of the specified container. More...
 
void ao2_container_unregister (const char *name)
 Unregister a container for CLI stats and integrity check. More...
 
void ao2_iterator_cleanup (struct ao2_iterator *iter)
 
int ao2_iterator_count (struct ao2_iterator *iter)
 Get a count of the iterated container objects. More...
 
void ao2_iterator_destroy (struct ao2_iterator *iter)
 Destroy a container iterator. More...
 
struct ao2_iterator ao2_iterator_init (struct ao2_container *c, int flags)
 Create an iterator for a container. More...
 
void ao2_iterator_restart (struct ao2_iterator *iter)
 Restart an iteration. More...
 
int ao2_match_by_addr (void *user_data, void *arg, int flags)
 another convenience function is a callback that matches on address More...
 
static int cb_true (void *user_data, void *arg, int flags)
 special callback that matches all More...
 
static int cb_true_data (void *user_data, void *arg, void *data, int flags)
 similar to cb_true, but is an ao2_callback_data_fn instead More...
 
void container_destruct (void *_c)
 
int container_init (void)
 
static int dup_obj_cb (void *obj, void *arg, int flags)
 
static int dup_weakproxy_cb (void *proxy, void *arg, int flags)
 Copy obj associated with a weakproxy into the arg container. More...
 
static void * internal_ao2_traverse (struct ao2_container *self, enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type, const char *tag, const char *file, int line, const char *func)
 

Detailed Description

Functions implementing astobj2 objects.

Author
Richard Mudgett rmudg.nosp@m.ett@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Definition in file astobj2_container.c.

Function Documentation

◆ __ao2_callback()

void* __ao2_callback ( struct ao2_container c,
enum search_flags  flags,
ao2_callback_fn cb_fn,
void *  arg,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Definition at line 410 of file astobj2_container.c.

References AO2_CALLBACK_DEFAULT, internal_ao2_traverse(), and NULL.

Referenced by __ao2_find(), __ao2_unlink(), and __find_call().

413 {
414  return internal_ao2_traverse(c, flags, cb_fn, arg, NULL, AO2_CALLBACK_DEFAULT, tag, file, line, func);
415 }
#define NULL
Definition: resample.c:96
static void * internal_ao2_traverse(struct ao2_container *self, enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type, const char *tag, const char *file, int line, const char *func)

◆ __ao2_callback_data()

void* __ao2_callback_data ( struct ao2_container c,
enum search_flags  flags,
ao2_callback_data_fn cb_fn,
void *  arg,
void *  data,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Definition at line 417 of file astobj2_container.c.

References AO2_CALLBACK_WITH_DATA, and internal_ao2_traverse().

420 {
421  return internal_ao2_traverse(c, flags, cb_fn, arg, data, AO2_CALLBACK_WITH_DATA, tag, file, line, func);
422 }
static void * internal_ao2_traverse(struct ao2_container *self, enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type, const char *tag, const char *file, int line, const char *func)

◆ __ao2_container_clone()

struct ao2_container* __ao2_container_clone ( struct ao2_container orig,
enum search_flags  flags,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Create a clone/copy of the given container.

Since
11.0
Parameters
origContainer to copy all object references from.
flagsOBJ_NOLOCK if a lock is already held on the container.
Note
This can potentially be expensive because a malloc is needed for every object in the orig container.
Return values
Clonecontainer on success.
NULLon error.

Definition at line 753 of file astobj2_container.c.

References __ao2_ref(), __ast_assert_failed(), __is_ao2_object, ao2_container_methods::alloc_empty_clone, ao2_container_dup(), ao2_unlock, ao2_wrlock, NULL, OBJ_NOLOCK, and ao2_container::v_table.

754 {
755  struct ao2_container *clone;
756  int failed;
757 
758  /* Create the clone container with the same properties as the original. */
759  if (!__is_ao2_object(orig, file, line, func)) {
760  return NULL;
761  }
762 
763  if (!orig->v_table || !orig->v_table->alloc_empty_clone) {
764  /* Sanity checks. */
765  __ast_assert_failed(0, "invalid container v_table", file, line, func);
766  return NULL;
767  }
768 
769  clone = orig->v_table->alloc_empty_clone(orig, tag, file, line, func);
770  if (!clone) {
771  return NULL;
772  }
773 
774  /* This test is correct. clone must be locked before calling
775  * ao2_container_dup when the OBJ_NOLOCK flag is set, otherwise
776  * we could have errors in __adjust_lock. */
777  if (flags & OBJ_NOLOCK) {
778  ao2_wrlock(clone);
779  }
780  failed = ao2_container_dup(clone, orig, flags);
781  if (flags & OBJ_NOLOCK) {
782  ao2_unlock(clone);
783  }
784  if (failed) {
785  /* Object copy into the clone container failed. */
786  __ao2_ref(clone, -1, tag ?: "Clone creation failed", file, line, func);
787  clone = NULL;
788  }
789  return clone;
790 }
#define __is_ao2_object(user_data, file, line, func)
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ao2_wrlock(a)
Definition: astobj2.h:720
int __ao2_ref(void *o, int delta, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:498
const struct ao2_container_methods * v_table
void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function)
Definition: main/utils.c:2564
Generic container type.
ao2_container_alloc_empty_clone_fn alloc_empty_clone
Create an empty copy of this container.
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.

◆ __ao2_find()

void* __ao2_find ( struct ao2_container c,
const void *  arg,
enum search_flags  flags,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

the find function just invokes the default callback with some reasonable flags.

Definition at line 427 of file astobj2_container.c.

References __ao2_callback(), ast_assert, ao2_container::cmp_fn, and NULL.

Referenced by __ast_format_cache_get(), __find_call(), and _get_mohbyname().

429 {
430  void *arged = (void *) arg;/* Done to avoid compiler const warning */
431 
432  if (!c) {
433  /* Sanity checks. */
434  ast_assert(0);
435  return NULL;
436  }
437  return __ao2_callback(c, flags, c->cmp_fn, arged, tag, file, line, func);
438 }
void * __ao2_callback(struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg, const char *tag, const char *file, int line, const char *func)
#define ast_assert(a)
Definition: utils.h:710
#define NULL
Definition: resample.c:96
ao2_callback_fn * cmp_fn

◆ __ao2_iterator_next()

void* __ao2_iterator_next ( struct ao2_iterator iter,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Definition at line 556 of file astobj2_container.c.

References __adjust_lock(), __ao2_ref(), __ast_assert_failed(), __container_unlink_node_debug(), __is_ao2_object, AO2_ITERATOR_DONTLOCK, AO2_ITERATOR_UNLINK, AO2_LOCK_REQ_MUTEX, AO2_LOCK_REQ_RDLOCK, AO2_LOCK_REQ_WRLOCK, ao2_rdlock, ao2_ref, AO2_UNLINK_NODE_DEC_COUNT, ao2_unlock, ao2_wrlock, ao2_iterator::c, ao2_iterator::complete, ao2_iterator::flags, ao2_container_methods::iterator_next, ao2_iterator::last_node, NULL, ao2_container_node::obj, and ao2_container::v_table.

558 {
559  enum ao2_lock_req orig_lock;
560  struct ao2_container_node *node;
561  void *ret;
562 
563  if (!__is_ao2_object(iter->c, file, line, func)) {
564  return NULL;
565  }
566 
567  if (!iter->c->v_table || !iter->c->v_table->iterator_next) {
568  /* Sanity checks. */
569  __ast_assert_failed(0, "invalid iterator container v_table", file, line, func);
570  return NULL;
571  }
572 
573  if (iter->complete) {
574  /* Don't return any more objects. */
575  return NULL;
576  }
577 
578  if (iter->flags & AO2_ITERATOR_DONTLOCK) {
579  if (iter->flags & AO2_ITERATOR_UNLINK) {
580  orig_lock = __adjust_lock(iter->c, AO2_LOCK_REQ_WRLOCK, 1);
581  } else {
582  orig_lock = __adjust_lock(iter->c, AO2_LOCK_REQ_RDLOCK, 1);
583  }
584  } else {
585  orig_lock = AO2_LOCK_REQ_MUTEX;
586  if (iter->flags & AO2_ITERATOR_UNLINK) {
587  ao2_wrlock(iter->c);
588  } else {
589  ao2_rdlock(iter->c);
590  }
591  }
592 
593  node = iter->c->v_table->iterator_next(iter->c, iter->last_node, iter->flags);
594  if (node) {
595  ret = node->obj;
596 
597  if (iter->flags & AO2_ITERATOR_UNLINK) {
598  /* Transfer the object ref from the container to the returned object. */
600 
601  /* Transfer the container's node ref to the iterator. */
602  } else {
603  /* Bump ref of returned object */
604  __ao2_ref(ret, +1, tag ?: "Next iterator object.", file, line, func);
605 
606  /* Bump the container's node ref for the iterator. */
607  ao2_ref(node, +1);
608  }
609  } else {
610  /* The iteration has completed. */
611  iter->complete = 1;
612  ret = NULL;
613  }
614 
615  /* Replace the iterator's node */
616  if (iter->last_node) {
617  ao2_ref(iter->last_node, -1);
618  }
619  iter->last_node = node;
620 
621  if (iter->flags & AO2_ITERATOR_DONTLOCK) {
622  __adjust_lock(iter->c, orig_lock, 0);
623  } else {
624  ao2_unlock(iter->c);
625  }
626 
627  return ret;
628 }
Definition: test_heap.c:38
int __container_unlink_node_debug(struct ao2_container_node *node, uint32_t flags, const char *tag, const char *file, int line, const char *func)
void * last_node
Definition: astobj2.h:1845
#define __is_ao2_object(user_data, file, line, func)
ao2_lock_req
Which lock to request.
Definition: astobj2.h:701
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ao2_wrlock(a)
Definition: astobj2.h:720
int complete
Definition: astobj2.h:1847
struct ao2_container * c
Definition: astobj2.h:1843
Generic container node.
int __ao2_ref(void *o, int delta, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:498
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const struct ao2_container_methods * v_table
void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function)
Definition: main/utils.c:2564
ao2_iterator_next_fn iterator_next
#define ao2_rdlock(a)
Definition: astobj2.h:719
Assume that the ao2_container is already locked.
Definition: astobj2.h:1872
enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
Definition: astobj2.c:425

◆ __ao2_link()

int __ao2_link ( struct ao2_container self,
void *  obj_new,
int  flags,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Definition at line 94 of file astobj2_container.c.

References __adjust_lock(), __ast_assert_failed(), __is_ao2_object, ao2_container_check(), AO2_CONTAINER_INSERT_NODE_INSERTED, AO2_CONTAINER_INSERT_NODE_OBJ_REPLACED, AO2_CONTAINER_INSERT_NODE_REJECTED, AO2_DEVMODE_STAT, AO2_LOCK_REQ_MUTEX, AO2_LOCK_REQ_WRLOCK, ao2_ref, ao2_unlock, ao2_wrlock, ast_atomic_fetchadd_int(), ast_log, ao2_container_node::is_linked, LOG_ERROR, and OBJ_NOLOCK.

Referenced by internal_ao2_traverse().

96 {
97  int res;
98  enum ao2_lock_req orig_lock;
99  struct ao2_container_node *node;
100 
101  if (!__is_ao2_object(obj_new, file, line, func)
102  || !__is_ao2_object(self, file, line, func)) {
103  return 0;
104  }
105 
106  if (!self->v_table || !self->v_table->new_node || !self->v_table->insert) {
107  /* Sanity checks. */
108  __ast_assert_failed(0, "invalid container v_table", file, line, func);
109  return 0;
110  }
111 
112  if (flags & OBJ_NOLOCK) {
113  orig_lock = __adjust_lock(self, AO2_LOCK_REQ_WRLOCK, 1);
114  } else {
115  ao2_wrlock(self);
116  orig_lock = AO2_LOCK_REQ_MUTEX;
117  }
118 
119  res = 0;
120  node = self->v_table->new_node(self, obj_new, tag, file, line, func);
121  if (node) {
122 #if defined(AO2_DEBUG)
123  if (ao2_container_check(self, OBJ_NOLOCK)) {
124  ast_log(LOG_ERROR, "Container integrity failed before insert.\n");
125  }
126 #endif /* defined(AO2_DEBUG) */
127 
128  /* Insert the new node. */
129  switch (self->v_table->insert(self, node)) {
131  node->is_linked = 1;
133 #if defined(AO2_DEBUG)
134  AO2_DEVMODE_STAT(++self->nodes);
135  if (self->v_table->link_stat) {
136  self->v_table->link_stat(self, node);
137  }
138 #endif /* defined(AO2_DEBUG) */
139  /* Fall through */
141 #if defined(AO2_DEBUG)
142  if (ao2_container_check(self, OBJ_NOLOCK)) {
143  ast_log(LOG_ERROR, "Container integrity failed after insert or replace.\n");
144  }
145 #endif /* defined(AO2_DEBUG) */
146  res = 1;
147  break;
149  ao2_ref(node, -1);
150  break;
151  }
152  }
153 
154  if (flags & OBJ_NOLOCK) {
155  __adjust_lock(self, orig_lock, 0);
156  } else {
157  ao2_unlock(self);
158  }
159 
160  return res;
161 }
Definition: test_heap.c:38
#define __is_ao2_object(user_data, file, line, func)
ao2_lock_req
Which lock to request.
Definition: astobj2.h:701
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ao2_unlock(a)
Definition: astobj2.h:730
int ao2_container_check(struct ao2_container *self, enum search_flags flags)
Perform an integrity check on the specified container.
#define ao2_wrlock(a)
Definition: astobj2.h:720
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
Generic container node.
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const struct ao2_container_methods * v_table
#define AO2_DEVMODE_STAT(stat)
void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function)
Definition: main/utils.c:2564
#define LOG_ERROR
Definition: logger.h:285
ao2_container_insert_fn insert
enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
Definition: astobj2.c:425
ao2_container_new_node_fn new_node

◆ __ao2_unlink()

void* __ao2_unlink ( struct ao2_container c,
void *  user_data,
int  flags,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Definition at line 175 of file astobj2_container.c.

References __ao2_callback(), __is_ao2_object, ao2_match_by_addr(), NULL, OBJ_NODATA, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and OBJ_UNLINK.

177 {
178  if (!__is_ao2_object(user_data, file, line, func)) {
179  /* Sanity checks. */
180  return NULL;
181  }
182 
183  flags &= ~OBJ_SEARCH_MASK;
184  flags |= (OBJ_UNLINK | OBJ_SEARCH_OBJECT | OBJ_NODATA);
185  __ao2_callback(c, flags, ao2_match_by_addr, user_data, tag, file, line, func);
186 
187  return NULL;
188 }
#define __is_ao2_object(user_data, file, line, func)
void * __ao2_callback(struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg, const char *tag, const char *file, int line, const char *func)
#define NULL
Definition: resample.c:96
int ao2_match_by_addr(void *user_data, void *arg, int flags)
another convenience function is a callback that matches on address
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
Search option field mask.
Definition: astobj2.h:1076

◆ __ao2_weakproxy_find()

void* __ao2_weakproxy_find ( struct ao2_container c,
const void *  arg,
enum search_flags  flags,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Definition at line 440 of file astobj2_container.c.

References __adjust_lock(), __ao2_weakproxy_get_object(), ao2_find, AO2_LOCK_REQ_RDLOCK, AO2_LOCK_REQ_WRLOCK, ao2_rdlock, ao2_ref, ao2_unlink_flags, ao2_unlock, ast_assert, NULL, OBJ_NOLOCK, and OBJ_SEARCH_MASK.

Referenced by __ast_named_lock_get(), and __ast_sorcery_open().

442 {
443  void *proxy;
444  void *obj = NULL;
445  enum ao2_lock_req orig_lock;
446 
447  ast_assert(!!c);
448  ast_assert(flags & OBJ_SEARCH_MASK);
449  ast_assert(!(flags & ~(OBJ_SEARCH_MASK | OBJ_NOLOCK)));
450 
451  if (flags & OBJ_NOLOCK) {
452  orig_lock = __adjust_lock(c, AO2_LOCK_REQ_RDLOCK, 1);
453  } else {
454  orig_lock = AO2_LOCK_REQ_RDLOCK;
455  ao2_rdlock(c);
456  }
457 
458  while ((proxy = ao2_find(c, arg, flags | OBJ_NOLOCK))) {
459  obj = __ao2_weakproxy_get_object(proxy, 0, tag ?: __PRETTY_FUNCTION__, file, line, func);
460 
461  if (obj) {
462  ao2_ref(proxy, -1);
463  break;
464  }
465 
466  /* Upgrade to a write lock */
468  ao2_unlink_flags(c, proxy, OBJ_NOLOCK);
469  ao2_ref(proxy, -1);
470  }
471 
472  if (flags & OBJ_NOLOCK) {
473  /* We'll keep any upgraded lock */
474  __adjust_lock(c, orig_lock, 1);
475  } else {
476  ao2_unlock(c);
477  }
478 
479  return obj;
480 }
ao2_lock_req
Which lock to request.
Definition: astobj2.h:701
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ast_assert(a)
Definition: utils.h:710
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ao2_ref(o, delta)
Definition: astobj2.h:464
void * __ao2_weakproxy_get_object(void *weakproxy, int flags, const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result
Get the object associated with weakproxy.
Definition: astobj2.c:886
#define ao2_rdlock(a)
Definition: astobj2.h:719
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
Definition: astobj2.c:425
#define ao2_unlink_flags(container, obj, flags)
Definition: astobj2.h:1622
Search option field mask.
Definition: astobj2.h:1076

◆ __container_unlink_node_debug()

int __container_unlink_node_debug ( struct ao2_container_node node,
uint32_t  flags,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Definition at line 39 of file astobj2_container.c.

References __ao2_ref(), ao2_ref, AO2_UNLINK_NODE_DEC_COUNT, AO2_UNLINK_NODE_NOUNREF_OBJECT, AO2_UNLINK_NODE_UNLINK_OBJECT, AO2_UNLINK_NODE_UNREF_NODE, ast_atomic_fetchadd_int(), container, ao2_container::elements, ao2_container_node::my_container, NULL, ao2_container_node::obj, and ao2_container::v_table.

Referenced by __ao2_iterator_next(), and internal_ao2_traverse().

41 {
42  struct ao2_container *container = node->my_container;
43 
44  if (container == NULL && (flags & AO2_UNLINK_NODE_DEC_COUNT)) {
45  return 0;
46  }
47 
48  if ((flags & AO2_UNLINK_NODE_UNLINK_OBJECT)
49  && !(flags & AO2_UNLINK_NODE_NOUNREF_OBJECT)) {
50  __ao2_ref(node->obj, -1, tag ?: "Remove obj from container", file, line, func);
51  }
52 
53  node->obj = NULL;
54 
55  if (flags & AO2_UNLINK_NODE_DEC_COUNT) {
56  ast_atomic_fetchadd_int(&container->elements, -1);
57 #if defined(AO2_DEBUG)
58  {
59  int empty = container->nodes - container->elements;
60 
61  if (container->max_empty_nodes < empty) {
62  container->max_empty_nodes = empty;
63  }
64  if (container->v_table->unlink_stat) {
65  container->v_table->unlink_stat(container, node);
66  }
67  }
68 #endif /* defined(AO2_DEBUG) */
69  }
70 
71  if (flags & AO2_UNLINK_NODE_UNREF_NODE) {
72  /* Remove node from container */
73  ao2_ref(node, -1);
74  }
75 
76  return 1;
77 }
#define NULL
Definition: resample.c:96
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
int __ao2_ref(void *o, int delta, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:498
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const struct ao2_container_methods * v_table
struct ao2_container * container
Definition: res_fax.c:502
Generic container type.
struct ao2_container * my_container

◆ ao2_container_check()

int ao2_container_check ( struct ao2_container self,
enum search_flags  flags 
)

Perform an integrity check on the specified container.

Since
12.0.0
Parameters
selfContainer to check integrity.
flagsOBJ_NOLOCK if a lock is already held on the container.
Return values
0on success.
-1on error.

Definition at line 856 of file astobj2_container.c.

References ao2_rdlock, ao2_t_ref, ao2_unlock, ast_assert, is_ao2_object, len(), name, OBJ_NOLOCK, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and OBJ_SEARCH_PARTIAL_KEY.

Referenced by __ao2_link(), ao2_container_unregister(), AST_TEST_DEFINE(), astobj2_test_1_helper(), hash_ao2_node_destructor(), insert_test_duplicates(), insert_test_vector(), rb_ao2_node_destructor(), and test_container_clone().

857 {
858  int res = 0;
859 
860  if (!is_ao2_object(self) || !self->v_table) {
861  /* Sanity checks. */
862  ast_assert(0);
863  return -1;
864  }
865 #if defined(AO2_DEBUG)
866  if (!self->v_table->integrity) {
867  /* No ingetrigy check available. Assume container is ok. */
868  return 0;
869  }
870 
871  if (!(flags & OBJ_NOLOCK)) {
872  ao2_rdlock(self);
873  }
874  res = self->v_table->integrity(self);
875  if (!(flags & OBJ_NOLOCK)) {
876  ao2_unlock(self);
877  }
878 #endif /* defined(AO2_DEBUG) */
879  return res;
880 }
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ast_assert(a)
Definition: utils.h:710
#define ao2_unlock(a)
Definition: astobj2.h:730
#define is_ao2_object(user_data)
const struct ao2_container_methods * v_table
#define ao2_rdlock(a)
Definition: astobj2.h:719

◆ ao2_container_count()

int ao2_container_count ( struct ao2_container c)

Returns the number of elements in a container.

return the number of elements in the container

Definition at line 34 of file astobj2_container.c.

References ast_atomic_fetchadd_int(), and ao2_container::elements.

Referenced by _sip_show_peers(), action_confbridgekick(), action_confbridgelist(), action_confbridgelistrooms(), action_confbridgesetsinglevideosrc(), action_confbridgestartrecord(), action_confbridgestoprecord(), action_lock_unlock_helper(), action_mute_unmute_helper(), aeap_server_show_all(), ami_show_aors(), ami_show_auths(), ami_show_contacts(), ami_show_endpoints(), ami_show_resource_lists(), ao2_iterator_count(), ao2_weakproxy_unsubscribe(), app_is_finished(), ari_show(), ast_active_channels(), ast_ari_applications_list(), ast_bridge_transfer_attended(), ast_bridge_transfer_blind(), ast_cdr_generic_unregister(), ast_endpoint_snapshot_create(), ast_get_chan_applicationmap(), ast_get_namedgroups(), ast_merge_contexts_and_delete(), ast_namedgroups_intersect(), ast_sip_cli_traverse_objects(), ast_sip_initialize_system(), ast_sip_location_retrieve_first_aor_contact_filtered(), ast_sorcery_create(), ast_sorcery_delete(), ast_sorcery_retrieve_by_fields(), ast_sorcery_retrieve_by_prefix(), ast_sorcery_retrieve_by_regex(), ast_sorcery_update(), ast_srtp_unprotect(), AST_TEST_DEFINE(), ast_tone_zone_count(), astobj2_test_1_helper(), auth_observer(), bridges_scrape_cb(), calc_metric(), cc_cli_output_status(), cel_pre_apply_config(), channels_scrape_cb(), check_events(), check_expiration_thread(), cleanup(), cleanup_module(), cli_display_parking_lot(), cli_fax_show_sessions(), cli_show_modules(), cli_show_tasks(), common_identify(), control_command_count(), control_wait(), cpg_confchg_cb(), create_sound_blob(), create_unsolicited_mwi_subscriptions(), device_state_cb(), dial_state_process_bridge_enter(), do_timing(), endelm(), endpoints_scrape_cb(), exten_state_pub_data_alloc(), format_ami_aor_handler(), get_device_state_causing_channels(), global_loaded_observer(), grow(), handle_cli_sound_show(), handle_feature_show(), handle_manager_show_events(), handle_registrations(), handle_show_hint(), handle_show_hints(), hash_ao2_destroy(), insert_test_vector(), ip_identify_apply(), locals_show(), match_filter(), member_add_to_queue(), memory_cache_full_update(), memory_cache_populate(), mid_test_sync(), mwi_subscription_established(), native_bridge_is_capable(), native_rtp_bridge_compatible_check(), object_type_loaded_observer(), one_protocol(), parking_lot_remove_if_unused(), pjsip_acf_dial_contacts_read(), presence_state_cb(), print_queue(), process_config(), pthread_timer_open(), publisher_start(), queue_exec(), queue_function_mem_read(), queued_set_size(), queued_task_pushed(), rb_ao2_destroy(), register_aor_core(), send_unsolicited_mwi_notify(), shrink(), single_state_process_bridge_enter(), sip_options_apply_aor_configuration(), sip_options_contact_add_task(), sip_options_contact_delete_task(), sip_options_unused_endpoint_state_compositor(), sip_send_all_registers(), sip_show_objects(), sla_in_use(), smdi_load(), sorcery_memory_cache_ami_populate(), sorcery_memory_cache_create(), sorcery_memory_cache_dump(), sorcery_memory_cache_populate(), sorcery_memory_cache_retrieve_multiple(), sorcery_memory_cache_retrieve_prefix(), sorcery_memory_cache_retrieve_regex(), sorcery_memory_cache_show(), sorcery_object_load(), stale_cache_update(), stasis_app_set_global_debug(), stasis_app_to_cli(), stir_shaken_certificate_show_all(), stir_shaken_general_get(), system_create_resolver_and_set_nameservers(), test_ao2_iteration(), test_cel_peer_strings_match(), test_container_clone(), test_sub(), threadpool_send_state_changed(), try_calling(), unload_module(), and xmpp_show_clients().

35 {
36  return ast_atomic_fetchadd_int(&c->elements, 0);
37 }
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755

◆ ao2_container_dump()

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 
)

Display contents of the specified container.

Since
12.0.0
Parameters
selfContainer to dump.
flagsOBJ_NOLOCK if a lock is already held on the container.
nameContainer name. (NULL if anonymous)
whereUser data needed by prnt to determine where to put output.
prntPrint output callback function to use.
prnt_objCallback function to print the given object's key. (NULL if not available)
Returns
Nothing

Definition at line 792 of file astobj2_container.c.

References ao2_rdlock, ao2_unlock, ast_assert, is_ao2_object, and OBJ_NOLOCK.

Referenced by ao2_container_unregister(), astobj2_test_1_helper(), and test_traversal_sorted().

793 {
794  if (!is_ao2_object(self) || !self->v_table) {
795  prnt(where, "Invalid container\n");
796  ast_assert(0);
797  return;
798  }
799 
800  if (!(flags & OBJ_NOLOCK)) {
801  ao2_rdlock(self);
802  }
803  if (name) {
804  prnt(where, "Container name: %s\n", name);
805  }
806 #if defined(AO2_DEBUG)
807  if (self->v_table->dump) {
808  self->v_table->dump(self, where, prnt, prnt_obj);
809  } else
810 #endif /* defined(AO2_DEBUG) */
811  {
812  prnt(where, "Container dump not available.\n");
813  }
814  if (!(flags & OBJ_NOLOCK)) {
815  ao2_unlock(self);
816  }
817 }
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ast_assert(a)
Definition: utils.h:710
#define ao2_unlock(a)
Definition: astobj2.h:730
#define is_ao2_object(user_data)
const struct ao2_container_methods * v_table
#define ao2_rdlock(a)
Definition: astobj2.h:719
static const char name[]
Definition: cdr_mysql.c:74

◆ ao2_container_dup()

int ao2_container_dup ( struct ao2_container dest,
struct ao2_container src,
enum search_flags  flags 
)

Copy all object references in the src container into the dest container.

Since
11.0
Parameters
destContainer to copy src object references into.
srcContainer to copy all object references from.
flagsOBJ_NOLOCK if a lock is already held on both containers. Otherwise, the src container is locked first.
Precondition
The dest container must be empty. If the duplication fails, the dest container will be returned empty.
Note
This can potentially be expensive because a malloc is needed for every object in the src container.
Return values
0on success.
-1on error.

Definition at line 673 of file astobj2_container.c.

References ao2_callback, ao2_rdlock, ao2_t_ref, ao2_unlock, ao2_wrlock, dup_obj_cb(), NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, and OBJ_UNLINK.

Referenced by __ao2_container_clone(), __queues_show(), cli_aor_get_container(), cli_endpoint_get_container(), cli_get_container(), cli_show_tasks(), cli_unid_get_container(), handle_cli_sounds_show(), sip_options_apply_aor_configuration(), stasis_show_topics(), and tps_report_taskprocessor_list().

674 {
675  void *obj;
676  int res = 0;
677 
678  if (!(flags & OBJ_NOLOCK)) {
679  ao2_rdlock(src);
680  ao2_wrlock(dest);
681  }
682  obj = ao2_callback(src, OBJ_NOLOCK, dup_obj_cb, dest);
683  if (obj) {
684  /* Failed to put this obj into the dest container. */
685  ao2_t_ref(obj, -1, "Failed to put this object into the dest container.");
686 
687  /* Remove all items from the dest container. */
688  ao2_callback(dest, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL,
689  NULL);
690  res = -1;
691  }
692  if (!(flags & OBJ_NOLOCK)) {
693  ao2_unlock(dest);
694  ao2_unlock(src);
695  }
696 
697  return res;
698 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
static int dup_obj_cb(void *obj, void *arg, int flags)
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ao2_wrlock(a)
Definition: astobj2.h:720
#define ao2_rdlock(a)
Definition: astobj2.h:719

◆ ao2_container_dup_weakproxy_objs()

int ao2_container_dup_weakproxy_objs ( struct ao2_container dest,
struct ao2_container src,
enum search_flags  flags 
)

Copy object references associated with src container weakproxies into the dest container.

Parameters
destContainer to copy src strong object references into.
srcContainer to copy all weak object references from.
flagsOBJ_NOLOCK if a lock is already held on both containers. Otherwise, the src container is locked first.
Precondition
The dest container must be empty. If the duplication fails, the dest container will be returned empty.
Note
This can potentially be expensive because a malloc is needed for every object in the src container.
Every object inside the container is locked by ao2_weakproxy_get_object. Any weakproxy in src with no associated object is ignored.
Return values
0on success.
-1on error.

Definition at line 726 of file astobj2_container.c.

References ao2_callback, ao2_rdlock, ao2_t_ref, ao2_unlock, ao2_wrlock, dup_weakproxy_cb(), NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, and OBJ_UNLINK.

Referenced by AST_TEST_DEFINE().

727 {
728  void *obj;
729  int res = 0;
730 
731  if (!(flags & OBJ_NOLOCK)) {
732  ao2_rdlock(src);
733  ao2_wrlock(dest);
734  }
735  obj = ao2_callback(src, OBJ_NOLOCK, dup_weakproxy_cb, dest);
736  if (obj) {
737  /* Failed to put this obj into the dest container. */
738  ao2_t_ref(obj, -1, "Failed to put this object into the dest container.");
739 
740  /* Remove all items from the dest container. */
741  ao2_callback(dest, OBJ_NOLOCK | OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL,
742  NULL);
743  res = -1;
744  }
745  if (!(flags & OBJ_NOLOCK)) {
746  ao2_unlock(dest);
747  ao2_unlock(src);
748  }
749 
750  return res;
751 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ao2_wrlock(a)
Definition: astobj2.h:720
#define ao2_rdlock(a)
Definition: astobj2.h:719
static int dup_weakproxy_cb(void *proxy, void *arg, int flags)
Copy obj associated with a weakproxy into the arg container.

◆ ao2_container_register()

int ao2_container_register ( const char *  name,
struct ao2_container self,
ao2_prnt_obj_fn prnt_obj 
)

Register a container for CLI stats and integrity check.

Since
12.0.0
Parameters
nameName to register the container under.
selfContainer to register.
prnt_objCallback function to print the given object's key. (NULL if not available)
Return values
0on success.
-1on error.

Definition at line 958 of file astobj2_container.c.

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_t_alloc_options, ao2_t_link, and ao2_t_ref.

Referenced by ast_bridging_init(), ast_channels_init(), ast_pbx_init(), load_module(), stasis_caching_topic_create(), stasis_state_manager_create(), and stasis_topic_pool_create().

959 {
960  int res = 0;
961 #if defined(AO2_DEBUG)
962  struct ao2_reg_container *reg;
963 
964  reg = ao2_t_alloc_options(sizeof(*reg) + strlen(name), ao2_reg_destructor,
965  AO2_ALLOC_OPT_LOCK_NOLOCK, "Container registration object.");
966  if (!reg) {
967  return -1;
968  }
969 
970  /* Fill in registered entry */
971  ao2_t_ref(self, +1, "Registering container.");
972  reg->registered = self;
973  reg->prnt_obj = prnt_obj;
974  strcpy(reg->name, name);/* safe */
975 
976  if (!ao2_t_link(reg_containers, reg, "Save registration object.")) {
977  res = -1;
978  }
979 
980  ao2_t_ref(reg, -1, "Done registering container.");
981 #endif /* defined(AO2_DEBUG) */
982  return res;
983 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
#define ao2_t_link(container, obj, tag)
Add an object to a container.
Definition: astobj2.h:1547
#define ao2_t_alloc_options(data_size, destructor_fn, options, debug_msg)
Allocate and initialize an object.
Definition: astobj2.h:404
static const char name[]
Definition: cdr_mysql.c:74

◆ ao2_container_stats()

void ao2_container_stats ( struct ao2_container self,
enum search_flags  flags,
const char *  name,
void *  where,
ao2_prnt_fn prnt 
)

Display statistics of the specified container.

Since
12.0.0
Parameters
selfContainer to display statistics.
flagsOBJ_NOLOCK if a lock is already held on the container.
nameContainer name. (NULL if anonymous)
whereUser data needed by prnt to determine where to put output.
prntPrint output callback function to use.
Returns
Nothing

Definition at line 819 of file astobj2_container.c.

References ao2_rdlock, ao2_unlock, ast_assert, is_ao2_object, and OBJ_NOLOCK.

Referenced by ao2_container_unregister(), astobj2_test_1_helper(), and test_traversal_sorted().

820 {
821  if (!is_ao2_object(self) || !self->v_table) {
822  prnt(where, "Invalid container\n");
823  ast_assert(0);
824  return;
825  }
826 
827  if (!(flags & OBJ_NOLOCK)) {
828  ao2_rdlock(self);
829  }
830  if (name) {
831  prnt(where, "Container name: %s\n", name);
832  }
833  prnt(where, "Number of objects: %d\n", self->elements);
834 #if defined(AO2_DEBUG)
835  prnt(where, "Number of nodes: %d\n", self->nodes);
836  prnt(where, "Number of empty nodes: %d\n", self->nodes - self->elements);
837  /*
838  * XXX
839  * If the max_empty_nodes count gets out of single digits you
840  * likely have a code path where ao2_iterator_destroy() is not
841  * called.
842  *
843  * Empty nodes do not harm the container but they do make
844  * container operations less efficient.
845  */
846  prnt(where, "Maximum empty nodes: %d\n", self->max_empty_nodes);
847  if (self->v_table->stats) {
848  self->v_table->stats(self, where, prnt);
849  }
850 #endif /* defined(AO2_DEBUG) */
851  if (!(flags & OBJ_NOLOCK)) {
852  ao2_unlock(self);
853  }
854 }
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ast_assert(a)
Definition: utils.h:710
#define ao2_unlock(a)
Definition: astobj2.h:730
#define is_ao2_object(user_data)
const struct ao2_container_methods * v_table
#define ao2_rdlock(a)
Definition: astobj2.h:719
static const char name[]
Definition: cdr_mysql.c:74

◆ ao2_container_unregister()

void ao2_container_unregister ( const char *  name)

Unregister a container for CLI stats and integrity check.

Since
12.0.0
Parameters
nameName the container is registered under.
Returns
Nothing

Definition at line 985 of file astobj2_container.c.

References a, ao2_callback, ao2_container_check(), ao2_container_dump(), ao2_container_stats(), ao2_t_find, ao2_t_ref, ast_cli_args::argc, ast_cli_args::argv, ARRAY_LEN, ast_cli(), ast_cli_completion_add(), AST_CLI_DEFINE, ast_cli_unregister_multiple(), AST_DYNSTR_BUILD_FAILED, ast_str_buffer(), ast_str_set_va(), ast_str_thread_get(), ast_strdup, AST_THREADSTORAGE, buf, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, CMP_STOP, ast_cli_entry::command, ast_cli_args::fd, format, name, NULL, OBJ_NODATA, OBJ_SEARCH_KEY, OBJ_SEARCH_PARTIAL_KEY, OBJ_UNLINK, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

Referenced by bridge_cleanup(), cdr_engine_shutdown(), channels_shutdown(), load_module(), pbx_shutdown(), stasis_caching_topic_dtor(), state_manager_dtor(), topic_pool_dtor(), and unload_module().

986 {
987 #if defined(AO2_DEBUG)
988  ao2_t_find(reg_containers, name, OBJ_UNLINK | OBJ_NODATA | OBJ_SEARCH_KEY,
989  "Unregister container");
990 #endif /* defined(AO2_DEBUG) */
991 }
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
static const char name[]
Definition: cdr_mysql.c:74
#define ao2_t_find(container, arg, flags, tag)
Definition: astobj2.h:1754

◆ ao2_iterator_cleanup()

void ao2_iterator_cleanup ( struct ao2_iterator iter)

Definition at line 549 of file astobj2_container.c.

References ao2_iterator_destroy().

Referenced by AST_TEST_DEFINE(), and stasis_app_set_global_debug().

550 {
551  if (iter) {
552  ao2_iterator_destroy(iter);
553  }
554 }
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.

◆ ao2_iterator_count()

int ao2_iterator_count ( struct ao2_iterator iter)

Get a count of the iterated container objects.

Parameters
iterthe iterator to query
Return values
Thenumber of objects in the iterated container

Definition at line 630 of file astobj2_container.c.

References ao2_container_count(), and ao2_iterator::c.

631 {
632  return ao2_container_count(iter->c);
633 }
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
struct ao2_container * c
Definition: astobj2.h:1843

◆ ao2_iterator_destroy()

void ao2_iterator_destroy ( struct ao2_iterator iter)

Destroy a container iterator.

Parameters
iterthe iterator to destroy
Return values
noneThis function will release the container reference held by the iterator and any other resources it may be holding.

Definition at line 534 of file astobj2_container.c.

References AO2_ITERATOR_MALLOCD, ao2_iterator_restart(), ao2_t_ref, ast_free, ao2_iterator::c, ao2_iterator::flags, and NULL.

Referenced by __find_call(), __iax2_show_peers(), __manager_event_sessions_va(), __queues_show(), __test_cel_generate_peer_str(), _sip_show_peers(), aco_set_defaults(), action_agents(), action_confbridgelistrooms(), action_coreshowchannels(), action_devicestatelist(), action_extensionstatelist(), action_meetmelist(), action_presencestatelist(), add_ice_to_sdp(), add_ice_to_stream(), aeap_tab_complete_name(), agent_show_requested(), agents_post_apply_config(), agents_sweep(), alias_show(), ami_show_registration_contact_statuses(), ao2_iterator_cleanup(), ao2_weakproxy_unsubscribe(), app_to_json(), ari_show_apps(), ast_add_hint(), ast_ari_bridges_list(), ast_ari_channels_list(), ast_ari_endpoints_list(), ast_ari_endpoints_list_by_tech(), ast_ari_recordings_list_stored(), ast_bridge_channel_kick(), ast_bucket_file_json(), ast_bucket_json(), ast_cdr_setvar(), ast_channel_iterator_destroy(), ast_complete_channels(), ast_endpoint_snapshot_create(), ast_format_cache_get_by_codec(), ast_merge_contexts_and_delete(), ast_msg_var_iterator_destroy(), ast_multi_channel_blob_get_channels(), ast_pickup_find_by_group(), ast_print_namedgroups(), ast_sip_destroy_scheduler(), ast_sip_for_each_contact(), ast_sorcery_objectset_create2(), ast_sorcery_objectset_json_create(), ast_srtp_unprotect(), AST_TEST_DEFINE(), ast_var_indications(), ast_var_indications_table(), astman_verify_session_readpermissions(), astman_verify_session_writepermissions(), astobj2_test_1_helper(), auth_observer(), authenticate(), authenticate_reply(), bridge_app_subscribed_involved(), bridge_channel_event_join_leave(), bridge_channel_moving(), bridge_channel_talking(), bridges_scrape_cb(), build_cli_notify(), calendar_query_exec(), cel_generate_peer_str(), channels_scrape_cb(), check_access(), check_events(), clear_queue(), clear_stats(), cli_complete_endpoint(), cli_complete_notify(), cli_complete_registration(), cli_complete_show(), cli_complete_uri(), cli_console_active(), cli_display_named_acl_list(), cli_fax_show_sessions(), cli_list_devices(), cli_show_channels(), cli_show_modules(), cli_show_tasks(), cli_tps_reset_stats_all(), compare_weight(), complete_bridge_profile_name(), complete_confbridge_name(), complete_config_module(), complete_core_id(), complete_core_show_hint(), complete_country(), complete_iax2_peers(), complete_iax2_unregister(), complete_menu_name(), complete_mohclass_realtime(), complete_queue(), complete_queue_remove_member(), complete_show_sorcery_object(), complete_sip_peer(), complete_sip_registered_peer(), complete_sip_user(), complete_sipch(), complete_user_profile_name(), complete_userno(), conf_queue_dtmf(), config_hook_exec(), configure_parking_extensions(), container_to_json_array(), control_dispatch_all(), control_flush_queue(), control_prestart_dispatch_all(), destroy_pvts(), device_state_cb(), device_state_notify_callbacks(), dial_state_process_bridge_enter(), dialgroup_read(), disable_marked_lots(), dump_queue_members(), endpoints_scrape_cb(), event_session_shutdown(), exten_state_publisher_state_cb(), extension_state_cb(), fax_session_tab_complete(), find_queue_by_name_rt(), find_ringing_channel(), find_session(), find_session_by_nonce(), free_members(), generate_or_link_lots_to_configs(), get_device_state_causing_channels(), get_member_status(), get_transferee(), get_udp_transport(), get_write_timeout(), handle_bridge_pairings(), handle_bridge_show_all(), handle_chanlist(), handle_cli_confbridge_list(), handle_cli_confbridge_show_bridge_profiles(), handle_cli_confbridge_show_menus(), handle_cli_confbridge_show_user_profiles(), handle_cli_iax2_show_callno_limits(), handle_cli_iax2_show_users(), handle_cli_indication_show(), handle_cli_moh_show_classes(), handle_cli_moh_show_files(), handle_cli_moh_unregister_class(), handle_cli_odbc_show(), handle_cli_sound_show(), handle_cli_status(), handle_export_primitives(), handle_manager_show_event(), handle_manager_show_events(), handle_show_calendar(), handle_show_calendars(), handle_show_hint(), handle_show_hints(), handle_show_named_acl_cmd(), handle_showmanconn(), handle_skel_show_games(), handle_skel_show_levels(), handle_voicemail_show_aliases(), has_mwi_subscription(), iax2_getpeername(), iax2_getpeertrunk(), interface_exists(), ip_identify_apply(), jingle_add_google_candidates_to_transport(), jingle_add_ice_udp_candidates_to_transport(), jingle_request(), keepalive_transport_thread(), kill_duplicate_offers(), load_users(), local_devicestate(), locals_show(), manager_fax_sessions(), manager_iax2_show_peer_list(), manager_parking_status_all_lots(), manager_parking_status_single_lot(), manager_queues_status(), manager_queues_summary(), manager_show_registry(), manager_sip_peer_status(), mark_lots_as_disabled(), media_cache_handle_show_item(), meetme_menu_admin_extended(), meetme_show_cmd(), moh_rescan_files(), msg_func_write(), mwi_contact_deleted(), mwi_initial_events(), mwi_mailbox_delete_all(), mwi_mailbox_get(), mwi_subscription_mailboxes_str(), num_available_members(), parking_lot_get_space(), pjsip_acf_dial_contacts_read(), pjsip_aor_function_read(), poke_all_peers(), presence_state_cb(), presence_state_notify_callbacks(), print_queue(), prune_peers(), prune_users(), purge_sessions(), queue_function_mem_read(), queue_function_qac_dep(), queue_function_queuememberlist(), queue_mwi_event(), qupd_exec(), reload(), reload_single_queue(), remove_all_configured_parking_lot_extensions(), remove_pending_parking_lot_extensions(), rt_handle_member_record(), rtp_learning_start(), set_member_paused(), set_member_value(), set_transfer_variables_all(), show_codecs(), single_state_process_bridge_enter(), sip_keepalive_all_peers(), sip_options_apply_aor_configuration(), sip_options_cleanup_task(), sip_options_endpoint_unlink_aor_feeders(), sip_options_get_endpoint_state_compositor_state(), sip_outbound_publish_synchronize(), sip_poke_all_peers(), sip_prune_realtime(), sip_send_all_mwi_subscriptions(), sip_send_all_registers(), sip_show_channel(), sip_show_channels(), sip_show_channelstats(), sip_show_history(), sip_show_inuse(), sip_show_mwi(), sip_show_objects(), sip_show_registry(), sip_show_tcp(), sip_show_users(), sip_unregister_tests(), sla_calc_station_delays(), sla_change_trunk_state(), sla_queue_event_conf(), sla_show_stations(), sla_show_trunks(), sorcery_memory_cache_complete_name(), sorcery_memory_cache_complete_object_name(), stasis_app_mailboxes_to_json(), stasis_app_to_cli(), stasis_show_topics(), stir_shaken_tab_complete_name(), stop_streams(), system_create_resolver_and_set_nameservers(), test_ao2_callback_traversal(), test_ao2_iteration(), test_container_clone(), test_expected_duplicates(), topic_complete_name(), tps_report_taskprocessor_list(), tps_taskprocessor_tab_complete(), try_calling(), unbound_config_preapply(), unlink_peers_from_tables(), unload_module(), update_queue(), update_realtime_members(), xmpp_pubsub_create_affiliations(), xmpp_show_buddies(), and xmpp_show_clients().

535 {
536  /* Release any last container node reference. */
537  ao2_iterator_restart(iter);
538 
539  /* Release the iterated container reference. */
540  ao2_t_ref(iter->c, -1, "Unref iterator in ao2_iterator_destroy");
541  iter->c = NULL;
542 
543  /* Free the malloced iterator. */
544  if (iter->flags & AO2_ITERATOR_MALLOCD) {
545  ast_free(iter);
546  }
547 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
void ao2_iterator_restart(struct ao2_iterator *iter)
Restart an iteration.
#define NULL
Definition: resample.c:96
struct ao2_container * c
Definition: astobj2.h:1843
#define ast_free(a)
Definition: astmm.h:182

◆ ao2_iterator_init()

struct ao2_iterator ao2_iterator_init ( struct ao2_container c,
int  flags 
)

Create an iterator for a container.

initialize an iterator so we start from the first object

Definition at line 485 of file astobj2_container.c.

References a, ao2_t_ref, c, ao2_iterator::c, and ao2_iterator::flags.

Referenced by __iax2_show_peers(), __manager_event_sessions_va(), __queues_show(), __test_cel_generate_peer_str(), aco_set_defaults(), action_agents(), action_confbridgelistrooms(), action_coreshowchannels(), action_devicestatelist(), action_extensionstatelist(), action_meetmelist(), action_presencestatelist(), add_ice_to_sdp(), add_ice_to_stream(), aeap_tab_complete_name(), agent_show_requested(), agents_post_apply_config(), alias_show(), ami_show_registration_contact_statuses(), ao2_weakproxy_unsubscribe(), app_to_json(), ari_show_apps(), ast_add_hint(), ast_ari_bridges_list(), ast_ari_channels_list(), ast_ari_endpoints_list(), ast_ari_endpoints_list_by_tech(), ast_ari_recordings_list_stored(), ast_bridge_channel_kick(), ast_bucket_file_json(), ast_bucket_json(), ast_channel_iterator_all_new(), ast_complete_channels(), ast_endpoint_snapshot_create(), ast_format_cache_get_by_codec(), ast_merge_contexts_and_delete(), ast_msg_var_iterator_init(), ast_pickup_find_by_group(), ast_print_namedgroups(), ast_sip_destroy_scheduler(), ast_sip_for_each_contact(), ast_sorcery_objectset_create2(), ast_sorcery_objectset_json_create(), ast_srtp_unprotect(), AST_TEST_DEFINE(), ast_tone_zone_iterator_init(), astman_verify_session_readpermissions(), astman_verify_session_writepermissions(), astobj2_test_1_helper(), auth_observer(), authenticate(), authenticate_reply(), bridge_app_subscribed_involved(), bridge_channel_event_join_leave(), bridge_channel_moving(), bridge_channel_talking(), bridges_scrape_cb(), build_cli_notify(), calendar_query_exec(), cel_generate_peer_str(), channels_scrape_cb(), check_access(), check_events(), clear_queue(), clear_stats(), cli_complete_endpoint(), cli_complete_notify(), cli_complete_registration(), cli_complete_show(), cli_complete_uri(), cli_console_active(), cli_display_named_acl_list(), cli_fax_show_sessions(), cli_list_devices(), cli_show_channels(), cli_show_modules(), cli_show_tasks(), cli_tps_reset_stats_all(), compare_weight(), complete_bridge_profile_name(), complete_confbridge_name(), complete_config_module(), complete_core_id(), complete_core_show_hint(), complete_country(), complete_iax2_peers(), complete_iax2_unregister(), complete_menu_name(), complete_mohclass_realtime(), complete_queue(), complete_queue_remove_member(), complete_show_sorcery_object(), complete_sip_peer(), complete_sip_registered_peer(), complete_sip_user(), complete_sipch(), complete_user_profile_name(), complete_userno(), conf_queue_dtmf(), config_hook_exec(), configure_parking_extensions(), container_to_json_array(), control_dispatch_all(), control_flush_queue(), control_prestart_dispatch_all(), destroy_pvts(), device_state_cb(), device_state_notify_callbacks(), dial_state_process_bridge_enter(), dialgroup_read(), disable_marked_lots(), dump_queue_members(), endpoints_scrape_cb(), event_session_shutdown(), exten_state_publisher_state_cb(), extension_state_cb(), fax_session_tab_complete(), find_queue_by_name_rt(), find_ringing_channel(), find_session(), find_session_by_nonce(), free_members(), generate_or_link_lots_to_configs(), get_device_state_causing_channels(), get_member_status(), get_transferee(), get_udp_transport(), get_write_timeout(), handle_bridge_pairings(), handle_bridge_show_all(), handle_chanlist(), handle_cli_confbridge_list(), handle_cli_confbridge_show_bridge_profiles(), handle_cli_confbridge_show_menus(), handle_cli_confbridge_show_user_profiles(), handle_cli_iax2_show_callno_limits(), handle_cli_iax2_show_users(), handle_cli_moh_show_classes(), handle_cli_moh_show_files(), handle_cli_moh_unregister_class(), handle_cli_odbc_show(), handle_cli_sound_show(), handle_cli_status(), handle_export_primitives(), handle_manager_show_event(), handle_show_calendar(), handle_show_calendars(), handle_show_hint(), handle_show_hints(), handle_show_named_acl_cmd(), handle_showmanconn(), handle_skel_show_games(), handle_skel_show_levels(), handle_voicemail_show_aliases(), iax2_getpeername(), iax2_getpeertrunk(), interface_exists(), internal_ao2_traverse(), ip_identify_apply(), jingle_add_google_candidates_to_transport(), jingle_add_ice_udp_candidates_to_transport(), jingle_request(), keepalive_transport_thread(), load_users(), local_devicestate(), locals_show(), manager_fax_sessions(), manager_iax2_show_peer_list(), manager_parking_status_all_lots(), manager_parking_status_single_lot(), manager_queues_status(), manager_queues_summary(), manager_show_registry(), manager_sip_peer_status(), mark_lots_as_disabled(), media_cache_handle_show_item(), meetme_menu_admin_extended(), meetme_show_cmd(), moh_rescan_files(), msg_func_write(), mwi_initial_events(), mwi_mailbox_delete_all(), mwi_mailbox_get(), mwi_subscription_mailboxes_str(), num_available_members(), parking_lot_get_space(), pjsip_acf_dial_contacts_read(), pjsip_aor_function_read(), poke_all_peers(), presence_state_notify_callbacks(), print_queue(), prune_peers(), prune_users(), purge_sessions(), queue_function_mem_read(), queue_function_qac_dep(), queue_function_queuememberlist(), qupd_exec(), reload(), reload_single_queue(), remove_all_configured_parking_lot_extensions(), remove_pending_parking_lot_extensions(), rt_handle_member_record(), rtp_learning_start(), set_member_paused(), set_member_value(), set_transfer_variables_all(), show_codecs(), single_state_process_bridge_enter(), sip_keepalive_all_peers(), sip_options_apply_aor_configuration(), sip_options_cleanup_task(), sip_options_endpoint_unlink_aor_feeders(), sip_options_get_endpoint_state_compositor_state(), sip_outbound_publish_synchronize(), sip_poke_all_peers(), sip_prune_realtime(), sip_send_all_mwi_subscriptions(), sip_send_all_registers(), sip_show_channel(), sip_show_channels(), sip_show_channelstats(), sip_show_history(), sip_show_inuse(), sip_show_mwi(), sip_show_objects(), sip_show_registry(), sip_show_tcp(), sip_show_users(), sip_unregister_tests(), sla_calc_station_delays(), sla_change_trunk_state(), sla_queue_event_conf(), sla_show_stations(), sla_show_trunks(), sorcery_memory_cache_complete_name(), sorcery_memory_cache_complete_object_name(), stasis_app_mailboxes_to_json(), stasis_app_set_global_debug(), stasis_show_topics(), stir_shaken_tab_complete_name(), stop_streams(), system_create_resolver_and_set_nameservers(), test_ao2_iteration(), test_container_clone(), topic_complete_name(), tps_report_taskprocessor_list(), tps_taskprocessor_tab_complete(), try_calling(), unbound_config_preapply(), unload_module(), update_queue(), update_realtime_members(), xmpp_pubsub_create_affiliations(), xmpp_show_buddies(), and xmpp_show_clients().

486 {
487  struct ao2_iterator a = {
488  .c = c,
489  .flags = flags
490  };
491 
492  ao2_t_ref(c, +1, "Init iterator with container.");
493 
494  return a;
495 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
static struct test_val c
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
static struct test_val a

◆ ao2_iterator_restart()

void ao2_iterator_restart ( struct ao2_iterator iter)

Restart an iteration.

Parameters
iterthe iterator to restart
Note
A restart is not going to have any effect if the iterator was created with the AO2_ITERATOR_UNLINK flag. Any previous objects returned were removed from the container.
Return values
none

Definition at line 497 of file astobj2_container.c.

References __adjust_lock(), AO2_ITERATOR_DONTLOCK, AO2_LOCK_REQ_MUTEX, AO2_LOCK_REQ_RDLOCK, ao2_rdlock, ao2_ref, ao2_unlock, ao2_iterator::c, ao2_iterator::complete, ao2_iterator::flags, is_ao2_object, ao2_iterator::last_node, and NULL.

Referenced by ao2_iterator_destroy().

498 {
499  if (!is_ao2_object(iter->c)) {
500  /* Sanity check. */
501  return;
502  }
503 
504  /* Release the last container node reference if we have one. */
505  if (iter->last_node) {
506  enum ao2_lock_req orig_lock;
507 
508  /*
509  * Do a read lock in case the container node unref does not
510  * destroy the node. If the container node is destroyed then
511  * the lock will be upgraded to a write lock.
512  */
513  if (iter->flags & AO2_ITERATOR_DONTLOCK) {
514  orig_lock = __adjust_lock(iter->c, AO2_LOCK_REQ_RDLOCK, 1);
515  } else {
516  orig_lock = AO2_LOCK_REQ_MUTEX;
517  ao2_rdlock(iter->c);
518  }
519 
520  ao2_ref(iter->last_node, -1);
521  iter->last_node = NULL;
522 
523  if (iter->flags & AO2_ITERATOR_DONTLOCK) {
524  __adjust_lock(iter->c, orig_lock, 0);
525  } else {
526  ao2_unlock(iter->c);
527  }
528  }
529 
530  /* The iteration is no longer complete. */
531  iter->complete = 0;
532 }
void * last_node
Definition: astobj2.h:1845
ao2_lock_req
Which lock to request.
Definition: astobj2.h:701
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
int complete
Definition: astobj2.h:1847
struct ao2_container * c
Definition: astobj2.h:1843
#define is_ao2_object(user_data)
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_rdlock(a)
Definition: astobj2.h:719
Assume that the ao2_container is already locked.
Definition: astobj2.h:1872
enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
Definition: astobj2.c:425

◆ ao2_match_by_addr()

int ao2_match_by_addr ( void *  user_data,
void *  arg,
int  flags 
)

another convenience function is a callback that matches on address

A common ao2_callback is one that matches by address.

Definition at line 166 of file astobj2_container.c.

References CMP_MATCH, and CMP_STOP.

Referenced by __ao2_unlink(), load_module(), and test_container_clone().

167 {
168  return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
169 }

◆ cb_true()

static int cb_true ( void *  user_data,
void *  arg,
int  flags 
)
static

special callback that matches all

Definition at line 193 of file astobj2_container.c.

References CMP_MATCH.

Referenced by internal_ao2_traverse().

194 {
195  return CMP_MATCH;
196 }

◆ cb_true_data()

static int cb_true_data ( void *  user_data,
void *  arg,
void *  data,
int  flags 
)
static

similar to cb_true, but is an ao2_callback_data_fn instead

Definition at line 201 of file astobj2_container.c.

References CMP_MATCH.

Referenced by internal_ao2_traverse().

202 {
203  return CMP_MATCH;
204 }

◆ container_destruct()

void container_destruct ( void *  _c)

Definition at line 635 of file astobj2_container.c.

References ao2_t_callback, ast_atomic_fetchadd_int(), ao2_container_methods::destroy, ao2_container::destroying, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, and ao2_container::v_table.

Referenced by __ao2_container_alloc_hash(), and __ao2_container_alloc_rbtree().

636 {
637  struct ao2_container *c = _c;
638 
639  /* Unlink any stored objects in the container. */
640  c->destroying = 1;
642  "container_destruct called");
643 
644  /* Perform any extra container cleanup. */
645  if (c->v_table && c->v_table->destroy) {
646  c->v_table->destroy(c);
647  }
648 
649 #if defined(AO2_DEBUG)
650  ast_atomic_fetchadd_int(&ao2.total_containers, -1);
651 #endif
652 }
ao2_container_destroy_fn destroy
static struct test_val c
#define NULL
Definition: resample.c:96
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:755
const struct ao2_container_methods * v_table
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:1714
unsigned int destroying
TRUE if the container is being destroyed.
Generic container type.

◆ container_init()

int container_init ( void  )

Definition at line 1183 of file astobj2_container.c.

References AO2_ALLOC_OPT_LOCK_RWLOCK, AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, ao2_t_container_alloc_list, ARRAY_LEN, ast_cli_register_multiple, ast_register_cleanup(), and NULL.

Referenced by astobj2_init().

1184 {
1185 #if defined(AO2_DEBUG)
1187  AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, ao2_reg_sort_cb, NULL,
1188  "Container registration container.");
1189  if (!reg_containers) {
1190  return -1;
1191  }
1192 
1193  ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
1194  ast_register_cleanup(container_cleanup);
1195 #endif /* defined(AO2_DEBUG) */
1196 
1197  return 0;
1198 }
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag)
Allocate and initialize a list container.
Definition: astobj2.h:1333
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define NULL
Definition: resample.c:96
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
Replace objects with duplicate keys in container.
Definition: astobj2.h:1215

◆ dup_obj_cb()

static int dup_obj_cb ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 666 of file astobj2_container.c.

References ao2_link_flags, CMP_MATCH, CMP_STOP, and OBJ_NOLOCK.

Referenced by ao2_container_dup().

667 {
668  struct ao2_container *dest = arg;
669 
670  return ao2_link_flags(dest, obj, OBJ_NOLOCK) ? 0 : (CMP_MATCH | CMP_STOP);
671 }
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ao2_link_flags(container, obj, flags)
Definition: astobj2.h:1572
Generic container type.

◆ dup_weakproxy_cb()

static int dup_weakproxy_cb ( void *  proxy,
void *  arg,
int  flags 
)
static

Copy obj associated with a weakproxy into the arg container.

Parameters
proxypointer to the weakproxy.
argcallback argument from ao2_callback()
flagsflags from ao2_callback()
Return values
0on success.
CMP_STOP|CMP_MATCHon error.

Definition at line 710 of file astobj2_container.c.

References ao2_link_flags, ao2_ref, ao2_weakproxy_get_object, CMP_MATCH, CMP_STOP, and OBJ_NOLOCK.

Referenced by ao2_container_dup_weakproxy_objs().

711 {
712  void *obj = ao2_weakproxy_get_object(proxy, 0);
713  struct ao2_container *dest = arg;
714  int ret;
715 
716  if (!obj) {
717  return 0;
718  }
719 
720  ret = ao2_link_flags(dest, obj, OBJ_NOLOCK) ? 0 : (CMP_MATCH | CMP_STOP);
721  ao2_ref(obj, -1);
722 
723  return ret;
724 }
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ao2_link_flags(container, obj, flags)
Definition: astobj2.h:1572
#define ao2_weakproxy_get_object(weakproxy, flags)
Definition: astobj2.h:625
#define ao2_ref(o, delta)
Definition: astobj2.h:464
Generic container type.

◆ internal_ao2_traverse()

static void* internal_ao2_traverse ( struct ao2_container self,
enum search_flags  flags,
void *  cb_fn,
void *  arg,
void *  data,
enum ao2_callback_type  type,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)
static

Definition at line 230 of file astobj2_container.c.

References __adjust_lock(), __ao2_link(), __ao2_ref(), __ast_assert_failed(), __container_unlink_node_debug(), __is_ao2_object, AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_CALLBACK_WITH_DATA, ao2_iterator_init(), AO2_ITERATOR_MALLOCD, AO2_ITERATOR_UNLINK, AO2_LOCK_REQ_MUTEX, AO2_LOCK_REQ_RDLOCK, AO2_LOCK_REQ_WRLOCK, ao2_rdlock, ao2_ref, ao2_t_container_alloc_list, ao2_t_ref, AO2_TRAVERSAL_STATE_SIZE, AO2_UNLINK_NODE_DEC_COUNT, AO2_UNLINK_NODE_UNLINK_OBJECT, AO2_UNLINK_NODE_UNREF_NODE, ao2_unlock, ao2_wrlock, ast_calloc, cb_true(), cb_true_data(), CMP_MATCH, CMP_STOP, match(), NULL, ao2_container_node::obj, OBJ_MULTIPLE, OBJ_NODATA, OBJ_NOLOCK, and OBJ_UNLINK.

Referenced by __ao2_callback(), and __ao2_callback_data().

233 {
234  void *ret;
235  ao2_callback_fn *cb_default = NULL;
236  ao2_callback_data_fn *cb_withdata = NULL;
237  struct ao2_container_node *node;
238  void *traversal_state;
239 
240  enum ao2_lock_req orig_lock;
241  struct ao2_container *multi_container = NULL;
242  struct ao2_iterator *multi_iterator = NULL;
243 
244  if (!__is_ao2_object(self, file, line, func)) {
245  return NULL;
246  }
247 
248  if (!self->v_table
249  || !self->v_table->traverse_first || !self->v_table->traverse_next) {
250  /* Sanity checks. */
251  __ast_assert_failed(0, "invalid container v_table", file, line, func);
252  return NULL;
253  }
254 
255  /*
256  * This logic is used so we can support OBJ_MULTIPLE with OBJ_NODATA
257  * turned off. This if statement checks for the special condition
258  * where multiple items may need to be returned.
259  */
260  if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) {
261  /* we need to return an ao2_iterator with the results,
262  * as there could be more than one. the iterator will
263  * hold the only reference to a container that has all the
264  * matching objects linked into it, so when the iterator
265  * is destroyed, the container will be automatically
266  * destroyed as well.
267  */
269  NULL, "OBJ_MULTIPLE return container creation");
270  if (!multi_container) {
271  return NULL;
272  }
273  if (!(multi_iterator = ast_calloc(1, sizeof(*multi_iterator)))) {
274  ao2_t_ref(multi_container, -1, "OBJ_MULTIPLE interator creation failed.");
275  return NULL;
276  }
277  }
278 
279  if (!cb_fn) {
280  /* Match everything if no callback match function provided. */
281  if (type == AO2_CALLBACK_WITH_DATA) {
282  cb_withdata = cb_true_data;
283  } else {
284  cb_default = cb_true;
285  }
286  } else {
287  /*
288  * We do this here to avoid the per object casting penalty (even
289  * though that is probably optimized away anyway).
290  */
291  if (type == AO2_CALLBACK_WITH_DATA) {
292  cb_withdata = cb_fn;
293  } else {
294  cb_default = cb_fn;
295  }
296  }
297 
298  /* avoid modifications to the content */
299  if (flags & OBJ_NOLOCK) {
300  if (flags & OBJ_UNLINK) {
301  orig_lock = __adjust_lock(self, AO2_LOCK_REQ_WRLOCK, 1);
302  } else {
303  orig_lock = __adjust_lock(self, AO2_LOCK_REQ_RDLOCK, 1);
304  }
305  } else {
306  orig_lock = AO2_LOCK_REQ_MUTEX;
307  if (flags & OBJ_UNLINK) {
308  ao2_wrlock(self);
309  } else {
310  ao2_rdlock(self);
311  }
312  }
313 
314  /* Create a buffer for the traversal state. */
315  traversal_state = alloca(AO2_TRAVERSAL_STATE_SIZE);
316 
317  ret = NULL;
318  for (node = self->v_table->traverse_first(self, flags, arg, traversal_state);
319  node;
320  node = self->v_table->traverse_next(self, traversal_state, node)) {
321  int match;
322 
323  /* Visit the current node. */
324  match = (CMP_MATCH | CMP_STOP);
325  if (type == AO2_CALLBACK_WITH_DATA) {
326  match &= cb_withdata(node->obj, arg, data, flags);
327  } else {
328  match &= cb_default(node->obj, arg, flags);
329  }
330  if (match == 0) {
331  /* no match, no stop, continue */
332  continue;
333  }
334  if (match == CMP_STOP) {
335  /* no match but stop, we are done */
336  break;
337  }
338 
339  /*
340  * CMP_MATCH is set here
341  *
342  * we found the object, performing operations according to flags
343  */
344  if (node->obj) {
345  /* The object is still in the container. */
346  if (!(flags & OBJ_NODATA)) {
347  /*
348  * We are returning the object, record the value. It is
349  * important to handle this case before the unlink.
350  */
351  if (multi_container) {
352  /*
353  * Link the object into the container that will hold the
354  * results.
355  */
356  __ao2_link(multi_container, node->obj, flags, tag, file, line, func);
357  } else {
358  ret = node->obj;
359  /* Returning a single object. */
360  if (!(flags & OBJ_UNLINK)) {
361  /*
362  * Bump the ref count since we are not going to unlink and
363  * transfer the container's object ref to the returned object.
364  */
365  __ao2_ref(ret, 1, tag ?: "Traversal found object", file, line, func);
366  }
367  }
368  }
369 
370  if (flags & OBJ_UNLINK) {
372  if (multi_container || (flags & OBJ_NODATA)) {
374  }
375  __container_unlink_node_debug(node, ulflag, tag, file, line, func);
376  }
377  }
378 
379  if ((match & CMP_STOP) || !(flags & OBJ_MULTIPLE)) {
380  /* We found our only (or last) match, so we are done */
381  break;
382  }
383  }
384  if (self->v_table->traverse_cleanup) {
385  self->v_table->traverse_cleanup(traversal_state);
386  }
387  if (node) {
388  /* Unref the node from self->v_table->traverse_first/traverse_next() */
389  ao2_ref(node, -1);
390  }
391 
392  if (flags & OBJ_NOLOCK) {
393  __adjust_lock(self, orig_lock, 0);
394  } else {
395  ao2_unlock(self);
396  }
397 
398  /* if multi_container was created, we are returning multiple objects */
399  if (multi_container) {
400  *multi_iterator = ao2_iterator_init(multi_container,
402  ao2_t_ref(multi_container, -1,
403  "OBJ_MULTIPLE for multiple objects traversal complete.");
404  return multi_iterator;
405  } else {
406  return ret;
407  }
408 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
static const char type[]
Definition: chan_ooh323.c:109
Definition: test_heap.c:38
int __container_unlink_node_debug(struct ao2_container_node *node, uint32_t flags, const char *tag, const char *file, int line, const char *func)
#define __is_ao2_object(user_data, file, line, func)
ao2_lock_req
Which lock to request.
Definition: astobj2.h:701
static int cb_true_data(void *user_data, void *arg, void *data, int flags)
similar to cb_true, but is an ao2_callback_data_fn instead
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
int __ao2_link(struct ao2_container *self, void *obj_new, int flags, const char *tag, const char *file, int line, const char *func)
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag)
Allocate and initialize a list container.
Definition: astobj2.h:1333
#define ao2_unlock(a)
Definition: astobj2.h:730
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2315
ao2_container_find_first_fn traverse_first
ao2_container_find_cleanup_fn traverse_cleanup
#define NULL
Definition: resample.c:96
static int cb_true(void *user_data, void *arg, int flags)
special callback that matches all
#define ao2_wrlock(a)
Definition: astobj2.h:720
int() ao2_callback_data_fn(void *obj, void *arg, void *data, int flags)
Type of a generic callback function.
Definition: astobj2.h:1248
Generic container node.
int __ao2_ref(void *o, int delta, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:498
int() ao2_callback_fn(void *obj, void *arg, int flags)
Type of a generic callback function.
Definition: astobj2.h:1230
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const struct ao2_container_methods * v_table
void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function)
Definition: main/utils.c:2564
ao2_container_find_next_fn traverse_next
#define ao2_rdlock(a)
Definition: astobj2.h:719
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
#define AO2_TRAVERSAL_STATE_SIZE
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
Definition: astobj2.c:425
Generic container type.