Asterisk - The Open Source Telephony Project  18.5.0
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 /*! \file
18  *
19  * \brief Functions implementing astobj2 objects.
20  *
21  * \author Richard Mudgett <[email protected]>
22  */
23 
24 /*** MODULEINFO
25  <support_level>core</support_level>
26  ***/
27 
28 /* This reduces the size of lock structures within astobj2 objects when
29  * DEBUG_THREADS is not defined. */
30 #define DEBUG_THREADS_LOOSE_ABI
31 
32 #include "asterisk.h"
33 
34 #include "asterisk/_private.h"
35 #include "asterisk/astobj2.h"
36 #include "astobj2_private.h"
38 #include "asterisk/cli.h"
39 #include "asterisk/paths.h"
40 
41 /* Use ast_log_safe in place of ast_log. */
42 #define ast_log ast_log_safe
43 
44 static FILE *ref_log;
45 
46 /*!
47  * astobj2 objects are always preceded by this data structure,
48  * which contains a reference counter,
49  * option flags and a pointer to a destructor.
50  * The refcount is used to decide when it is time to
51  * invoke the destructor.
52  * The magic number is used for consistency check.
53  */
54 struct __priv_data {
56  /*! This field is used for astobj2 and ao2_weakproxy objects to reference each other */
57  void *weakptr;
58 #if defined(AO2_DEBUG)
59  /*! User data size for stats */
60  size_t data_size;
61 #endif
62  /*! Number of references held for this object */
64  /*!
65  * \brief The ao2 object option flags.
66  *
67  * \note This field is constant after object creation. It shares
68  * a uint32_t with \ref lockused and \ref magic.
69  */
70  uint32_t options:3;
71  /*!
72  * \brief Set to 1 when the lock is used if refdebug is enabled.
73  *
74  * \note This bit-field may be modified after object creation. It
75  * shares a uint32_t with \ref options and \ref magic.
76  */
77  uint32_t lockused:1;
78  /*!
79  * \brief Magic number.
80  *
81  * This is used to verify that a pointer is a valid astobj2 or ao2_weak
82  * reference.
83  *
84  * \note This field is constant after object creation. It shares
85  * a uint32_t with \ref options and \ref lockused.
86  *
87  * \warning Stealing bits for any additional writable fields would cause
88  * reentrancy issues if using bitfields. If any additional
89  * writable bits are required in the future we will need to put
90  * all bitfields into a single 'uint32_t flags' field and use
91  * atomic operations from \file lock.h to perform writes.
92  */
93  uint32_t magic:28;
94 };
95 
96 #define AO2_MAGIC 0xa70b123
97 #define AO2_WEAK 0xa70b122
98 #define IS_AO2_MAGIC_BAD(p) (AO2_MAGIC != (p->priv_data.magic | 1))
99 
100 /*!
101  * What an astobj2 object looks like: fixed-size private data
102  * followed by variable-size user data.
103  */
104 struct astobj2 {
105  struct __priv_data priv_data;
106  void *user_data[0];
107 };
108 
111  void *data;
113 };
114 
117 };
118 
119 /* AstObj2 with recursive lock. */
120 struct astobj2_lock {
122  struct __priv_data priv_data;
123  void *user_data[0];
124 };
125 
128  /*! Count of the number of threads holding a lock on this object. -1 if it is the write lock. */
130 };
131 
132 /* AstObj2 with RW lock. */
134  struct ao2_rwlock_priv rwlock;
135  struct __priv_data priv_data;
136  void *user_data[0];
137 };
138 
140  void *lock;
141 };
142 
143 /* AstObj2 with locking provided by a separate object. */
145  struct ao2_lockobj_priv lockobj;
146  struct __priv_data priv_data;
147  void *user_data[0];
148 };
149 
150 #ifdef AO2_DEBUG
151 struct ao2_stats ao2;
152 #endif
153 
154 #define INTERNAL_OBJ_MUTEX(user_data) \
155  ((struct astobj2_lock *) (((char *) (user_data)) - sizeof(struct astobj2_lock)))
156 
157 #define INTERNAL_OBJ_RWLOCK(user_data) \
158  ((struct astobj2_rwlock *) (((char *) (user_data)) - sizeof(struct astobj2_rwlock)))
159 
160 #define INTERNAL_OBJ_LOCKOBJ(user_data) \
161  ((struct astobj2_lockobj *) (((char *) (user_data)) - sizeof(struct astobj2_lockobj)))
162 
163 #define INTERNAL_OBJ(user_data) \
164  (struct astobj2 *) ((char *) user_data - sizeof(struct astobj2))
165 
166 /*!
167  * \brief convert from a pointer _p to a user-defined object
168  *
169  * \return the pointer to the astobj2 structure
170  */
171 #define __INTERNAL_OBJ_CHECK(user_data, file, line, func) \
172  ({ \
173  struct astobj2 *p ## __LINE__; \
174  if (!user_data \
175  || !(p ## __LINE__ = INTERNAL_OBJ(user_data)) \
176  || IS_AO2_MAGIC_BAD(p ## __LINE__)) { \
177  log_bad_ao2(user_data, file, line, func); \
178  p ## __LINE__ = NULL; \
179  } \
180  (p ## __LINE__); \
181  })
182 
183 #define INTERNAL_OBJ_CHECK(user_data) \
184  __INTERNAL_OBJ_CHECK(user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__)
185 
186 /*!
187  * \brief convert from a pointer _p to an astobj2 object
188  *
189  * \return the pointer to the user-defined portion.
190  */
191 #define EXTERNAL_OBJ(_p) ((_p) == NULL ? NULL : (_p)->user_data)
192 
193 int internal_is_ao2_object(void *user_data)
194 {
195  struct astobj2 *p;
196 
197  if (!user_data) {
198  return 0;
199  }
200 
201  p = INTERNAL_OBJ(user_data);
202 
203  return !p || IS_AO2_MAGIC_BAD(p) ? 0 : 1;
204 }
205 
206 void log_bad_ao2(void *user_data, const char *file, int line, const char *func)
207 {
208  struct astobj2 *p;
209  char bad_magic[100];
210 
211  if (!user_data) {
212  __ast_assert_failed(0, "user_data is NULL", file, line, func);
213  return;
214  }
215 
216  p = INTERNAL_OBJ(user_data);
217  snprintf(bad_magic, sizeof(bad_magic), "bad magic number 0x%x for object %p",
218  p->priv_data.magic, user_data);
219  __ast_assert_failed(0, bad_magic, file, line, func);
220 }
221 
222 int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
223 {
224  struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
225  struct astobj2_lock *obj_mutex;
226  struct astobj2_rwlock *obj_rwlock;
227  struct astobj2_lockobj *obj_lockobj;
228  int res = 0;
229 
230  if (obj == NULL) {
231  return -1;
232  }
233 
234  if (ref_log) {
235  obj->priv_data.lockused = 1;
236  }
237 
238  switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
240  obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
241  res = __ast_pthread_mutex_lock(file, line, func, var, &obj_mutex->mutex.lock);
242 #ifdef AO2_DEBUG
243  if (!res) {
244  ast_atomic_fetchadd_int(&ao2.total_locked, 1);
245  }
246 #endif
247  break;
249  obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
250  switch (lock_how) {
251  case AO2_LOCK_REQ_MUTEX:
252  case AO2_LOCK_REQ_WRLOCK:
253  res = __ast_rwlock_wrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
254  if (!res) {
255  ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1);
256 #ifdef AO2_DEBUG
257  ast_atomic_fetchadd_int(&ao2.total_locked, 1);
258 #endif
259  }
260  break;
261  case AO2_LOCK_REQ_RDLOCK:
262  res = __ast_rwlock_rdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
263  if (!res) {
264  ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1);
265 #ifdef AO2_DEBUG
266  ast_atomic_fetchadd_int(&ao2.total_locked, 1);
267 #endif
268  }
269  break;
270  }
271  break;
273  /* The ao2 object has no lock. */
274  break;
276  obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data);
277  res = __ao2_lock(obj_lockobj->lockobj.lock, lock_how, file, func, line, var);
278  break;
279  default:
280  ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
281  user_data);
282  return -1;
283  }
284 
285  return res;
286 }
287 
288 int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
289 {
290  struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
291  struct astobj2_lock *obj_mutex;
292  struct astobj2_rwlock *obj_rwlock;
293  struct astobj2_lockobj *obj_lockobj;
294  int res = 0;
295  int current_value;
296 
297  if (obj == NULL) {
298  return -1;
299  }
300 
301  switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
303  obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
304  res = __ast_pthread_mutex_unlock(file, line, func, var, &obj_mutex->mutex.lock);
305 #ifdef AO2_DEBUG
306  if (!res) {
307  ast_atomic_fetchadd_int(&ao2.total_locked, -1);
308  }
309 #endif
310  break;
312  obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
313 
314  current_value = ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1) - 1;
315  if (current_value < 0) {
316  /* It was a WRLOCK that we are unlocking. Fix the count. */
317  ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -current_value);
318  }
319  res = __ast_rwlock_unlock(file, line, func, &obj_rwlock->rwlock.lock, var);
320 #ifdef AO2_DEBUG
321  if (!res) {
322  ast_atomic_fetchadd_int(&ao2.total_locked, -1);
323  }
324 #endif
325  break;
327  /* The ao2 object has no lock. */
328  break;
330  obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data);
331  res = __ao2_unlock(obj_lockobj->lockobj.lock, file, func, line, var);
332  break;
333  default:
334  ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
335  user_data);
336  res = -1;
337  break;
338  }
339  return res;
340 }
341 
342 int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
343 {
344  struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
345  struct astobj2_lock *obj_mutex;
346  struct astobj2_rwlock *obj_rwlock;
347  struct astobj2_lockobj *obj_lockobj;
348  int res = 0;
349 
350  if (obj == NULL) {
351  return -1;
352  }
353 
354  if (ref_log) {
355  obj->priv_data.lockused = 1;
356  }
357 
358  switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
360  obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
361  res = __ast_pthread_mutex_trylock(file, line, func, var, &obj_mutex->mutex.lock);
362 #ifdef AO2_DEBUG
363  if (!res) {
364  ast_atomic_fetchadd_int(&ao2.total_locked, 1);
365  }
366 #endif
367  break;
369  obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
370  switch (lock_how) {
371  case AO2_LOCK_REQ_MUTEX:
372  case AO2_LOCK_REQ_WRLOCK:
373  res = __ast_rwlock_trywrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
374  if (!res) {
375  ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, -1);
376 #ifdef AO2_DEBUG
377  ast_atomic_fetchadd_int(&ao2.total_locked, 1);
378 #endif
379  }
380  break;
381  case AO2_LOCK_REQ_RDLOCK:
382  res = __ast_rwlock_tryrdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
383  if (!res) {
384  ast_atomic_fetchadd_int(&obj_rwlock->rwlock.num_lockers, +1);
385 #ifdef AO2_DEBUG
386  ast_atomic_fetchadd_int(&ao2.total_locked, 1);
387 #endif
388  }
389  break;
390  }
391  break;
393  /* The ao2 object has no lock. */
394  return 0;
396  obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data);
397  res = __ao2_trylock(obj_lockobj->lockobj.lock, lock_how, file, func, line, var);
398  break;
399  default:
400  ast_log(__LOG_ERROR, file, line, func, "Invalid lock option on ao2 object %p\n",
401  user_data);
402  return -1;
403  }
404 
405  return res;
406 }
407 
408 /*!
409  * \internal
410  * \brief Adjust an object's lock to the requested level.
411  *
412  * \param user_data An ao2 object to adjust lock level.
413  * \param lock_how What level to adjust lock.
414  * \param keep_stronger TRUE if keep original lock level if it is stronger.
415  *
416  * \pre The ao2 object is already locked.
417  *
418  * \details
419  * An ao2 object with a RWLOCK will have its lock level adjusted
420  * to the specified level if it is not already there. An ao2
421  * object with a different type of lock is not affected.
422  *
423  * \return Original lock level.
424  */
425 enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
426 {
427  struct astobj2 *obj = INTERNAL_OBJ(user_data);
428  struct astobj2_rwlock *obj_rwlock;
429  struct astobj2_lockobj *obj_lockobj;
430  enum ao2_lock_req orig_lock;
431 
432  switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
434  obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
435  if (obj_rwlock->rwlock.num_lockers < 0) {
436  orig_lock = AO2_LOCK_REQ_WRLOCK;
437  } else {
438  orig_lock = AO2_LOCK_REQ_RDLOCK;
439  }
440  switch (lock_how) {
441  case AO2_LOCK_REQ_MUTEX:
442  lock_how = AO2_LOCK_REQ_WRLOCK;
443  /* Fall through */
444  case AO2_LOCK_REQ_WRLOCK:
445  if (lock_how != orig_lock) {
446  /* Switch from read lock to write lock. */
447  ao2_unlock(user_data);
448  ao2_wrlock(user_data);
449  }
450  break;
451  case AO2_LOCK_REQ_RDLOCK:
452  if (!keep_stronger && lock_how != orig_lock) {
453  /* Switch from write lock to read lock. */
454  ao2_unlock(user_data);
455  ao2_rdlock(user_data);
456  }
457  break;
458  }
459  break;
461  obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data);
462  orig_lock = __adjust_lock(obj_lockobj->lockobj.lock, lock_how, keep_stronger);
463  break;
464  default:
465  ast_log(LOG_ERROR, "Invalid lock option on ao2 object %p\n", user_data);
466  /* Fall through */
469  orig_lock = AO2_LOCK_REQ_MUTEX;
470  break;
471  }
472 
473  return orig_lock;
474 }
475 
477 {
478  struct astobj2 *obj;
479  struct astobj2_lock *obj_mutex;
480 
481  obj = INTERNAL_OBJ_CHECK(user_data);
482 
483  if (obj == NULL) {
484  return NULL;
485  }
486 
487  switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
489  obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
490  return &obj_mutex->mutex.lock;
491  default:
492  break;
493  }
494 
495  return NULL;
496 }
497 
498 int __ao2_ref(void *user_data, int delta,
499  const char *tag, const char *file, int line, const char *func)
500 {
501  struct astobj2 *obj = __INTERNAL_OBJ_CHECK(user_data, file, line, func);
502  struct astobj2_lock *obj_mutex;
503  struct astobj2_rwlock *obj_rwlock;
504  struct astobj2_lockobj *obj_lockobj;
505  int32_t current_value;
506  int32_t ret;
507  struct ao2_weakproxy *weakproxy = NULL;
508  const char *lock_state;
509 
510  if (obj == NULL) {
511  if (ref_log && user_data) {
512  fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
513  user_data, delta, ast_get_tid(), file, line, func, tag ?: "");
514  fflush(ref_log);
515  }
516  return -1;
517  }
518 
519  /* if delta is 0, just return the refcount */
520  if (delta == 0) {
521  return obj->priv_data.ref_counter;
522  }
523 
524  if (delta < 0 && obj->priv_data.magic == AO2_MAGIC && (weakproxy = obj->priv_data.weakptr)) {
525  ao2_lock(weakproxy);
526  }
527 
528  /* we modify with an atomic operation the reference counter */
529  ret = ast_atomic_fetch_add(&obj->priv_data.ref_counter, delta, __ATOMIC_RELAXED);
530  current_value = ret + delta;
531 
532 #ifdef AO2_DEBUG
533  ast_atomic_fetchadd_int(&ao2.total_refs, delta);
534 #endif
535 
536  if (weakproxy) {
537  struct ao2_weakproxy cbs;
538 
539  if (current_value == 1) {
540  /* The only remaining reference is the one owned by the weak object */
541  struct astobj2 *internal_weakproxy;
542 
543  internal_weakproxy = INTERNAL_OBJ_CHECK(weakproxy);
544 
545  /* Unlink the obj from the weak proxy */
546  internal_weakproxy->priv_data.weakptr = NULL;
547  obj->priv_data.weakptr = NULL;
548 
549  /* transfer list to local copy so callbacks are run with weakproxy unlocked. */
550  cbs.destroyed_cb = weakproxy->destroyed_cb;
552 
553  /* weak is already unlinked from obj so this won't recurse */
554  ao2_ref(user_data, -1);
555  }
556 
557  ao2_unlock(weakproxy);
558 
559  if (current_value == 1) {
560  struct ao2_weakproxy_notification *destroyed_cb;
561 
562  /* Notify the subscribers that weakproxy now points to NULL. */
563  while ((destroyed_cb = AST_LIST_REMOVE_HEAD(&cbs.destroyed_cb, list))) {
564  destroyed_cb->cb(weakproxy, destroyed_cb->data);
565  ast_free(destroyed_cb);
566  }
567 
568  ao2_ref(weakproxy, -1);
569  }
570  }
571 
572  if (0 < current_value) {
573  /* The object still lives. */
574 #define EXCESSIVE_REF_COUNT 100000
575 
576  if (EXCESSIVE_REF_COUNT <= current_value && ret < EXCESSIVE_REF_COUNT) {
577  char excessive_ref_buf[100];
578 
579  /* We just reached or went over the excessive ref count trigger */
580  snprintf(excessive_ref_buf, sizeof(excessive_ref_buf),
581  "Excessive refcount %d reached on ao2 object %p",
582  (int)current_value, user_data);
583  ast_log(__LOG_ERROR, file, line, func, "%s\n", excessive_ref_buf);
584 
585  __ast_assert_failed(0, excessive_ref_buf, file, line, func);
586  }
587 
589  fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data,
590  (delta < 0 ? "" : "+"), delta, ast_get_tid(),
591  file, line, func, (int)ret, tag ?: "");
592  fflush(ref_log);
593  }
594  return ret;
595  }
596 
597  /* this case must never happen */
598  if (current_value < 0) {
599  ast_log(__LOG_ERROR, file, line, func,
600  "Invalid refcount %d on ao2 object %p\n", (int)current_value, user_data);
601  if (ref_log) {
602  /* Log to ref_log even if AO2_ALLOC_OPT_NO_REF_DEBUG */
603  fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
604  user_data, delta, ast_get_tid(), file, line, func, tag ?: "");
605  fflush(ref_log);
606  }
607  ast_assert(0);
608  /* stop here even if assert doesn't DO_CRASH */
609  return -1;
610  }
611 
612  /* last reference, destroy the object */
613  if (obj->priv_data.destructor_fn != NULL) {
614  obj->priv_data.destructor_fn(user_data);
615  }
616 
617 #ifdef AO2_DEBUG
618  ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
619  ast_atomic_fetchadd_int(&ao2.total_objects, -1);
620 #endif
621 
622  /* In case someone uses an object after it's been freed */
623  obj->priv_data.magic = 0;
624 
625  switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
627  obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
628  lock_state = obj->priv_data.lockused ? "used" : "unused";
629  ast_mutex_destroy(&obj_mutex->mutex.lock);
630 
631  ast_free(obj_mutex);
632  break;
634  obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
635  lock_state = obj->priv_data.lockused ? "used" : "unused";
636  ast_rwlock_destroy(&obj_rwlock->rwlock.lock);
637 
638  ast_free(obj_rwlock);
639  break;
641  lock_state = "none";
642  ast_free(obj);
643  break;
645  obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data);
646  lock_state = obj->priv_data.lockused ? "used" : "unused";
647  ao2_t_ref(obj_lockobj->lockobj.lock, -1, "release lockobj");
648 
649  ast_free(obj_lockobj);
650  break;
651  default:
652  ast_log(__LOG_ERROR, file, line, func,
653  "Invalid lock option on ao2 object %p\n", user_data);
654  lock_state = "invalid";
655  break;
656  }
657 
659  fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**destructor**lock-state:%s**,%s\n",
660  user_data, delta, ast_get_tid(), file, line, func, lock_state, tag ?: "");
661  fflush(ref_log);
662  }
663 
664  return ret;
665 }
666 
667 void __ao2_cleanup_debug(void *obj, const char *tag, const char *file, int line, const char *function)
668 {
669  if (obj) {
670  __ao2_ref(obj, -1, tag, file, line, function);
671  }
672 }
673 
674 void __ao2_cleanup(void *obj)
675 {
676  if (obj) {
677  ao2_ref(obj, -1);
678  }
679 }
680 
681 static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options,
682  void *lockobj, const char *tag, const char *file, int line, const char *func)
683 {
684  /* allocation */
685  struct astobj2 *obj;
686  struct astobj2_lock *obj_mutex;
687  struct astobj2_rwlock *obj_rwlock;
688  struct astobj2_lockobj *obj_lockobj;
689  size_t overhead;
690 
691  switch (options & AO2_ALLOC_OPT_LOCK_MASK) {
693  overhead = sizeof(*obj_mutex);
694  obj_mutex = __ast_calloc(1, overhead + data_size, file, line, func);
695  if (obj_mutex == NULL) {
696  return NULL;
697  }
698 
699  ast_mutex_init(&obj_mutex->mutex.lock);
700  obj = (struct astobj2 *) &obj_mutex->priv_data;
701  break;
703  overhead = sizeof(*obj_rwlock);
704  obj_rwlock = __ast_calloc(1, overhead + data_size, file, line, func);
705  if (obj_rwlock == NULL) {
706  return NULL;
707  }
708 
709  ast_rwlock_init(&obj_rwlock->rwlock.lock);
710  obj = (struct astobj2 *) &obj_rwlock->priv_data;
711  break;
713  overhead = sizeof(*obj);
714  obj = __ast_calloc(1, overhead + data_size, file, line, func);
715  if (obj == NULL) {
716  return NULL;
717  }
718  break;
720  lockobj = ao2_t_bump(lockobj, "set lockobj");
721  if (!lockobj) {
722  ast_log(__LOG_ERROR, file, line, func, "AO2_ALLOC_OPT_LOCK_OBJ requires a non-NULL lockobj.\n");
723  return NULL;
724  }
725 
726  overhead = sizeof(*obj_lockobj);
727  obj_lockobj = __ast_calloc(1, overhead + data_size, file, line, func);
728  if (obj_lockobj == NULL) {
729  ao2_t_ref(lockobj, -1, "release lockobj for failed alloc");
730  return NULL;
731  }
732 
733  obj_lockobj->lockobj.lock = lockobj;
734  obj = (struct astobj2 *) &obj_lockobj->priv_data;
735  break;
736  default:
737  /* Invalid option value. */
738  ast_log(__LOG_DEBUG, file, line, func, "Invalid lock option requested\n");
739  return NULL;
740  }
741 
742  /* Initialize common ao2 values. */
743  obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */
744  obj->priv_data.ref_counter = 1;
745  obj->priv_data.options = options;
746  obj->priv_data.magic = AO2_MAGIC;
747 
748 #ifdef AO2_DEBUG
749  obj->priv_data.data_size = data_size;
750  ast_atomic_fetchadd_int(&ao2.total_objects, 1);
751  ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
752  ast_atomic_fetchadd_int(&ao2.total_refs, 1);
753 #endif
754 
756  fprintf(ref_log, "%p,+1,%d,%s,%d,%s,**constructor**%zu**%zu**,%s\n",
757  EXTERNAL_OBJ(obj), ast_get_tid(), file, line, func, overhead, data_size, tag ?: "");
758  fflush(ref_log);
759  }
760 
761  /* return a pointer to the user data */
762  return EXTERNAL_OBJ(obj);
763 }
764 
765 void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options,
766  const char *tag, const char *file, int line, const char *func)
767 {
768  return internal_ao2_alloc(data_size, destructor_fn, options, NULL, tag, file, line, func);
769 }
770 
771 void *__ao2_alloc_with_lockobj(size_t data_size, ao2_destructor_fn destructor_fn, void *lockobj,
772  const char *tag, const char *file, int line, const char *func)
773 {
774  return internal_ao2_alloc(data_size, destructor_fn, AO2_ALLOC_OPT_LOCK_OBJ, lockobj,
775  tag, file, line, func);
776 }
777 
778 unsigned int ao2_options_get(void *obj)
779 {
780  struct astobj2 *orig_obj;
781 
782  orig_obj = INTERNAL_OBJ_CHECK(obj);
783  if (!orig_obj) {
784  return 0;
785  }
786  return orig_obj->priv_data.options;
787 }
788 
789 
791  const char *tag, const char *file, int line, const char *func)
792 {
793  struct ao2_weakproxy *weakproxy;
794 
795  if (data_size < sizeof(*weakproxy)) {
796  ast_assert(0);
797  ast_log(LOG_ERROR, "Requested data_size smaller than minimum.\n");
798  return NULL;
799  }
800 
801  weakproxy = __ao2_alloc(data_size, destructor_fn, AO2_ALLOC_OPT_LOCK_MUTEX,
802  tag, file, line, func);
803 
804  if (weakproxy) {
805  struct astobj2 *weakproxy_internal;
806 
807  /* Just created weakproxy, no need to check if it's valid. */
808  weakproxy_internal = INTERNAL_OBJ(weakproxy);
809  weakproxy_internal->priv_data.magic = AO2_WEAK;
810  }
811 
812  return weakproxy;
813 }
814 
815 int __ao2_weakproxy_set_object(void *weakproxy, void *obj, int flags,
816  const char *tag, const char *file, int line, const char *func)
817 {
818  struct astobj2 *weakproxy_internal = __INTERNAL_OBJ_CHECK(weakproxy, file, line, func);
819  struct astobj2 *obj_internal = __INTERNAL_OBJ_CHECK(obj, file, line, func);
820  int ret = -1;
821 
822  if (!weakproxy_internal
823  || weakproxy_internal->priv_data.magic != AO2_WEAK) {
824  return -1;
825  }
826 
827  if (!obj_internal
828  || obj_internal->priv_data.weakptr
829  || obj_internal->priv_data.magic != AO2_MAGIC) {
830  return -1;
831  }
832 
833  if (!(flags & OBJ_NOLOCK)) {
834  ao2_lock(weakproxy);
835  }
836 
837  if (!weakproxy_internal->priv_data.weakptr) {
838  __ao2_ref(obj, +1, tag, file, line, func);
839  __ao2_ref(weakproxy, +1, tag, file, line, func);
840 
841  weakproxy_internal->priv_data.weakptr = obj;
842  obj_internal->priv_data.weakptr = weakproxy;
843 
844  ret = 0;
845  }
846 
847  if (!(flags & OBJ_NOLOCK)) {
848  ao2_unlock(weakproxy);
849  /* It is possible for obj to be accessed now. It's allowed
850  * for weakproxy to already be in a container. Another thread
851  * could have been waiting for a lock on weakproxy to retrieve
852  * the object.
853  */
854  }
855 
856  return ret;
857 }
858 
859 int __ao2_weakproxy_ref_object(void *weakproxy, int delta, int flags,
860  const char *tag, const char *file, int line, const char *func)
861 {
862  struct astobj2 *internal = __INTERNAL_OBJ_CHECK(weakproxy, file, line, func);
863  int ret = -1;
864 
865  if (!internal || internal->priv_data.magic != AO2_WEAK) {
866  /* This method is meant to be run on weakproxy objects! */
867  return -2;
868  }
869 
870  /* We have a weak object, grab lock. */
871  if (!(flags & OBJ_NOLOCK)) {
872  ao2_lock(weakproxy);
873  }
874 
875  if (internal->priv_data.weakptr) {
876  ret = __ao2_ref(internal->priv_data.weakptr, delta, tag, file, line, func);
877  }
878 
879  if (!(flags & OBJ_NOLOCK)) {
880  ao2_unlock(weakproxy);
881  }
882 
883  return ret;
884 }
885 
886 void *__ao2_weakproxy_get_object(void *weakproxy, int flags,
887  const char *tag, const char *file, int line, const char *func)
888 {
889  struct astobj2 *internal = __INTERNAL_OBJ_CHECK(weakproxy, file, line, func);
890  void *obj;
891 
892  if (!internal || internal->priv_data.magic != AO2_WEAK) {
893  /* This method is meant to be run on weakproxy objects! */
894  return NULL;
895  }
896 
897  /* We have a weak object, grab reference to object within lock */
898  if (!(flags & OBJ_NOLOCK)) {
899  ao2_lock(weakproxy);
900  }
901 
902  obj = internal->priv_data.weakptr;
903  if (obj) {
904  __ao2_ref(obj, +1, tag, file, line, func);
905  }
906 
907  if (!(flags & OBJ_NOLOCK)) {
908  ao2_unlock(weakproxy);
909  }
910 
911  return obj;
912 }
913 
914 void *__ao2_get_weakproxy(void *obj, const char *tag, const char *file, int line, const char *func)
915 {
916  struct astobj2 *obj_internal = __INTERNAL_OBJ_CHECK(obj, file, line, func);
917 
918  if (!obj_internal || obj_internal->priv_data.magic != AO2_MAGIC) {
919  /* This method is meant to be run on normal ao2 objects! */
920  return NULL;
921  }
922 
923  if (!obj_internal->priv_data.weakptr) {
924  return NULL;
925  }
926 
927  __ao2_ref(obj_internal->priv_data.weakptr, +1, tag, file, line, func);
928  return obj_internal->priv_data.weakptr;
929 }
930 
931 int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, void *data, int flags)
932 {
933  struct astobj2 *weakproxy_internal = INTERNAL_OBJ_CHECK(weakproxy);
934  int ret = -1;
935  int hasobj;
936 
937  if (!weakproxy_internal || weakproxy_internal->priv_data.magic != AO2_WEAK) {
938  return -1;
939  }
940 
941  if (!(flags & OBJ_NOLOCK)) {
942  ao2_lock(weakproxy);
943  }
944 
945  hasobj = weakproxy_internal->priv_data.weakptr != NULL;
946  if (hasobj) {
947  struct ao2_weakproxy *weak = weakproxy;
948  struct ao2_weakproxy_notification *sub = ast_calloc(1, sizeof(*sub));
949 
950  if (sub) {
951  sub->cb = cb;
952  sub->data = data;
953  AST_LIST_INSERT_HEAD(&weak->destroyed_cb, sub, list);
954  ret = 0;
955  }
956  }
957 
958  if (!(flags & OBJ_NOLOCK)) {
959  ao2_unlock(weakproxy);
960  }
961 
962  if (!hasobj) {
963  cb(weakproxy, data);
964  ret = 0;
965  }
966 
967  return ret;
968 }
969 
970 int ao2_weakproxy_unsubscribe(void *weakproxy, ao2_weakproxy_notification_cb destroyed_cb, void *data, int flags)
971 {
972  struct astobj2 *internal_weakproxy = INTERNAL_OBJ_CHECK(weakproxy);
973  struct ao2_weakproxy *weak;
975  int ret = 0;
976 
977  if (!internal_weakproxy || internal_weakproxy->priv_data.magic != AO2_WEAK || !destroyed_cb) {
978  return -1;
979  }
980 
981  if (!(flags & OBJ_NOLOCK)) {
982  ao2_lock(weakproxy);
983  }
984 
985  weak = weakproxy;
987  if (sub->cb == destroyed_cb && sub->data == data) {
989  ast_free(sub);
990  ret++;
991  if (!(flags & OBJ_MULTIPLE)) {
992  break;
993  }
994  }
995  }
997 
998  if (!(flags & OBJ_NOLOCK)) {
999  ao2_unlock(weakproxy);
1000  }
1001 
1002  return ret;
1003 }
1004 
1005 
1006 #ifdef AO2_DEBUG
1007 static int print_cb(void *obj, void *arg, int flag)
1008 {
1009  struct ast_cli_args *a = (struct ast_cli_args *) arg;
1010  char *s = (char *)obj;
1011 
1012  ast_cli(a->fd, "string <%s>\n", s);
1013  return 0;
1014 }
1015 
1016 /*
1017  * Print stats
1018  */
1019 static char *handle_astobj2_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1020 {
1021  switch (cmd) {
1022  case CLI_INIT:
1023  e->command = "astobj2 show stats";
1024  e->usage = "Usage: astobj2 show stats\n"
1025  " Show astobj2 show stats\n";
1026  return NULL;
1027  case CLI_GENERATE:
1028  return NULL;
1029  }
1030  ast_cli(a->fd, "Objects : %d\n", ao2.total_objects);
1031  ast_cli(a->fd, "Containers : %d\n", ao2.total_containers);
1032  ast_cli(a->fd, "Memory : %d\n", ao2.total_mem);
1033  ast_cli(a->fd, "Locked : %d\n", ao2.total_locked);
1034  ast_cli(a->fd, "Refs : %d\n", ao2.total_refs);
1035  return CLI_SUCCESS;
1036 }
1037 
1038 /*
1039  * This is testing code for astobj
1040  */
1041 static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1042 {
1043  struct ao2_container *c1;
1044  struct ao2_container *c2;
1045  int i, lim;
1046  char *obj;
1047  static int prof_id = -1;
1048  struct ast_cli_args fake_args = { a->fd, 0, NULL };
1049 
1050  switch (cmd) {
1051  case CLI_INIT:
1052  e->command = "astobj2 test";
1053  e->usage = "Usage: astobj2 test <num>\n"
1054  " Runs astobj2 test. Creates 'num' objects,\n"
1055  " and test iterators, callbacks and maybe other stuff\n";
1056  return NULL;
1057  case CLI_GENERATE:
1058  return NULL;
1059  }
1060 
1061  if (a->argc != 3) {
1062  return CLI_SHOWUSAGE;
1063  }
1064 
1065  if (prof_id == -1) {
1066  prof_id = ast_add_profile("ao2_alloc", 0);
1067  }
1068 
1069  ast_cli(a->fd, "argc %d argv %s %s %s\n", a->argc, a->argv[0], a->argv[1], a->argv[2]);
1070  lim = atoi(a->argv[2]);
1071  ast_cli(a->fd, "called astobj_test\n");
1072 
1073  handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
1074  /*
1075  * Allocate a list container.
1076  */
1078  NULL /* no callback */, "test");
1079  ast_cli(a->fd, "container allocated as %p\n", c1);
1080 
1081  /*
1082  * fill the container with objects.
1083  * ao2_alloc() gives us a reference which we pass to the
1084  * container when we do the insert.
1085  */
1086  for (i = 0; i < lim; i++) {
1087  ast_mark(prof_id, 1 /* start */);
1088  obj = ao2_t_alloc(80, NULL,"test");
1089  ast_mark(prof_id, 0 /* stop */);
1090  ast_cli(a->fd, "object %d allocated as %p\n", i, obj);
1091  sprintf(obj, "-- this is obj %d --", i);
1092  ao2_link(c1, obj);
1093  /* At this point, the refcount on obj is 2 due to the allocation
1094  * and linking. We can go ahead and reduce the refcount by 1
1095  * right here so that when the container is unreffed later, the
1096  * objects will be freed
1097  */
1098  ao2_t_ref(obj, -1, "test");
1099  }
1100 
1101  ast_cli(a->fd, "testing callbacks\n");
1102  ao2_t_callback(c1, 0, print_cb, a, "test callback");
1103 
1104  ast_cli(a->fd, "testing container cloning\n");
1105  c2 = ao2_container_clone(c1, 0);
1106  if (ao2_container_count(c1) != ao2_container_count(c2)) {
1107  ast_cli(a->fd, "Cloned container does not have the same number of objects!\n");
1108  }
1109  ao2_t_callback(c2, 0, print_cb, a, "test callback");
1110 
1111  ast_cli(a->fd, "testing iterators, remove every second object\n");
1112  {
1113  struct ao2_iterator ai;
1114  int x = 0;
1115 
1116  ai = ao2_iterator_init(c1, 0);
1117  while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
1118  ast_cli(a->fd, "iterator on <%s>\n", obj);
1119  if (x++ & 1)
1120  ao2_t_unlink(c1, obj,"test");
1121  ao2_t_ref(obj, -1,"test");
1122  }
1123  ao2_iterator_destroy(&ai);
1124  ast_cli(a->fd, "testing iterators again\n");
1125  ai = ao2_iterator_init(c1, 0);
1126  while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
1127  ast_cli(a->fd, "iterator on <%s>\n", obj);
1128  ao2_t_ref(obj, -1,"test");
1129  }
1130  ao2_iterator_destroy(&ai);
1131  }
1132 
1133  ast_cli(a->fd, "testing callbacks again\n");
1134  ao2_t_callback(c1, 0, print_cb, a, "test callback");
1135 
1136  ast_verbose("now you should see an error and possible assertion failure messages:\n");
1137  ao2_t_ref(&i, -1, ""); /* i is not a valid object so we print an error here */
1138 
1139  ast_cli(a->fd, "destroy container\n");
1140  ao2_t_ref(c1, -1, ""); /* destroy container */
1141  ao2_t_ref(c2, -1, ""); /* destroy container */
1142  handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
1143  return CLI_SUCCESS;
1144 }
1145 #endif /* AO2_DEBUG */
1146 
1147 #if defined(AO2_DEBUG)
1148 static struct ast_cli_entry cli_astobj2[] = {
1149  AST_CLI_DEFINE(handle_astobj2_stats, "Print astobj2 statistics"),
1150  AST_CLI_DEFINE(handle_astobj2_test, "Test astobj2"),
1151 };
1152 #endif /* AO2_DEBUG */
1153 
1154 static void astobj2_cleanup(void)
1155 {
1156 #if defined(AO2_DEBUG)
1157  ast_cli_unregister_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
1158 #endif
1159 
1160  if (ast_opt_ref_debug) {
1161  fclose(ref_log);
1162  ref_log = NULL;
1163  }
1164 }
1165 
1166 int astobj2_init(void)
1167 {
1168  char ref_filename[1024];
1169 
1170  if (ast_opt_ref_debug) {
1171  snprintf(ref_filename, sizeof(ref_filename), "%s/refs", ast_config_AST_LOG_DIR);
1172  ref_log = fopen(ref_filename, "w");
1173  if (!ref_log) {
1174  ast_log(LOG_ERROR, "Could not open ref debug log file: %s\n", ref_filename);
1175  }
1176  }
1177 
1179 
1180  if (container_init() != 0) {
1181  fclose(ref_log);
1182  ref_log = NULL;
1183  return -1;
1184  }
1185 
1186 #if defined(AO2_DEBUG)
1187  ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
1188 #endif /* defined(AO2_DEBUG) */
1189 
1190  return 0;
1191 }
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
int __ao2_trylock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
Try locking– (don&#39;t block if fail)
Definition: astobj2.c:342
int __ao2_weakproxy_ref_object(void *weakproxy, int delta, int flags, const char *tag, const char *file, int line, const char *func)
Run ao2_t_ref on the object associated with weakproxy.
Definition: astobj2.c:859
unsigned int ao2_options_get(void *obj)
Retrieve the ao2 options used to create the object.
Definition: astobj2.c:778
int64_t ast_mark(int, int start1_stop0)
Definition: astman.c:103
void * __ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) attribute_malloc
Definition: astmm.c:1635
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
Asterisk main include file. File version handling, generic pbx functions.
int __ast_rwlock_trywrlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:1228
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
uint32_t options
The ao2 object option flags.
Definition: astobj2.c:70
int __ao2_lock(void *user_data, enum ao2_lock_req lock_how, const char *file, const char *func, int line, const char *var)
Lock an object.
Definition: astobj2.c:222
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
void(* ao2_weakproxy_notification_cb)(void *weakproxy, void *data)
Definition: astobj2.h:527
#define __LOG_DEBUG
Definition: logger.h:240
ao2_lock_req
Which lock to request.
Definition: astobj2.h:701
static void astobj2_cleanup(void)
Definition: astobj2.c:1154
#define ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:409
struct ao2_lock_priv mutex
Definition: astobj2.c:121
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
void * user_data[0]
Definition: astobj2.c:123
#define ast_rwlock_destroy(rwlock)
Definition: lock.h:231
Common, private definitions for astobj2.
#define ao2_container_clone(orig, flags)
Definition: astobj2.h:1430
descriptor for a cli entry.
Definition: cli.h:171
const int argc
Definition: cli.h:160
#define var
Definition: ast_expr2f.c:614
int __ast_rwlock_rdlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:819
#define ast_atomic_fetch_add(ptr, val, memorder)
Support for atomic instructions.
Definition: lock.h:667
Definition: cli.h:152
int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, void *data, int flags)
Request notification when weakproxy points to NULL.
Definition: astobj2.c:931
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
void * __ao2_weakproxy_alloc(size_t data_size, ao2_destructor_fn destructor_fn, const char *tag, const char *file, int line, const char *func)
Allocate an ao2_weakproxy object.
Definition: astobj2.c:790
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define ao2_t_unlink(container, obj, tag)
Remove an object from a container.
Definition: astobj2.h:1596
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ast_assert(a)
Definition: utils.h:695
#define ao2_unlock(a)
Definition: astobj2.h:730
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2207
#define __LOG_ERROR
Definition: logger.h:284
#define __INTERNAL_OBJ_CHECK(user_data, file, line, func)
convert from a pointer _p to a user-defined object
Definition: astobj2.c:171
#define AO2_WEAK
Definition: astobj2.c:97
#define NULL
Definition: resample.c:96
int __ast_rwlock_unlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:748
#define ao2_wrlock(a)
Definition: astobj2.h:720
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
Unlock an object.
Definition: astobj2.c:288
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
ast_rwlock_t lock
Definition: astobj2.c:127
#define EXCESSIVE_REF_COUNT
#define AO2_MAGIC
Definition: astobj2.c:96
#define INTERNAL_OBJ_LOCKOBJ(user_data)
Definition: astobj2.c:160
struct ao2_rwlock_priv rwlock
Definition: astobj2.c:134
ast_mutex_t lock
Definition: astobj2.c:116
#define ast_log
Definition: astobj2.c:42
void __ao2_cleanup(void *obj)
Definition: astobj2.c:674
struct __priv_data priv_data
Definition: astobj2.c:135
void * ao2_object_get_lockaddr(void *user_data)
Return the mutex lock address of an object.
Definition: astobj2.c:476
#define INTERNAL_OBJ_CHECK(user_data)
Definition: astobj2.c:183
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
Asterisk file paths, configured in asterisk.conf.
int ast_get_tid(void)
Get current thread ID.
Definition: main/utils.c:2504
const int fd
Definition: cli.h:159
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
#define ao2_ref(o, delta)
Definition: astobj2.h:464
ao2_destructor_fn destructor_fn
Definition: astobj2.c:55
#define ao2_lock(a)
Definition: astobj2.h:718
uint32_t lockused
Set to 1 when the lock is used if refdebug is enabled.
Definition: astobj2.c:77
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
int __ao2_ref(void *user_data, int delta, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:498
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 EXTERNAL_OBJ(_p)
convert from a pointer _p to an astobj2 object
Definition: astobj2.c:191
const char *const * argv
Definition: cli.h:161
int ast_add_profile(const char *, uint64_t scale)
support for event profiling
Definition: astman.c:92
struct ao2_weakproxy::@224 destroyed_cb
struct ao2_weakproxy_notification::@339 list
int internal_is_ao2_object(void *user_data)
Definition: astobj2.c:193
int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:421
#define LOG_ERROR
Definition: logger.h:285
void * user_data[0]
Definition: astobj2.c:147
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
#define INTERNAL_OBJ(user_data)
Definition: astobj2.c:163
void * weakptr
Definition: astobj2.c:57
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
Definition: lock.h:222
void(* ao2_destructor_fn)(void *vdoomed)
Typedef for an object destructor.
Definition: astobj2.h:360
#define ao2_rdlock(a)
Definition: astobj2.h:719
#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
void * __ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:765
void log_bad_ao2(void *user_data, const char *file, int line, const char *func)
Definition: astobj2.c:206
const char * ast_config_AST_LOG_DIR
Definition: options.c:159
#define INTERNAL_OBJ_RWLOCK(user_data)
Definition: astobj2.c:157
#define INTERNAL_OBJ_MUTEX(user_data)
Definition: astobj2.c:154
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
long int flag
Definition: f2c.h:83
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
#define ast_free(a)
Definition: astmm.h:182
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
struct __priv_data priv_data
Definition: astobj2.c:146
Prototypes for public functions only of internal interest,.
int ao2_weakproxy_unsubscribe(void *weakproxy, ao2_weakproxy_notification_cb destroyed_cb, void *data, int flags)
Remove notification of real object destruction.
Definition: astobj2.c:970
#define IS_AO2_MAGIC_BAD(p)
Definition: astobj2.c:98
int __ast_rwlock_wrlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:917
const char * usage
Definition: cli.h:177
#define ao2_t_bump(obj, tag)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:483
#define CLI_SUCCESS
Definition: cli.h:44
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
void * user_data[0]
Definition: astobj2.c:106
void * __ao2_weakproxy_get_object(void *weakproxy, int flags, const char *tag, const char *file, int line, const char *func)
Get the object associated with weakproxy.
Definition: astobj2.c:886
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
int __ao2_weakproxy_set_object(void *weakproxy, void *obj, int flags, const char *tag, const char *file, int line, const char *func)
Associate weakproxy with obj.
Definition: astobj2.c:815
Structure for rwlock and tracking information.
Definition: lock.h:156
Standard Command Line Interface.
This struct should be opaque, but it&#39;s size is needed.
Definition: astobj2.h:530
int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:253
Common, private definitions for astobj2 containers.
enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
Definition: astobj2.c:425
int32_t ref_counter
Definition: astobj2.c:63
int astobj2_init(void)
Definition: astobj2.c:1166
struct __priv_data priv_data
Definition: astobj2.c:105
struct stasis_forward * sub
Definition: res_corosync.c:240
ao2_weakproxy_notification_cb cb
Definition: astobj2.c:110
int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:366
void __ao2_cleanup_debug(void *obj, const char *tag, const char *file, int line, const char *function)
Definition: astobj2.c:667
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
int int32_t
Definition: db.h:60
void * __ao2_alloc_with_lockobj(size_t data_size, ao2_destructor_fn destructor_fn, void *lockobj, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:771
#define ast_mutex_init(pmutex)
Definition: lock.h:184
Generic container type.
#define ast_mutex_destroy(a)
Definition: lock.h:186
static FILE * ref_log
Definition: astobj2.c:44
int __ast_rwlock_tryrdlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:1178
struct __priv_data priv_data
Definition: astobj2.c:122
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
struct ao2_lockobj_priv lockobj
Definition: astobj2.c:145
Structure for mutex and tracking information.
Definition: lock.h:135
#define ast_opt_ref_debug
Definition: options.h:135
static ast_mutex_t mutex
uint32_t magic
Definition: astobj2.c:93
static struct test_val a
#define ao2_link(container, obj)
Definition: astobj2.h:1549
void * __ao2_get_weakproxy(void *obj, const char *tag, const char *file, int line, const char *func)
Get the weakproxy attached to obj.
Definition: astobj2.c:914
static void * internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, void *lockobj, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:681
int container_init(void)