Wed Jan 8 2020 09:49:42

Asterisk developer's documentation


astobj2.c
Go to the documentation of this file.
1 /*
2  * astobj2 - replacement containers for asterisk data structures.
3  *
4  * Copyright (C) 2006 Marta Carbone, Luigi Rizzo - Univ. di Pisa, Italy
5  *
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.
11  *
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.
15  */
16 
17 /*
18  * Function implementing astobj2 objects.
19  */
20 
21 /*** MODULEINFO
22  <support_level>core</support_level>
23  ***/
24 
25 #include "asterisk.h"
26 
27 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 424786 $")
28 
29 #include "asterisk/_private.h"
30 #include "asterisk/astobj2.h"
31 #include "asterisk/utils.h"
32 #include "asterisk/cli.h"
33 #include "asterisk/paths.h"
34 
35 static FILE *ref_log;
36 
37 /*!
38  * astobj2 objects are always preceded by this data structure,
39  * which contains a lock, a reference counter,
40  * the flags and a pointer to a destructor.
41  * The refcount is used to decide when it is time to
42  * invoke the destructor.
43  * The magic number is used for consistency check.
44  * XXX the lock is not always needed, and its initialization may be
45  * expensive. Consider making it external.
46  */
47 struct __priv_data {
51  /*! for stats */
52  size_t data_size;
53  /*! magic number. This is used to verify that a pointer passed in is a
54  * valid astobj2 */
55  uint32_t magic;
56 };
57 
58 #define AO2_MAGIC 0xa570b123
59 
60 /*!
61  * What an astobj2 object looks like: fixed-size private data
62  * followed by variable-size user data.
63  */
64 struct astobj2 {
66  void *user_data[0];
67 };
68 
69 #ifdef AST_DEVMODE
70 /* #define AO2_DEBUG 1 */
71 #endif
72 
73 #ifdef AO2_DEBUG
74 struct ao2_stats {
75  volatile int total_objects;
76  volatile int total_mem;
77  volatile int total_containers;
78  volatile int total_refs;
79  volatile int total_locked;
80 };
81 
82 static struct ao2_stats ao2;
83 #endif
84 
85 #ifndef HAVE_BKTR /* backtrace support */
86 void ao2_bt(void) {}
87 #else
88 #include <execinfo.h> /* for backtrace */
89 
90 void ao2_bt(void)
91 {
92  int c, i;
93 #define N1 20
94  void *addresses[N1];
95  char **strings;
96 
97  c = backtrace(addresses, N1);
98  strings = ast_bt_get_symbols(addresses,c);
99  ast_verbose("backtrace returned: %d\n", c);
100  for(i = 0; i < c; i++) {
101  ast_verbose("%d: %p %s\n", i, addresses[i], strings[i]);
102  }
103  ast_std_free(strings);
104 }
105 #endif
106 
107 /*!
108  * \brief convert from a pointer _p to a user-defined object
109  *
110  * \return the pointer to the astobj2 structure
111  */
112 static inline struct astobj2 *INTERNAL_OBJ(void *user_data)
113 {
114  struct astobj2 *p;
115 
116  if (!user_data) {
117  ast_log(LOG_ERROR, "user_data is NULL\n");
118  return NULL;
119  }
120 
121  p = (struct astobj2 *) ((char *) user_data - sizeof(*p));
122  if (AO2_MAGIC != p->priv_data.magic) {
123  if (p->priv_data.magic) {
124  ast_log(LOG_ERROR, "bad magic number 0x%x for object %p\n",
125  p->priv_data.magic, user_data);
126  } else {
128  "bad magic number for object %p. Object is likely destroyed.\n",
129  user_data);
130  }
131  ast_assert(0);
132  return NULL;
133  }
134 
135  return p;
136 }
137 
141 };
142 
143 /*!
144  * \brief convert from a pointer _p to an astobj2 object
145  *
146  * \return the pointer to the user-defined portion.
147  */
148 #define EXTERNAL_OBJ(_p) ((_p) == NULL ? NULL : (_p)->user_data)
149 
150 /* the underlying functions common to debug and non-debug versions */
151 
152 static int internal_ao2_ref(void *user_data, const int delta);
155 static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func);
156 static void *internal_ao2_callback(struct ao2_container *c,
157  const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
158  char *tag, char *file, int line, const char *funcname);
159 static void *internal_ao2_iterator_next(struct ao2_iterator *a, struct bucket_entry **q);
160 
161 int __ao2_lock(void *user_data, const char *file, const char *func, int line, const char *var)
162 {
163  struct astobj2 *p = INTERNAL_OBJ(user_data);
164 
165  if (p == NULL)
166  return -1;
167 
168 #ifdef AO2_DEBUG
169  ast_atomic_fetchadd_int(&ao2.total_locked, 1);
170 #endif
171 
172  return __ast_pthread_mutex_lock(file, line, func, var, &p->priv_data.lock);
173 }
174 
175 int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
176 {
177  struct astobj2 *p = INTERNAL_OBJ(user_data);
178 
179  if (p == NULL)
180  return -1;
181 
182 #ifdef AO2_DEBUG
183  ast_atomic_fetchadd_int(&ao2.total_locked, -1);
184 #endif
185 
186  return __ast_pthread_mutex_unlock(file, line, func, var, &p->priv_data.lock);
187 }
188 
189 int __ao2_trylock(void *user_data, const char *file, const char *func, int line, const char *var)
190 {
191  struct astobj2 *p = INTERNAL_OBJ(user_data);
192  int ret;
193 
194  if (p == NULL)
195  return -1;
196  ret = __ast_pthread_mutex_trylock(file, line, func, var, &p->priv_data.lock);
197 
198 #ifdef AO2_DEBUG
199  if (!ret)
200  ast_atomic_fetchadd_int(&ao2.total_locked, 1);
201 #endif
202  return ret;
203 }
204 
205 void *ao2_object_get_lockaddr(void *obj)
206 {
207  struct astobj2 *p = INTERNAL_OBJ(obj);
208 
209  if (p == NULL)
210  return NULL;
211 
212  return &p->priv_data.lock;
213 }
214 
215 /*
216  * The argument is a pointer to the user portion.
217  */
218 
219 int __ao2_ref_debug(void *user_data, const int delta, const char *tag, const char *file, int line, const char *funcname)
220 {
221  struct astobj2 *obj = INTERNAL_OBJ(user_data);
222  int old_refcount = -1;
223 
224  if (obj) {
225  old_refcount = internal_ao2_ref(user_data, delta);
226  }
227 
228  if (ref_log && user_data) {
229  if (!obj) {
230  /* Invalid object: Bad magic number. */
231  fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
232  user_data, delta, ast_get_tid(), file, line, funcname, tag);
233  fflush(ref_log);
234  } else if (old_refcount + delta == 0) {
235  fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**destructor**,%s\n",
236  user_data, delta, ast_get_tid(), file, line, funcname, tag);
237  fflush(ref_log);
238  } else if (delta != 0) {
239  fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data, (delta < 0 ? "" : "+"),
240  delta, ast_get_tid(), file, line, funcname, old_refcount, tag);
241  fflush(ref_log);
242  }
243  }
244 
245  return old_refcount;
246 }
247 
248 int __ao2_ref(void *user_data, const int delta)
249 {
250  return internal_ao2_ref(user_data, delta);
251 }
252 
253 static int internal_ao2_ref(void *user_data, const int delta)
254 {
255  struct astobj2 *obj = INTERNAL_OBJ(user_data);
256  int current_value;
257  int ret;
258 
259  if (obj == NULL)
260  return -1;
261 
262  /* if delta is 0, just return the refcount */
263  if (delta == 0)
264  return (obj->priv_data.ref_counter);
265 
266  /* we modify with an atomic operation the reference counter */
267  ret = ast_atomic_fetchadd_int(&obj->priv_data.ref_counter, delta);
268  current_value = ret + delta;
269 
270 #ifdef AO2_DEBUG
271  ast_atomic_fetchadd_int(&ao2.total_refs, delta);
272 #endif
273 
274  /* this case must never happen */
275  if (current_value < 0)
276  ast_log(LOG_ERROR, "refcount %d on object %p\n", current_value, user_data);
277 
278  if (current_value <= 0) { /* last reference, destroy the object */
279  if (obj->priv_data.destructor_fn != NULL) {
280  obj->priv_data.destructor_fn(user_data);
281  }
282 
284 #ifdef AO2_DEBUG
285  ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
286  ast_atomic_fetchadd_int(&ao2.total_objects, -1);
287 #endif
288  /* for safety, zero-out the astobj2 header and also the
289  * first word of the user-data, which we make sure is always
290  * allocated. */
291  memset(obj, '\0', sizeof(struct astobj2 *) + sizeof(void *) );
292  ast_free(obj);
293  }
294 
295  return ret;
296 }
297 
298 /*
299  * We always alloc at least the size of a void *,
300  * for debugging purposes.
301  */
302 static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, const char *file, int line, const char *funcname)
303 {
304  /* allocation */
305  struct astobj2 *obj;
306 
307  if (data_size < sizeof(void *))
308  data_size = sizeof(void *);
309 
310 #if defined(__AST_DEBUG_MALLOC)
311  obj = __ast_calloc(1, sizeof(*obj) + data_size, file, line, funcname);
312 #else
313  obj = ast_calloc(1, sizeof(*obj) + data_size);
314 #endif
315 
316  if (obj == NULL)
317  return NULL;
318 
320  obj->priv_data.magic = AO2_MAGIC;
321  obj->priv_data.data_size = data_size;
322  obj->priv_data.ref_counter = 1;
323  obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */
324 
325 #ifdef AO2_DEBUG
326  ast_atomic_fetchadd_int(&ao2.total_objects, 1);
327  ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
328  ast_atomic_fetchadd_int(&ao2.total_refs, 1);
329 #endif
330 
331  /* return a pointer to the user data */
332  return EXTERNAL_OBJ(obj);
333 }
334 
335 void *__ao2_alloc_debug(size_t data_size, ao2_destructor_fn destructor_fn, char *tag,
336  const char *file, int line, const char *funcname, int ref_debug)
337 {
338  /* allocation */
339  void *obj;
340 
341  if ((obj = internal_ao2_alloc(data_size, destructor_fn, file, line, funcname)) == NULL) {
342  return NULL;
343  }
344 
345  if (ref_log) {
346  fprintf(ref_log, "%p,+1,%d,%s,%d,%s,**constructor**,%s\n", obj, ast_get_tid(), file, line, funcname, tag);
347  fflush(ref_log);
348  }
349 
350  /* return a pointer to the user data */
351  return obj;
352 }
353 
354 void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn)
355 {
356  return internal_ao2_alloc(data_size, destructor_fn, __FILE__, __LINE__, __FUNCTION__);
357 }
358 
359 
360 /* internal callback to destroy a container. */
361 static void container_destruct(void *c);
362 
363 /* internal callback to destroy a container. */
364 static void container_destruct_debug(void *c);
365 
366 /* each bucket in the container is a tailq. */
368 
369 /*!
370  * A container; stores the hash and callback functions, information on
371  * the size, the hash bucket heads, and a version number, starting at 0
372  * (for a newly created, empty container)
373  * and incremented every time an object is inserted or deleted.
374  * The assumption is that an object is never moved in a container,
375  * but removed and readded with the new number.
376  * The version number is especially useful when implementing iterators.
377  * In fact, we can associate a unique, monotonically increasing number to
378  * each object, which means that, within an iterator, we can store the
379  * version number of the current object, and easily look for the next one,
380  * which is the next one in the list with a higher number.
381  * Since all objects have a version >0, we can use 0 as a marker for
382  * 'we need the first object in the bucket'.
383  *
384  * \todo Linking and unlink objects is typically expensive, as it
385  * involves a malloc() of a small object which is very inefficient.
386  * To optimize this, we allocate larger arrays of bucket_entry's
387  * when we run out of them, and then manage our own freelist.
388  * This will be more efficient as we can do the freelist management while
389  * we hold the lock (that we need anyways).
390  */
395  /*! Number of elements in the container */
396  int elements;
397  /*! described above */
398  int version;
399  /*! variable size */
400  struct bucket buckets[0];
401 };
402 
403 /*!
404  * \brief always zero hash function
405  *
406  * it is convenient to have a hash function that always returns 0.
407  * This is basically used when we want to have a container that is
408  * a simple linked list.
409  *
410  * \returns 0
411  */
412 static int hash_zero(const void *user_obj, const int flags)
413 {
414  return 0;
415 }
416 
417 /*
418  * A container is just an object, after all!
419  */
422 {
423  /* XXX maybe consistency check on arguments ? */
424  /* compute the container size */
425 
426  if (!c)
427  return NULL;
428 
429  c->version = 1; /* 0 is a reserved value here */
430  c->n_buckets = hash_fn ? n_buckets : 1;
431  c->hash_fn = hash_fn ? hash_fn : hash_zero;
432  c->cmp_fn = cmp_fn;
433 
434 #ifdef AO2_DEBUG
435  ast_atomic_fetchadd_int(&ao2.total_containers, 1);
436 #endif
437 
438  return c;
439 }
440 
442  ao2_callback_fn *cmp_fn, char *tag, char *file, int line,
443  const char *funcname, int ref_debug)
444 {
445  /* XXX maybe consistency check on arguments ? */
446  /* compute the container size */
447  const unsigned int num_buckets = hash_fn ? n_buckets : 1;
448  size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket);
449  struct ao2_container *c = __ao2_alloc_debug(container_size, ref_debug ? container_destruct_debug : container_destruct, tag, file, line, funcname, ref_debug);
450 
451  return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn);
452 }
453 
456 {
457  /* XXX maybe consistency check on arguments ? */
458  /* compute the container size */
459 
460  const unsigned int num_buckets = hash_fn ? n_buckets : 1;
461  size_t container_size = sizeof(struct ao2_container) + num_buckets * sizeof(struct bucket);
462  struct ao2_container *c = __ao2_alloc(container_size, container_destruct);
463 
464  return internal_ao2_container_alloc(c, num_buckets, hash_fn, cmp_fn);
465 }
466 
467 /*!
468  * return the number of elements in the container
469  */
471 {
472  return c->elements;
473 }
474 
475 /*!
476  * A structure to create a linked list of entries,
477  * used within a bucket.
478  * XXX \todo this should be private to the container code
479  */
480 struct bucket_entry {
482  int version;
483  struct astobj2 *astobj; /* pointer to internal data */
484 };
485 
486 /*
487  * link an object to a container
488  */
489 
490 static struct bucket_entry *internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func)
491 {
492  int i;
493  /* create a new list entry */
494  struct bucket_entry *p;
495  struct astobj2 *obj = INTERNAL_OBJ(user_data);
496 
497  if (obj == NULL)
498  return NULL;
499 
500  if (INTERNAL_OBJ(c) == NULL)
501  return NULL;
502 
503  p = ast_calloc(1, sizeof(*p));
504  if (!p)
505  return NULL;
506 
507  i = abs(c->hash_fn(user_data, OBJ_POINTER));
508 
509  ao2_lock(c);
510  i %= c->n_buckets;
511  p->astobj = obj;
512  p->version = ast_atomic_fetchadd_int(&c->version, 1);
513  AST_LIST_INSERT_TAIL(&c->buckets[i], p, entry);
514  ast_atomic_fetchadd_int(&c->elements, 1);
515 
516  /* the last two operations (ao2_ref, ao2_unlock) must be done by the calling func */
517  return p;
518 }
519 
520 void *__ao2_link_debug(struct ao2_container *c, void *user_data, char *tag, char *file, int line, const char *funcname)
521 {
522  struct bucket_entry *p = internal_ao2_link(c, user_data, file, line, funcname);
523 
524  if (p) {
525  __ao2_ref_debug(user_data, +1, tag, file, line, funcname);
526  ao2_unlock(c);
527  }
528  return p;
529 }
530 
531 void *__ao2_link(struct ao2_container *c, void *user_data)
532 {
533  struct bucket_entry *p = internal_ao2_link(c, user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__);
534 
535  if (p) {
536  __ao2_ref(user_data, +1);
537  ao2_unlock(c);
538  }
539  return p;
540 }
541 
542 /*!
543  * \brief another convenience function is a callback that matches on address
544  */
545 int ao2_match_by_addr(void *user_data, void *arg, int flags)
546 {
547  return (user_data == arg) ? (CMP_MATCH | CMP_STOP) : 0;
548 }
549 
550 /*
551  * Unlink an object from the container
552  * and destroy the associated * bucket_entry structure.
553  */
554 void *__ao2_unlink_debug(struct ao2_container *c, void *user_data, char *tag,
555  char *file, int line, const char *funcname)
556 {
557  if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */
558  return NULL;
559 
560  __ao2_callback_debug(c, OBJ_UNLINK | OBJ_POINTER | OBJ_NODATA, ao2_match_by_addr, user_data, tag, file, line, funcname);
561 
562  return NULL;
563 }
564 
565 void *__ao2_unlink(struct ao2_container *c, void *user_data)
566 {
567  if (INTERNAL_OBJ(user_data) == NULL) /* safety check on the argument */
568  return NULL;
569 
571 
572  return NULL;
573 }
574 
575 /*!
576  * \brief special callback that matches all
577  */
578 static int cb_true(void *user_data, void *arg, int flags)
579 {
580  return CMP_MATCH;
581 }
582 
583 /*!
584  * \brief similar to cb_true, but is an ao2_callback_data_fn instead
585  */
586 static int cb_true_data(void *user_data, void *arg, void *data, int flags)
587 {
588  return CMP_MATCH;
589 }
590 
591 /*!
592  * Browse the container using different stategies accoding the flags.
593  * \return Is a pointer to an object or to a list of object if OBJ_MULTIPLE is
594  * specified.
595  * Luckily, for debug purposes, the added args (tag, file, line, funcname)
596  * aren't an excessive load to the system, as the callback should not be
597  * called as often as, say, the ao2_ref func is called.
598  */
599 static void *internal_ao2_callback(struct ao2_container *c,
600  const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type,
601  char *tag, char *file, int line, const char *funcname)
602 {
603  int i, start, last; /* search boundaries */
604  void *ret = NULL;
605  ao2_callback_fn *cb_default = NULL;
606  ao2_callback_data_fn *cb_withdata = NULL;
607  struct ao2_container *multi_container = NULL;
608  struct ao2_iterator *multi_iterator = NULL;
609 
610  if (INTERNAL_OBJ(c) == NULL) /* safety check on the argument */
611  return NULL;
612 
613  /*
614  * This logic is used so we can support OBJ_MULTIPLE with OBJ_NODATA
615  * turned off. This if statement checks for the special condition
616  * where multiple items may need to be returned.
617  */
618  if ((flags & (OBJ_MULTIPLE | OBJ_NODATA)) == OBJ_MULTIPLE) {
619  /* we need to return an ao2_iterator with the results,
620  * as there could be more than one. the iterator will
621  * hold the only reference to a container that has all the
622  * matching objects linked into it, so when the iterator
623  * is destroyed, the container will be automatically
624  * destroyed as well.
625  */
626  if (!(multi_container = ao2_container_alloc(1, NULL, NULL))) {
627  return NULL;
628  }
629  if (!(multi_iterator = ast_calloc(1, sizeof(*multi_iterator)))) {
630  ao2_ref(multi_container, -1);
631  return NULL;
632  }
633  }
634 
635  /* override the match function if necessary */
636  if (cb_fn == NULL) { /* if NULL, match everything */
637  if (type == WITH_DATA) {
638  cb_withdata = cb_true_data;
639  } else {
640  cb_default = cb_true;
641  }
642  } else {
643  /* We do this here to avoid the per object casting penalty (even though
644  that is probably optimized away anyway). */
645  if (type == WITH_DATA) {
646  cb_withdata = cb_fn;
647  } else {
648  cb_default = cb_fn;
649  }
650  }
651 
652  /*
653  * XXX this can be optimized.
654  * If we have a hash function and lookup by pointer,
655  * run the hash function. Otherwise, scan the whole container
656  * (this only for the time being. We need to optimize this.)
657  */
658  if ((flags & OBJ_POINTER)) /* we know hash can handle this case */
659  start = i = c->hash_fn(arg, flags & OBJ_POINTER) % c->n_buckets;
660  else /* don't know, let's scan all buckets */
661  start = i = -1; /* XXX this must be fixed later. */
662 
663  /* determine the search boundaries: i..last-1 */
664  if (i < 0) {
665  start = i = 0;
666  last = c->n_buckets;
667  } else if ((flags & OBJ_CONTINUE)) {
668  last = c->n_buckets;
669  } else {
670  last = i + 1;
671  }
672 
673  ao2_lock(c); /* avoid modifications to the content */
674 
675  for (; i < last ; i++) {
676  /* scan the list with prev-cur pointers */
677  struct bucket_entry *cur;
678 
680  int match = (CMP_MATCH | CMP_STOP);
681 
682  if (type == WITH_DATA) {
683  match &= cb_withdata(EXTERNAL_OBJ(cur->astobj), arg, data, flags);
684  } else {
685  match &= cb_default(EXTERNAL_OBJ(cur->astobj), arg, flags);
686  }
687 
688  /* we found the object, performing operations according flags */
689  if (match == 0) { /* no match, no stop, continue */
690  continue;
691  } else if (match == CMP_STOP) { /* no match but stop, we are done */
692  i = last;
693  break;
694  }
695 
696  /* we have a match (CMP_MATCH) here */
697  if (!(flags & OBJ_NODATA)) { /* if must return the object, record the value */
698  /* it is important to handle this case before the unlink */
699  ret = EXTERNAL_OBJ(cur->astobj);
700  if (!(flags & (OBJ_UNLINK | OBJ_MULTIPLE))) {
701  if (tag)
702  __ao2_ref_debug(ret, 1, tag, file, line, funcname);
703  else
704  __ao2_ref(ret, 1);
705  }
706  }
707 
708  /* If we are in OBJ_MULTIPLE mode and OBJ_NODATE is off,
709  * link the object into the container that will hold the results.
710  */
711  if (ret && (multi_container != NULL)) {
712  if (tag) {
713  __ao2_link_debug(multi_container, ret, tag, file, line, funcname);
714  } else {
715  __ao2_link(multi_container, ret);
716  }
717  ret = NULL;
718  }
719 
720  if (flags & OBJ_UNLINK) { /* must unlink */
721  /* we are going to modify the container, so update version */
724  /* update number of elements */
726 
727  /* - When unlinking and not returning the result, (OBJ_NODATA), the ref from the container
728  * must be decremented.
729  * - When unlinking with OBJ_MULTIPLE the ref from the original container
730  * must be decremented regardless if OBJ_NODATA is used. This is because the result is
731  * returned in a new container that already holds its own ref for the object. If the ref
732  * from the original container is not accounted for here a memory leak occurs. */
733  if (flags & (OBJ_NODATA | OBJ_MULTIPLE)) {
734  if (tag)
735  __ao2_ref_debug(EXTERNAL_OBJ(cur->astobj), -1, tag, file, line, funcname);
736  else
737  __ao2_ref(EXTERNAL_OBJ(cur->astobj), -1);
738  }
739  ast_free(cur); /* free the link record */
740  }
741 
742  if ((match & CMP_STOP) || !(flags & OBJ_MULTIPLE)) {
743  /* We found our only (or last) match, so force an exit from
744  the outside loop. */
745  i = last;
746  break;
747  }
748  }
750 
751  if (ret) {
752  break;
753  }
754 
755  if (i == c->n_buckets - 1 && (flags & OBJ_POINTER) && (flags & OBJ_CONTINUE)) {
756  /* Move to the beginning to ensure we check every bucket */
757  i = -1;
758  last = start;
759  }
760  }
761  ao2_unlock(c);
762 
763  /* if multi_container was created, we are returning multiple objects */
764  if (multi_container != NULL) {
765  *multi_iterator = ao2_iterator_init(multi_container,
767  ao2_ref(multi_container, -1);
768  return multi_iterator;
769  } else {
770  return ret;
771  }
772 }
773 
775  const enum search_flags flags,
776  ao2_callback_fn *cb_fn, void *arg,
777  char *tag, char *file, int line, const char *funcname)
778 {
779  return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, tag, file, line, funcname);
780 }
781 
782 void *__ao2_callback(struct ao2_container *c, const enum search_flags flags,
783  ao2_callback_fn *cb_fn, void *arg)
784 {
785  return internal_ao2_callback(c,flags, cb_fn, arg, NULL, DEFAULT, NULL, NULL, 0, NULL);
786 }
787 
789  const enum search_flags flags,
790  ao2_callback_data_fn *cb_fn, void *arg, void *data,
791  char *tag, char *file, int line, const char *funcname)
792 {
793  return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, tag, file, line, funcname);
794 }
795 
796 void *__ao2_callback_data(struct ao2_container *c, const enum search_flags flags,
797  ao2_callback_data_fn *cb_fn, void *arg, void *data)
798 {
799  return internal_ao2_callback(c, flags, cb_fn, arg, data, WITH_DATA, NULL, NULL, 0, NULL);
800 }
801 
802 /*!
803  * the find function just invokes the default callback with some reasonable flags.
804  */
805 void *__ao2_find_debug(struct ao2_container *c, void *arg, enum search_flags flags, char *tag, char *file, int line, const char *funcname)
806 {
807  return __ao2_callback_debug(c, flags, c->cmp_fn, arg, tag, file, line, funcname);
808 }
809 
810 void *__ao2_find(struct ao2_container *c, void *arg, enum search_flags flags)
811 {
812  return __ao2_callback(c, flags, c->cmp_fn, arg);
813 }
814 
815 /*!
816  * initialize an iterator so we start from the first object
817  */
819 {
820  struct ao2_iterator a = {
821  .c = c,
822  .flags = flags
823  };
824 
825  ao2_ref(c, +1);
826 
827  return a;
828 }
829 
830 /*!
831  * destroy an iterator
832  */
834 {
835  ao2_ref(i->c, -1);
836  if (i->flags & AO2_ITERATOR_MALLOCD) {
837  ast_free(i);
838  } else {
839  i->c = NULL;
840  }
841 }
842 
843 /*
844  * move to the next element in the container.
845  */
846 static void *internal_ao2_iterator_next(struct ao2_iterator *a, struct bucket_entry **q)
847 {
848  int lim;
849  struct bucket_entry *p = NULL;
850  void *ret = NULL;
851 
852  *q = NULL;
853 
854  if (INTERNAL_OBJ(a->c) == NULL)
855  return NULL;
856 
857  if (!(a->flags & AO2_ITERATOR_DONTLOCK))
858  ao2_lock(a->c);
859 
860  /* optimization. If the container is unchanged and
861  * we have a pointer, try follow it
862  */
863  if (a->c->version == a->c_version && (p = a->obj)) {
864  if ((p = AST_LIST_NEXT(p, entry)))
865  goto found;
866  /* nope, start from the next bucket */
867  a->bucket++;
868  a->version = 0;
869  a->obj = NULL;
870  }
871 
872  lim = a->c->n_buckets;
873 
874  /* Browse the buckets array, moving to the next
875  * buckets if we don't find the entry in the current one.
876  * Stop when we find an element with version number greater
877  * than the current one (we reset the version to 0 when we
878  * switch buckets).
879  */
880  for (; a->bucket < lim; a->bucket++, a->version = 0) {
881  /* scan the current bucket */
882  AST_LIST_TRAVERSE(&a->c->buckets[a->bucket], p, entry) {
883  if (p->version > a->version)
884  goto found;
885  }
886  }
887 
888 found:
889  if (p) {
890  ret = EXTERNAL_OBJ(p->astobj);
891  if (a->flags & AO2_ITERATOR_UNLINK) {
892  /* we are going to modify the container, so update version */
894  AST_LIST_REMOVE(&a->c->buckets[a->bucket], p, entry);
895  /* update number of elements */
897  a->version = 0;
898  a->obj = NULL;
899  a->c_version = a->c->version;
900  ast_free(p);
901  } else {
902  a->version = p->version;
903  a->obj = p;
904  a->c_version = a->c->version;
905  /* inc refcount of returned object */
906  *q = p;
907  }
908  }
909 
910  return ret;
911 }
912 
913 void *__ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname)
914 {
915  struct bucket_entry *p;
916  void *ret = NULL;
917 
918  ret = internal_ao2_iterator_next(a, &p);
919 
920  if (p) {
921  /* inc refcount of returned object */
922  __ao2_ref_debug(ret, 1, tag, file, line, funcname);
923  }
924 
925  if (!(a->flags & AO2_ITERATOR_DONTLOCK))
926  ao2_unlock(a->c);
927 
928  return ret;
929 }
930 
932 {
933  struct bucket_entry *p = NULL;
934  void *ret = NULL;
935 
936  ret = internal_ao2_iterator_next(a, &p);
937 
938  if (p) {
939  /* inc refcount of returned object */
940  __ao2_ref(ret, 1);
941  }
942 
943  if (!(a->flags & AO2_ITERATOR_DONTLOCK))
944  ao2_unlock(a->c);
945 
946  return ret;
947 }
948 
949 /* callback for destroying container.
950  * we can make it simple as we know what it does
951  */
952 static int cd_cb(void *obj, void *arg, int flag)
953 {
954  __ao2_ref(obj, -1);
955  return 0;
956 }
957 
958 static int cd_cb_debug(void *obj, void *arg, int flag)
959 {
960  __ao2_ref_debug(obj, -1, "deref object via container destroy", __FILE__, __LINE__, __PRETTY_FUNCTION__);
961  return 0;
962 }
963 
964 static void container_destruct(void *_c)
965 {
966  struct ao2_container *c = _c;
967  int i;
968 
969  __ao2_callback(c, OBJ_UNLINK, cd_cb, NULL);
970 
971  for (i = 0; i < c->n_buckets; i++) {
972  struct bucket_entry *current;
973 
974  while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
975  ast_free(current);
976  }
977  }
978 
979 #ifdef AO2_DEBUG
980  ast_atomic_fetchadd_int(&ao2.total_containers, -1);
981 #endif
982 }
983 
984 static void container_destruct_debug(void *_c)
985 {
986  struct ao2_container *c = _c;
987  int i;
988 
989  __ao2_callback_debug(c, OBJ_UNLINK, cd_cb_debug, NULL, "container_destruct_debug called", __FILE__, __LINE__, __PRETTY_FUNCTION__);
990 
991  for (i = 0; i < c->n_buckets; i++) {
992  struct bucket_entry *current;
993 
994  while ((current = AST_LIST_REMOVE_HEAD(&c->buckets[i], entry))) {
995  ast_free(current);
996  }
997  }
998 
999 #ifdef AO2_DEBUG
1000  ast_atomic_fetchadd_int(&ao2.total_containers, -1);
1001 #endif
1002 }
1003 
1004 #ifdef AO2_DEBUG
1005 static int print_cb(void *obj, void *arg, int flag)
1006 {
1007  struct ast_cli_args *a = (struct ast_cli_args *) arg;
1008  char *s = (char *)obj;
1009 
1010  ast_cli(a->fd, "string <%s>\n", s);
1011  return 0;
1012 }
1013 
1014 /*
1015  * Print stats
1016  */
1017 static char *handle_astobj2_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1018 {
1019  switch (cmd) {
1020  case CLI_INIT:
1021  e->command = "astobj2 show stats";
1022  e->usage = "Usage: astobj2 show stats\n"
1023  " Show astobj2 show stats\n";
1024  return NULL;
1025  case CLI_GENERATE:
1026  return NULL;
1027  }
1028  ast_cli(a->fd, "Objects : %d\n", ao2.total_objects);
1029  ast_cli(a->fd, "Containers : %d\n", ao2.total_containers);
1030  ast_cli(a->fd, "Memory : %d\n", ao2.total_mem);
1031  ast_cli(a->fd, "Locked : %d\n", ao2.total_locked);
1032  ast_cli(a->fd, "Refs : %d\n", ao2.total_refs);
1033  return CLI_SUCCESS;
1034 }
1035 
1036 /*
1037  * This is testing code for astobj
1038  */
1039 static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1040 {
1041  struct ao2_container *c1;
1042  int i, lim;
1043  char *obj;
1044  static int prof_id = -1;
1045  struct ast_cli_args fake_args = { a->fd, 0, NULL };
1046 
1047  switch (cmd) {
1048  case CLI_INIT:
1049  e->command = "astobj2 test";
1050  e->usage = "Usage: astobj2 test <num>\n"
1051  " Runs astobj2 test. Creates 'num' objects,\n"
1052  " and test iterators, callbacks and may be other stuff\n";
1053  return NULL;
1054  case CLI_GENERATE:
1055  return NULL;
1056  }
1057 
1058  if (a->argc != 3) {
1059  return CLI_SHOWUSAGE;
1060  }
1061 
1062  if (prof_id == -1)
1063  prof_id = ast_add_profile("ao2_alloc", 0);
1064 
1065  ast_cli(a->fd, "argc %d argv %s %s %s\n", a->argc, a->argv[0], a->argv[1], a->argv[2]);
1066  lim = atoi(a->argv[2]);
1067  ast_cli(a->fd, "called astobj_test\n");
1068 
1069  handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
1070  /*
1071  * allocate a container with no default callback, and no hash function.
1072  * No hash means everything goes in the same bucket.
1073  */
1074  c1 = ao2_t_container_alloc(100, NULL /* no callback */, NULL /* no hash */,"test");
1075  ast_cli(a->fd, "container allocated as %p\n", c1);
1076 
1077  /*
1078  * fill the container with objects.
1079  * ao2_alloc() gives us a reference which we pass to the
1080  * container when we do the insert.
1081  */
1082  for (i = 0; i < lim; i++) {
1083  ast_mark(prof_id, 1 /* start */);
1084  obj = ao2_t_alloc(80, NULL,"test");
1085  ast_mark(prof_id, 0 /* stop */);
1086  ast_cli(a->fd, "object %d allocated as %p\n", i, obj);
1087  sprintf(obj, "-- this is obj %d --", i);
1088  ao2_link(c1, obj);
1089  /* At this point, the refcount on obj is 2 due to the allocation
1090  * and linking. We can go ahead and reduce the refcount by 1
1091  * right here so that when the container is unreffed later, the
1092  * objects will be freed
1093  */
1094  ao2_t_ref(obj, -1, "test");
1095  }
1096  ast_cli(a->fd, "testing callbacks\n");
1097  ao2_t_callback(c1, 0, print_cb, a, "test callback");
1098  ast_cli(a->fd, "testing iterators, remove every second object\n");
1099  {
1100  struct ao2_iterator ai;
1101  int x = 0;
1102 
1103  ai = ao2_iterator_init(c1, 0);
1104  while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
1105  ast_cli(a->fd, "iterator on <%s>\n", obj);
1106  if (x++ & 1)
1107  ao2_t_unlink(c1, obj,"test");
1108  ao2_t_ref(obj, -1,"test");
1109  }
1110  ao2_iterator_destroy(&ai);
1111  ast_cli(a->fd, "testing iterators again\n");
1112  ai = ao2_iterator_init(c1, 0);
1113  while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
1114  ast_cli(a->fd, "iterator on <%s>\n", obj);
1115  ao2_t_ref(obj, -1,"test");
1116  }
1117  ao2_iterator_destroy(&ai);
1118  }
1119  ast_cli(a->fd, "testing callbacks again\n");
1120  ao2_t_callback(c1, 0, print_cb, a, "test callback");
1121 
1122  ast_verbose("now you should see an error message:\n");
1123  ao2_t_ref(&i, -1, ""); /* i is not a valid object so we print an error here */
1124 
1125  ast_cli(a->fd, "destroy container\n");
1126  ao2_t_ref(c1, -1, ""); /* destroy container */
1127  handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
1128  return CLI_SUCCESS;
1129 }
1130 
1131 static struct ast_cli_entry cli_astobj2[] = {
1132  AST_CLI_DEFINE(handle_astobj2_stats, "Print astobj2 statistics"),
1133  AST_CLI_DEFINE(handle_astobj2_test, "Test astobj2"),
1134 };
1135 #endif /* AO2_DEBUG */
1136 
1137 static void astobj2_cleanup(void)
1138 {
1139 #ifdef AO2_DEBUG
1140  ast_cli_unregister_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
1141 #endif
1142 
1143 #ifdef REF_DEBUG
1144  fclose(ref_log);
1145  ref_log = NULL;
1146 #endif
1147 }
1148 
1149 
1150 int astobj2_init(void)
1151 {
1152 #ifdef REF_DEBUG
1153  char ref_filename[1024];
1154 #endif
1155 
1156 #ifdef REF_DEBUG
1157  snprintf(ref_filename, sizeof(ref_filename), "%s/refs", ast_config_AST_LOG_DIR);
1158  ref_log = fopen(ref_filename, "w");
1159  if (!ref_log) {
1160  ast_log(LOG_ERROR, "Could not open ref debug log file: %s\n", ref_filename);
1161  }
1162 #endif
1163 
1164 #ifdef AO2_DEBUG
1165  ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
1166 #endif
1167 
1169  return 0;
1170 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:471
struct astobj2 * astobj
Definition: astobj2.c:483
unsigned int c_version
Definition: astobj2.h:1061
static void * internal_ao2_callback(struct ao2_container *c, const enum search_flags flags, void *cb_fn, void *arg, void *data, enum ao2_callback_type type, char *tag, char *file, int line, const char *funcname)
Definition: astobj2.c:599
static struct bucket_entry * internal_ao2_link(struct ao2_container *c, void *user_data, const char *file, int line, const char *func)
Definition: astobj2.c:490
void ast_std_free(void *ptr)
int64_t ast_mark(int, int start1_stop0)
Definition: asterisk.c:775
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
void ao2_bt(void)
Definition: astobj2.c:90
Asterisk main include file. File version handling, generic pbx functions.
#define ao2_link(arg1, arg2)
Definition: astobj2.h:785
static int cd_cb(void *obj, void *arg, int flag)
Definition: astobj2.c:952
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
Definition: astobj2.c:470
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static int internal_ao2_ref(void *user_data, const int delta)
Definition: astobj2.c:253
static void astobj2_cleanup(void)
Definition: astobj2.c:1137
static void container_destruct(void *c)
Definition: astobj2.c:964
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Allocate and initialize an object.
Definition: astobj2.h:429
void * __ao2_callback_data(struct ao2_container *c, enum search_flags flags, ao2_callback_data_fn *cb_fn, void *arg, void *data)
Definition: astobj2.c:796
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
static struct ao2_container * internal_ao2_container_alloc(struct ao2_container *c, const uint n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
descriptor for a cli entry.
Definition: cli.h:165
const int argc
Definition: cli.h:154
int n_buckets
Definition: astobj2.c:394
void ast_verbose(const char *fmt,...)
Definition: logger.c:1568
int ref_counter
Definition: astobj2.c:49
void * __ao2_find(struct ao2_container *c, void *arg, enum search_flags flags)
Definition: astobj2.c:810
#define var
Definition: ast_expr2f.c:606
#define ao2_t_iterator_next(arg1, arg2)
Definition: astobj2.h:1125
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Definition: linkedlists.h:438
size_t data_size
Definition: astobj2.c:52
int __ao2_unlock(void *a, const char *file, const char *func, int line, const char *var)
Unlock an object.
Definition: astobj2.c:175
Definition: cli.h:146
Continue if a match is not found in the hashed out bucket.
Definition: astobj2.h:687
char ** ast_bt_get_symbols(void **addresses, size_t num_frames)
Definition: logger.c:1335
void * __ao2_callback(struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg)
Definition: astobj2.c:782
void * __ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
#define ast_assert(a)
Definition: utils.h:738
#define ao2_unlock(a)
Definition: astobj2.h:497
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
Definition: astobj2.c:818
struct bucket_entry::@222 entry
search_flags
Flags passed to ao2_callback() and ao2_hash_fn() to modify its behaviour.
Definition: astobj2.h:660
#define ao2_t_container_alloc(arg1, arg2, arg3, arg4)
Allocate and initialize a container with the desired number of buckets.
Definition: astobj2.h:733
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
static void container_destruct_debug(void *c)
Definition: astobj2.c:984
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:841
void * __ao2_link_debug(struct ao2_container *c, void *new_obj, char *tag, char *file, int line, const char *funcname)
Definition: astobj2.c:520
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:600
struct ao2_container * c
Definition: astobj2.h:1055
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
Definition: lock.h:603
static int cd_cb_debug(void *obj, void *arg, int flag)
Definition: astobj2.c:958
int __ao2_trylock(void *a, const char *file, const char *func, int line, const char *var)
Try locking– (don&#39;t block if fail)
Definition: astobj2.c:189
Utility functions.
#define AO2_MAGIC
Definition: astobj2.c:58
void * ao2_object_get_lockaddr(void *obj)
Return the lock address of an object.
Definition: astobj2.c:205
void * __ao2_alloc_debug(const size_t data_size, ao2_destructor_fn destructor_fn, char *tag, const char *file, int line, const char *funcname, int ref_debug)
Definition: astobj2.c:335
Asterisk file paths, configured in asterisk.conf.
int ast_get_tid(void)
Get current thread ID.
Definition: utils.c:2346
const int fd
Definition: cli.h:153
struct sla_ringing_trunk * last
Definition: app_meetme.c:965
int __ao2_ref(void *o, int delta)
Definition: astobj2.c:248
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:554
#define ao2_ref(o, delta)
Definition: astobj2.h:472
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: asterisk.c:998
ao2_destructor_fn destructor_fn
Definition: astobj2.c:50
#define ao2_lock(a)
Definition: astobj2.h:488
void(* ao2_destructor_fn)(void *)
Typedef for an object destructor. This is called just before freeing the memory for the object...
Definition: astobj2.h:395
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
static struct astobj2 * INTERNAL_OBJ(void *user_data)
convert from a pointer _p to a user-defined object
Definition: astobj2.c:112
#define EXTERNAL_OBJ(_p)
convert from a pointer _p to an astobj2 object
Definition: astobj2.c:148
const char *const * argv
Definition: cli.h:155
int ast_add_profile(const char *, uint64_t scale)
support for event profiling
Definition: asterisk.c:710
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:224
void * obj
Definition: astobj2.h:1063
int __ao2_lock(void *a, const char *file, const char *func, int line, const char *var)
Lock an object.
Definition: astobj2.c:161
int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:399
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
#define ao2_t_unlink(arg1, arg2, arg3)
Remove an object from a container.
Definition: astobj2.h:816
#define CLI_SHOWUSAGE
Definition: cli.h:44
static void * internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, const char *file, int line, const char *funcname)
Definition: astobj2.c:302
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
Definition: astobj2.c:586
#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:909
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
const char * ast_config_AST_LOG_DIR
Definition: asterisk.c:263
int astobj2_init(void)
Definition: astobj2.c:1150
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
struct ao2_container * __ao2_container_alloc(const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn)
Definition: astobj2.c:454
#define ast_free(a)
Definition: astmm.h:97
char * command
Definition: cli.h:180
ao2_callback_type
Definition: astobj2.c:138
static const char type[]
Definition: chan_nbs.c:57
void ao2_iterator_destroy(struct ao2_iterator *i)
Destroy a container iterator.
Definition: astobj2.c:833
void * __ao2_callback_debug(struct ao2_container *c, enum search_flags flags, ao2_callback_fn *cb_fn, void *arg, char *tag, char *file, int line, const char *funcname)
Definition: astobj2.c:774
static int cb_true(void *user_data, void *arg, int flags)
special callback that matches all
Definition: astobj2.c:578
ao2_callback_fn ao2_match_by_addr
a very common callback is one that matches by address.
Definition: astobj2.h:646
const char * usage
Definition: cli.h:171
#define CLI_SUCCESS
Definition: cli.h:43
static int hash_zero(const void *user_obj, const int flags)
always zero hash function
Definition: astobj2.c:412
int elements
Definition: astobj2.c:396
void * user_data[0]
Definition: astobj2.c:66
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1053
Standard Command Line Interface.
struct ao2_container * __ao2_container_alloc_debug(const unsigned int n_buckets, ao2_hash_fn *hash_fn, ao2_callback_fn *cmp_fn, char *tag, char *file, int line, const char *funcname, int ref_debug)
Definition: astobj2.c:441
#define ast_calloc(a, b)
Definition: astmm.h:82
#define ao2_container_alloc(arg1, arg2, arg3)
Definition: astobj2.h:734
int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:177
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
int( ao2_hash_fn)(const void *obj, const int flags)
Definition: astobj2.h:695
void * __ao2_unlink(struct ao2_container *c, void *obj)
Definition: astobj2.c:565
struct __priv_data priv_data
Definition: astobj2.c:65
void * __ao2_find_debug(struct ao2_container *c, void *arg, enum search_flags flags, char *tag, char *file, int line, const char *funcname)
Definition: astobj2.c:805
int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:317
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
#define ast_mutex_init(pmutex)
Definition: lock.h:152
Definition: astobj2.c:480
int __ao2_ref_debug(void *o, int delta, const char *tag, const char *file, int line, const char *funcname)
Definition: astobj2.c:219
#define ast_mutex_destroy(a)
Definition: lock.h:154
ao2_hash_fn * hash_fn
Definition: astobj2.c:392
static void * internal_ao2_iterator_next(struct ao2_iterator *a, struct bucket_entry **q)
Definition: astobj2.c:846
static FILE * ref_log
Definition: astobj2.c:35
void * __ao2_callback_data_debug(struct ao2_container *c, enum search_flags flags, ao2_callback_data_fn *cb_fn, void *arg, void *data, char *tag, char *file, int line, const char *funcname)
Definition: astobj2.c:788
int version
Definition: astobj2.c:482
void * __ao2_unlink_debug(struct ao2_container *c, void *obj, char *tag, char *file, int line, const char *funcname)
Definition: astobj2.c:554
void * __ao2_alloc(const size_t data_size, ao2_destructor_fn destructor_fn)
Definition: astobj2.c:354
static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition: chan_iax2.c:2069
unsigned int version
Definition: astobj2.h:1065
#define N1
void * __ao2_iterator_next_debug(struct ao2_iterator *a, char *tag, char *file, int line, const char *funcname)
Definition: astobj2.c:913
void * __ao2_link(struct ao2_container *c, void *newobj)
Definition: astobj2.c:531
ao2_hash_fn * hash_fn
Event type specific hash function.
Definition: event.c:165
void * __ao2_iterator_next(struct ao2_iterator *a)
Definition: astobj2.c:931
int( ao2_callback_data_fn)(void *obj, void *arg, void *data, int flags)
Type of a generic callback function.
Definition: astobj2.h:643
int( ao2_callback_fn)(void *obj, void *arg, int flags)
Type of a generic callback function.
Definition: astobj2.h:631
ao2_callback_fn * cmp_fn
Definition: astobj2.c:393
struct bucket buckets[0]
Definition: astobj2.c:400
Structure for mutex and tracking information.
Definition: lock.h:121
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
Definition: asterisk.h:180
ast_mutex_t lock
Definition: astobj2.c:48
uint32_t magic
Definition: astobj2.c:55