Asterisk - The Open Source Telephony Project  GIT-master-4a4f1a5
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 <rmudgett@digium.com>
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 {
121  struct ao2_lock_priv mutex;
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",
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. */
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. */
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 
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  uint32_t privdataoptions;
508  struct ao2_weakproxy *weakproxy = NULL;
509  const char *lock_state;
510 
511  if (obj == NULL) {
512  if (ref_log && user_data) {
513  fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
514  user_data, delta, ast_get_tid(), file, line, func, tag ?: "");
515  fflush(ref_log);
516  }
517  return -1;
518  }
519 
520  /* if delta is 0, just return the refcount */
521  if (delta == 0) {
522  return obj->priv_data.ref_counter;
523  }
524 
525  if (delta < 0 && obj->priv_data.magic == AO2_MAGIC && (weakproxy = obj->priv_data.weakptr)) {
526  ao2_lock(weakproxy);
527  }
528 
529  /* we modify with an atomic operation the reference counter */
530  ret = ast_atomic_fetch_add(&obj->priv_data.ref_counter, delta, __ATOMIC_RELAXED);
531  current_value = ret + delta;
532 
533 #ifdef AO2_DEBUG
534  ast_atomic_fetchadd_int(&ao2.total_refs, delta);
535 #endif
536 
537  if (weakproxy) {
538  struct ao2_weakproxy cbs;
539 
540  if (current_value == 1) {
541  /* The only remaining reference is the one owned by the weak object */
542  struct astobj2 *internal_weakproxy;
543 
544  internal_weakproxy = INTERNAL_OBJ_CHECK(weakproxy);
545 
546  /* Unlink the obj from the weak proxy */
547  internal_weakproxy->priv_data.weakptr = NULL;
548  obj->priv_data.weakptr = NULL;
549 
550  /* transfer list to local copy so callbacks are run with weakproxy unlocked. */
551  cbs.destroyed_cb = weakproxy->destroyed_cb;
553 
554  /* weak is already unlinked from obj so this won't recurse */
555  ao2_ref(user_data, -1);
556  }
557 
558  ao2_unlock(weakproxy);
559 
560  if (current_value == 1) {
561  struct ao2_weakproxy_notification *destroyed_cb;
562 
563  /* Notify the subscribers that weakproxy now points to NULL. */
564  while ((destroyed_cb = AST_LIST_REMOVE_HEAD(&cbs.destroyed_cb, list))) {
565  destroyed_cb->cb(weakproxy, destroyed_cb->data);
566  ast_free(destroyed_cb);
567  }
568 
569  ao2_ref(weakproxy, -1);
570  }
571  }
572 
573  if (0 < current_value) {
574  /* The object still lives. */
575 #define EXCESSIVE_REF_COUNT 100000
576 
577  if (EXCESSIVE_REF_COUNT <= current_value && ret < EXCESSIVE_REF_COUNT) {
578  char excessive_ref_buf[100];
579 
580  /* We just reached or went over the excessive ref count trigger */
581  snprintf(excessive_ref_buf, sizeof(excessive_ref_buf),
582  "Excessive refcount %d reached on ao2 object %p",
583  (int)current_value, user_data);
584  ast_log(__LOG_ERROR, file, line, func, "%s\n", excessive_ref_buf);
585 
586  __ast_assert_failed(0, excessive_ref_buf, file, line, func);
587  }
588 
590  fprintf(ref_log, "%p,%s%d,%d,%s,%d,%s,%d,%s\n", user_data,
591  (delta < 0 ? "" : "+"), delta, ast_get_tid(),
592  file, line, func, (int)ret, tag ?: "");
593  fflush(ref_log);
594  }
595  return ret;
596  }
597 
598  /* this case must never happen */
599  if (current_value < 0) {
600  ast_log(__LOG_ERROR, file, line, func,
601  "Invalid refcount %d on ao2 object %p\n", (int)current_value, user_data);
602  if (ref_log) {
603  /* Log to ref_log even if AO2_ALLOC_OPT_NO_REF_DEBUG */
604  fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**invalid**,%s\n",
605  user_data, delta, ast_get_tid(), file, line, func, tag ?: "");
606  fflush(ref_log);
607  }
608  ast_assert(0);
609  /* stop here even if assert doesn't DO_CRASH */
610  return -1;
611  }
612 
613  /* last reference, destroy the object */
614  if (obj->priv_data.destructor_fn != NULL) {
615  obj->priv_data.destructor_fn(user_data);
616  }
617 
618 #ifdef AO2_DEBUG
619  ast_atomic_fetchadd_int(&ao2.total_mem, - obj->priv_data.data_size);
620  ast_atomic_fetchadd_int(&ao2.total_objects, -1);
621 #endif
622 
623  /* In case someone uses an object after it's been freed */
624  obj->priv_data.magic = 0;
625  /* Save the options locally so the ref_log print at the end doesn't access freed data */
626  privdataoptions = obj->priv_data.options;
627 
628  switch (obj->priv_data.options & AO2_ALLOC_OPT_LOCK_MASK) {
630  obj_mutex = INTERNAL_OBJ_MUTEX(user_data);
631  lock_state = obj->priv_data.lockused ? "used" : "unused";
632  ast_mutex_destroy(&obj_mutex->mutex.lock);
633 
634  ast_free(obj_mutex);
635  break;
637  obj_rwlock = INTERNAL_OBJ_RWLOCK(user_data);
638  lock_state = obj->priv_data.lockused ? "used" : "unused";
639  ast_rwlock_destroy(&obj_rwlock->rwlock.lock);
640 
641  ast_free(obj_rwlock);
642  break;
644  lock_state = "none";
645  ast_free(obj);
646  break;
648  obj_lockobj = INTERNAL_OBJ_LOCKOBJ(user_data);
649  lock_state = obj->priv_data.lockused ? "used" : "unused";
650  ao2_t_ref(obj_lockobj->lockobj.lock, -1, "release lockobj");
651 
652  ast_free(obj_lockobj);
653  break;
654  default:
655  ast_log(__LOG_ERROR, file, line, func,
656  "Invalid lock option on ao2 object %p\n", user_data);
657  lock_state = "invalid";
658  break;
659  }
660 
661  if (ref_log && !(privdataoptions & AO2_ALLOC_OPT_NO_REF_DEBUG)) {
662  fprintf(ref_log, "%p,%d,%d,%s,%d,%s,**destructor**lock-state:%s**,%s\n",
663  user_data, delta, ast_get_tid(), file, line, func, lock_state, tag ?: "");
664  fflush(ref_log);
665  }
666 
667  return ret;
668 }
669 
670 void __ao2_cleanup_debug(void *obj, const char *tag, const char *file, int line, const char *function)
671 {
672  if (obj) {
673  __ao2_ref(obj, -1, tag, file, line, function);
674  }
675 }
676 
677 void __ao2_cleanup(void *obj)
678 {
679  if (obj) {
680  ao2_ref(obj, -1);
681  }
682 }
683 
684 static void *internal_ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options,
685  void *lockobj, const char *tag, const char *file, int line, const char *func)
686 {
687  /* allocation */
688  struct astobj2 *obj;
689  struct astobj2_lock *obj_mutex;
690  struct astobj2_rwlock *obj_rwlock;
691  struct astobj2_lockobj *obj_lockobj;
692  size_t overhead;
693 
694  switch (options & AO2_ALLOC_OPT_LOCK_MASK) {
696  overhead = sizeof(*obj_mutex);
697  obj_mutex = __ast_calloc(1, overhead + data_size, file, line, func);
698  if (obj_mutex == NULL) {
699  return NULL;
700  }
701 
702  ast_mutex_init(&obj_mutex->mutex.lock);
703  obj = (struct astobj2 *) &obj_mutex->priv_data;
704  break;
706  overhead = sizeof(*obj_rwlock);
707  obj_rwlock = __ast_calloc(1, overhead + data_size, file, line, func);
708  if (obj_rwlock == NULL) {
709  return NULL;
710  }
711 
712  ast_rwlock_init(&obj_rwlock->rwlock.lock);
713  obj = (struct astobj2 *) &obj_rwlock->priv_data;
714  break;
716  overhead = sizeof(*obj);
717  obj = __ast_calloc(1, overhead + data_size, file, line, func);
718  if (obj == NULL) {
719  return NULL;
720  }
721  break;
723  lockobj = ao2_t_bump(lockobj, "set lockobj");
724  if (!lockobj) {
725  ast_log(__LOG_ERROR, file, line, func, "AO2_ALLOC_OPT_LOCK_OBJ requires a non-NULL lockobj.\n");
726  return NULL;
727  }
728 
729  overhead = sizeof(*obj_lockobj);
730  obj_lockobj = __ast_calloc(1, overhead + data_size, file, line, func);
731  if (obj_lockobj == NULL) {
732  ao2_t_ref(lockobj, -1, "release lockobj for failed alloc");
733  return NULL;
734  }
735 
736  obj_lockobj->lockobj.lock = lockobj;
737  obj = (struct astobj2 *) &obj_lockobj->priv_data;
738  break;
739  default:
740  /* Invalid option value. */
741  ast_log(__LOG_DEBUG, file, line, func, "Invalid lock option requested\n");
742  return NULL;
743  }
744 
745  /* Initialize common ao2 values. */
746  obj->priv_data.destructor_fn = destructor_fn; /* can be NULL */
747  obj->priv_data.ref_counter = 1;
748  obj->priv_data.options = options;
749  obj->priv_data.magic = AO2_MAGIC;
750 
751 #ifdef AO2_DEBUG
752  obj->priv_data.data_size = data_size;
753  ast_atomic_fetchadd_int(&ao2.total_objects, 1);
754  ast_atomic_fetchadd_int(&ao2.total_mem, data_size);
755  ast_atomic_fetchadd_int(&ao2.total_refs, 1);
756 #endif
757 
759  fprintf(ref_log, "%p,+1,%d,%s,%d,%s,**constructor**%zu**%zu**,%s\n",
760  EXTERNAL_OBJ(obj), ast_get_tid(), file, line, func, overhead, data_size, tag ?: "");
761  fflush(ref_log);
762  }
763 
764  /* return a pointer to the user data */
765  return EXTERNAL_OBJ(obj);
766 }
767 
768 void *__ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options,
769  const char *tag, const char *file, int line, const char *func)
770 {
771  return internal_ao2_alloc(data_size, destructor_fn, options, NULL, tag, file, line, func);
772 }
773 
774 void *__ao2_alloc_with_lockobj(size_t data_size, ao2_destructor_fn destructor_fn, void *lockobj,
775  const char *tag, const char *file, int line, const char *func)
776 {
777  return internal_ao2_alloc(data_size, destructor_fn, AO2_ALLOC_OPT_LOCK_OBJ, lockobj,
778  tag, file, line, func);
779 }
780 
781 unsigned int ao2_options_get(void *obj)
782 {
783  struct astobj2 *orig_obj;
784 
785  orig_obj = INTERNAL_OBJ_CHECK(obj);
786  if (!orig_obj) {
787  return 0;
788  }
789  return orig_obj->priv_data.options;
790 }
791 
792 
793 void *__ao2_weakproxy_alloc(size_t data_size, ao2_destructor_fn destructor_fn,
794  const char *tag, const char *file, int line, const char *func)
795 {
796  struct ao2_weakproxy *weakproxy;
797 
798  if (data_size < sizeof(*weakproxy)) {
799  ast_assert(0);
800  ast_log(LOG_ERROR, "Requested data_size smaller than minimum.\n");
801  return NULL;
802  }
803 
804  weakproxy = __ao2_alloc(data_size, destructor_fn, AO2_ALLOC_OPT_LOCK_MUTEX,
805  tag, file, line, func);
806 
807  if (weakproxy) {
808  struct astobj2 *weakproxy_internal;
809 
810  /* Just created weakproxy, no need to check if it's valid. */
811  weakproxy_internal = INTERNAL_OBJ(weakproxy);
812  weakproxy_internal->priv_data.magic = AO2_WEAK;
813  }
814 
815  return weakproxy;
816 }
817 
818 int __ao2_weakproxy_set_object(void *weakproxy, void *obj, int flags,
819  const char *tag, const char *file, int line, const char *func)
820 {
821  struct astobj2 *weakproxy_internal = __INTERNAL_OBJ_CHECK(weakproxy, file, line, func);
822  struct astobj2 *obj_internal = __INTERNAL_OBJ_CHECK(obj, file, line, func);
823  int ret = -1;
824 
825  if (!weakproxy_internal
826  || weakproxy_internal->priv_data.magic != AO2_WEAK) {
827  return -1;
828  }
829 
830  if (!obj_internal
831  || obj_internal->priv_data.weakptr
832  || obj_internal->priv_data.magic != AO2_MAGIC) {
833  return -1;
834  }
835 
836  if (!(flags & OBJ_NOLOCK)) {
837  ao2_lock(weakproxy);
838  }
839 
840  if (!weakproxy_internal->priv_data.weakptr) {
841  __ao2_ref(obj, +1, tag, file, line, func);
842  __ao2_ref(weakproxy, +1, tag, file, line, func);
843 
844  weakproxy_internal->priv_data.weakptr = obj;
845  obj_internal->priv_data.weakptr = weakproxy;
846 
847  ret = 0;
848  }
849 
850  if (!(flags & OBJ_NOLOCK)) {
851  ao2_unlock(weakproxy);
852  /* It is possible for obj to be accessed now. It's allowed
853  * for weakproxy to already be in a container. Another thread
854  * could have been waiting for a lock on weakproxy to retrieve
855  * the object.
856  */
857  }
858 
859  return ret;
860 }
861 
862 int __ao2_weakproxy_ref_object(void *weakproxy, int delta, int flags,
863  const char *tag, const char *file, int line, const char *func)
864 {
865  struct astobj2 *internal = __INTERNAL_OBJ_CHECK(weakproxy, file, line, func);
866  int ret = -1;
867 
868  if (!internal || internal->priv_data.magic != AO2_WEAK) {
869  /* This method is meant to be run on weakproxy objects! */
870  return -2;
871  }
872 
873  /* We have a weak object, grab lock. */
874  if (!(flags & OBJ_NOLOCK)) {
875  ao2_lock(weakproxy);
876  }
877 
878  if (internal->priv_data.weakptr) {
879  ret = __ao2_ref(internal->priv_data.weakptr, delta, tag, file, line, func);
880  }
881 
882  if (!(flags & OBJ_NOLOCK)) {
883  ao2_unlock(weakproxy);
884  }
885 
886  return ret;
887 }
888 
889 void *__ao2_weakproxy_get_object(void *weakproxy, int flags,
890  const char *tag, const char *file, int line, const char *func)
891 {
892  struct astobj2 *internal = __INTERNAL_OBJ_CHECK(weakproxy, file, line, func);
893  void *obj;
894 
895  if (!internal || internal->priv_data.magic != AO2_WEAK) {
896  /* This method is meant to be run on weakproxy objects! */
897  return NULL;
898  }
899 
900  /* We have a weak object, grab reference to object within lock */
901  if (!(flags & OBJ_NOLOCK)) {
902  ao2_lock(weakproxy);
903  }
904 
905  obj = internal->priv_data.weakptr;
906  if (obj) {
907  __ao2_ref(obj, +1, tag, file, line, func);
908  }
909 
910  if (!(flags & OBJ_NOLOCK)) {
911  ao2_unlock(weakproxy);
912  }
913 
914  return obj;
915 }
916 
917 void *__ao2_get_weakproxy(void *obj, const char *tag, const char *file, int line, const char *func)
918 {
919  struct astobj2 *obj_internal = __INTERNAL_OBJ_CHECK(obj, file, line, func);
920 
921  if (!obj_internal || obj_internal->priv_data.magic != AO2_MAGIC) {
922  /* This method is meant to be run on normal ao2 objects! */
923  return NULL;
924  }
925 
926  if (!obj_internal->priv_data.weakptr) {
927  return NULL;
928  }
929 
930  __ao2_ref(obj_internal->priv_data.weakptr, +1, tag, file, line, func);
931  return obj_internal->priv_data.weakptr;
932 }
933 
934 int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, void *data, int flags)
935 {
936  struct astobj2 *weakproxy_internal = INTERNAL_OBJ_CHECK(weakproxy);
937  int ret = -1;
938  int hasobj;
939 
940  if (!weakproxy_internal || weakproxy_internal->priv_data.magic != AO2_WEAK) {
941  return -1;
942  }
943 
944  if (!(flags & OBJ_NOLOCK)) {
945  ao2_lock(weakproxy);
946  }
947 
948  hasobj = weakproxy_internal->priv_data.weakptr != NULL;
949  if (hasobj) {
950  struct ao2_weakproxy *weak = weakproxy;
951  struct ao2_weakproxy_notification *sub = ast_calloc(1, sizeof(*sub));
952 
953  if (sub) {
954  sub->cb = cb;
955  sub->data = data;
957  ret = 0;
958  }
959  }
960 
961  if (!(flags & OBJ_NOLOCK)) {
962  ao2_unlock(weakproxy);
963  }
964 
965  if (!hasobj) {
966  cb(weakproxy, data);
967  ret = 0;
968  }
969 
970  return ret;
971 }
972 
973 int ao2_weakproxy_unsubscribe(void *weakproxy, ao2_weakproxy_notification_cb destroyed_cb, void *data, int flags)
974 {
975  struct astobj2 *internal_weakproxy = INTERNAL_OBJ_CHECK(weakproxy);
976  struct ao2_weakproxy *weak;
978  int ret = 0;
979 
980  if (!internal_weakproxy || internal_weakproxy->priv_data.magic != AO2_WEAK || !destroyed_cb) {
981  return -1;
982  }
983 
984  if (!(flags & OBJ_NOLOCK)) {
985  ao2_lock(weakproxy);
986  }
987 
988  weak = weakproxy;
990  if (sub->cb == destroyed_cb && sub->data == data) {
992  ast_free(sub);
993  ret++;
994  if (!(flags & OBJ_MULTIPLE)) {
995  break;
996  }
997  }
998  }
1000 
1001  if (!(flags & OBJ_NOLOCK)) {
1002  ao2_unlock(weakproxy);
1003  }
1004 
1005  return ret;
1006 }
1007 
1008 
1009 #ifdef AO2_DEBUG
1010 static int print_cb(void *obj, void *arg, int flag)
1011 {
1012  struct ast_cli_args *a = (struct ast_cli_args *) arg;
1013  char *s = (char *)obj;
1014 
1015  ast_cli(a->fd, "string <%s>\n", s);
1016  return 0;
1017 }
1018 
1019 /*
1020  * Print stats
1021  */
1022 static char *handle_astobj2_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1023 {
1024  switch (cmd) {
1025  case CLI_INIT:
1026  e->command = "astobj2 show stats";
1027  e->usage = "Usage: astobj2 show stats\n"
1028  " Show astobj2 show stats\n";
1029  return NULL;
1030  case CLI_GENERATE:
1031  return NULL;
1032  }
1033  ast_cli(a->fd, "Objects : %d\n", ao2.total_objects);
1034  ast_cli(a->fd, "Containers : %d\n", ao2.total_containers);
1035  ast_cli(a->fd, "Memory : %d\n", ao2.total_mem);
1036  ast_cli(a->fd, "Locked : %d\n", ao2.total_locked);
1037  ast_cli(a->fd, "Refs : %d\n", ao2.total_refs);
1038  return CLI_SUCCESS;
1039 }
1040 
1041 /*
1042  * This is testing code for astobj
1043  */
1044 static char *handle_astobj2_test(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1045 {
1046  struct ao2_container *c1;
1047  struct ao2_container *c2;
1048  int i, lim;
1049  char *obj;
1050  static int prof_id = -1;
1051  struct ast_cli_args fake_args = { a->fd, 0, NULL };
1052 
1053  switch (cmd) {
1054  case CLI_INIT:
1055  e->command = "astobj2 test";
1056  e->usage = "Usage: astobj2 test <num>\n"
1057  " Runs astobj2 test. Creates 'num' objects,\n"
1058  " and test iterators, callbacks and maybe other stuff\n";
1059  return NULL;
1060  case CLI_GENERATE:
1061  return NULL;
1062  }
1063 
1064  if (a->argc != 3) {
1065  return CLI_SHOWUSAGE;
1066  }
1067 
1068  if (prof_id == -1) {
1069  prof_id = ast_add_profile("ao2_alloc", 0);
1070  }
1071 
1072  ast_cli(a->fd, "argc %d argv %s %s %s\n", a->argc, a->argv[0], a->argv[1], a->argv[2]);
1073  lim = atoi(a->argv[2]);
1074  ast_cli(a->fd, "called astobj_test\n");
1075 
1076  handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
1077  /*
1078  * Allocate a list container.
1079  */
1081  NULL /* no callback */, "test");
1082  ast_cli(a->fd, "container allocated as %p\n", c1);
1083 
1084  /*
1085  * fill the container with objects.
1086  * ao2_alloc() gives us a reference which we pass to the
1087  * container when we do the insert.
1088  */
1089  for (i = 0; i < lim; i++) {
1090  ast_mark(prof_id, 1 /* start */);
1091  obj = ao2_t_alloc(80, NULL,"test");
1092  ast_mark(prof_id, 0 /* stop */);
1093  ast_cli(a->fd, "object %d allocated as %p\n", i, obj);
1094  sprintf(obj, "-- this is obj %d --", i);
1095  ao2_link(c1, obj);
1096  /* At this point, the refcount on obj is 2 due to the allocation
1097  * and linking. We can go ahead and reduce the refcount by 1
1098  * right here so that when the container is unreffed later, the
1099  * objects will be freed
1100  */
1101  ao2_t_ref(obj, -1, "test");
1102  }
1103 
1104  ast_cli(a->fd, "testing callbacks\n");
1105  ao2_t_callback(c1, 0, print_cb, a, "test callback");
1106 
1107  ast_cli(a->fd, "testing container cloning\n");
1108  c2 = ao2_container_clone(c1, 0);
1109  if (ao2_container_count(c1) != ao2_container_count(c2)) {
1110  ast_cli(a->fd, "Cloned container does not have the same number of objects!\n");
1111  }
1112  ao2_t_callback(c2, 0, print_cb, a, "test callback");
1113 
1114  ast_cli(a->fd, "testing iterators, remove every second object\n");
1115  {
1116  struct ao2_iterator ai;
1117  int x = 0;
1118 
1119  ai = ao2_iterator_init(c1, 0);
1120  while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
1121  ast_cli(a->fd, "iterator on <%s>\n", obj);
1122  if (x++ & 1)
1123  ao2_t_unlink(c1, obj,"test");
1124  ao2_t_ref(obj, -1,"test");
1125  }
1126  ao2_iterator_destroy(&ai);
1127  ast_cli(a->fd, "testing iterators again\n");
1128  ai = ao2_iterator_init(c1, 0);
1129  while ( (obj = ao2_t_iterator_next(&ai,"test")) ) {
1130  ast_cli(a->fd, "iterator on <%s>\n", obj);
1131  ao2_t_ref(obj, -1,"test");
1132  }
1133  ao2_iterator_destroy(&ai);
1134  }
1135 
1136  ast_cli(a->fd, "testing callbacks again\n");
1137  ao2_t_callback(c1, 0, print_cb, a, "test callback");
1138 
1139  ast_verbose("now you should see an error and possible assertion failure messages:\n");
1140  ao2_t_ref(&i, -1, ""); /* i is not a valid object so we print an error here */
1141 
1142  ast_cli(a->fd, "destroy container\n");
1143  ao2_t_ref(c1, -1, ""); /* destroy container */
1144  ao2_t_ref(c2, -1, ""); /* destroy container */
1145  handle_astobj2_stats(e, CLI_HANDLER, &fake_args);
1146  return CLI_SUCCESS;
1147 }
1148 #endif /* AO2_DEBUG */
1149 
1150 #if defined(AO2_DEBUG)
1151 static struct ast_cli_entry cli_astobj2[] = {
1152  AST_CLI_DEFINE(handle_astobj2_stats, "Print astobj2 statistics"),
1153  AST_CLI_DEFINE(handle_astobj2_test, "Test astobj2"),
1154 };
1155 #endif /* AO2_DEBUG */
1156 
1157 static void astobj2_cleanup(void)
1158 {
1159 #if defined(AO2_DEBUG)
1160  ast_cli_unregister_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
1161 #endif
1162 
1163  if (ast_opt_ref_debug) {
1164  fclose(ref_log);
1165  ref_log = NULL;
1166  }
1167 }
1168 
1169 int astobj2_init(void)
1170 {
1171  char ref_filename[1024];
1172 
1173  if (ast_opt_ref_debug) {
1174  snprintf(ref_filename, sizeof(ref_filename), "%s/refs", ast_config_AST_LOG_DIR);
1175  ref_log = fopen(ref_filename, "w");
1176  if (!ref_log) {
1177  ast_log(LOG_ERROR, "Could not open ref debug log file: %s\n", ref_filename);
1178  }
1179  }
1180 
1182 
1183  if (container_init() != 0) {
1184  fclose(ref_log);
1185  ref_log = NULL;
1186  return -1;
1187  }
1188 
1189 #if defined(AO2_DEBUG)
1190  ast_cli_register_multiple(cli_astobj2, ARRAY_LEN(cli_astobj2));
1191 #endif /* defined(AO2_DEBUG) */
1192 
1193  return 0;
1194 }
Prototypes for public functions only of internal interest,.
#define var
Definition: ast_expr2f.c:614
Asterisk main include file. File version handling, generic pbx functions.
int ast_add_profile(const char *, uint64_t scale)
support for event profiling
Definition: astman.c:92
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
int64_t ast_mark(int, int start1_stop0)
Definition: astman.c:103
#define ast_free(a)
Definition: astmm.h:182
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_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
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:793
enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
Definition: astobj2.c:425
#define EXTERNAL_OBJ(_p)
convert from a pointer _p to an astobj2 object
Definition: astobj2.c:191
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:934
#define AO2_WEAK
Definition: astobj2.c:97
unsigned int ao2_options_get(void *obj)
Retrieve the ao2 options used to create the object.
Definition: astobj2.c:781
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:768
#define EXCESSIVE_REF_COUNT
#define INTERNAL_OBJ_LOCKOBJ(user_data)
Definition: astobj2.c:160
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't block if fail)
Definition: astobj2.c:342
static void astobj2_cleanup(void)
Definition: astobj2.c:1157
#define __INTERNAL_OBJ_CHECK(user_data, file, line, func)
convert from a pointer _p to a user-defined object
Definition: astobj2.c:171
#define IS_AO2_MAGIC_BAD(p)
Definition: astobj2.c:98
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:774
void * ao2_object_get_lockaddr(void *user_data)
Return the mutex lock address of an object.
Definition: astobj2.c:476
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:862
void log_bad_ao2(void *user_data, const char *file, int line, const char *func)
Definition: astobj2.c:206
#define ast_log
Definition: astobj2.c:42
static FILE * ref_log
Definition: astobj2.c:44
int internal_is_ao2_object(void *user_data)
Definition: astobj2.c:193
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:818
#define INTERNAL_OBJ_CHECK(user_data)
Definition: astobj2.c:183
int __ao2_ref(void *user_data, int delta, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:498
#define INTERNAL_OBJ_MUTEX(user_data)
Definition: astobj2.c:154
void __ao2_cleanup(void *obj)
Definition: astobj2.c:677
int astobj2_init(void)
Definition: astobj2.c:1169
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:889
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
void __ao2_cleanup_debug(void *obj, const char *tag, const char *file, int line, const char *function)
Definition: astobj2.c:670
#define INTERNAL_OBJ_RWLOCK(user_data)
Definition: astobj2.c:157
#define INTERNAL_OBJ(user_data)
Definition: astobj2.c:163
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:973
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:917
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:684
int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
Unlock an object.
Definition: astobj2.c:288
#define AO2_MAGIC
Definition: astobj2.c:96
#define ao2_t_ref(o, delta, tag)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:463
#define ao2_link(container, obj)
Definition: astobj2.h:1549
#define ao2_rdlock(a)
Definition: astobj2.h:719
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:369
@ AO2_ALLOC_OPT_LOCK_OBJ
Definition: astobj2.h:378
@ AO2_ALLOC_OPT_LOCK_RWLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:365
@ AO2_ALLOC_OPT_LOCK_MASK
Definition: astobj2.h:371
@ AO2_ALLOC_OPT_NO_REF_DEBUG
Definition: astobj2.h:380
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
#define ao2_wrlock(a)
Definition: astobj2.h:720
ao2_lock_req
Which lock to request.
Definition: astobj2.h:701
@ AO2_LOCK_REQ_MUTEX
Definition: astobj2.h:703
@ AO2_LOCK_REQ_WRLOCK
Definition: astobj2.h:707
@ AO2_LOCK_REQ_RDLOCK
Definition: astobj2.h:705
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
void(* ao2_weakproxy_notification_cb)(void *weakproxy, void *data)
Definition: astobj2.h:527
void(* ao2_destructor_fn)(void *vdoomed)
Typedef for an object destructor.
Definition: astobj2.h:360
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_t_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn, tag)
Allocate and initialize a list container.
Definition: astobj2.h:1333
#define ao2_unlock(a)
Definition: astobj2.h:730
#define ao2_lock(a)
Definition: astobj2.h:718
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_t_bump(obj, tag)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:483
#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 ao2_t_alloc(data_size, destructor_fn, debug_msg)
Definition: astobj2.h:409
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1067
@ OBJ_MULTIPLE
Definition: astobj2.h:1053
#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,...
Definition: astobj2.h:1714
#define ao2_container_clone(orig, flags)
Definition: astobj2.h:1430
int container_init(void)
Common, private definitions for astobj2 containers.
Common, private definitions for astobj2.
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_HANDLER
Definition: cli.h:154
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
int int32_t
Definition: db.h:60
void ast_verbose(const char *fmt,...)
Definition: extconf.c:2207
long int flag
Definition: f2c.h:83
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
int __ast_rwlock_wrlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:917
int __ast_rwlock_trywrlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:1228
int __ast_rwlock_unlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:748
#define ast_mutex_init(pmutex)
Definition: lock.h:184
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
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
Definition: lock.h:222
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
#define ast_rwlock_destroy(rwlock)
Definition: lock.h:231
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
#define ast_mutex_destroy(a)
Definition: lock.h:186
int __ast_rwlock_tryrdlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:1178
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
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
#define __LOG_ERROR
Definition: logger.h:285
#define __LOG_DEBUG
Definition: logger.h:241
#define LOG_ERROR
Definition: logger.h:286
#define ast_opt_ref_debug
Definition: options.h:135
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_LOG_DIR
Definition: options.c:159
struct stasis_forward * sub
Definition: res_corosync.c:240
#define NULL
Definition: resample.c:96
int32_t ref_counter
Definition: astobj2.c:63
uint32_t options
The ao2 object option flags.
Definition: astobj2.c:70
uint32_t magic
Definition: astobj2.c:93
ao2_destructor_fn destructor_fn
Definition: astobj2.c:55
uint32_t lockused
Set to 1 when the lock is used if refdebug is enabled.
Definition: astobj2.c:77
void * weakptr
Definition: astobj2.c:57
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
ast_mutex_t lock
Definition: astobj2.c:116
ast_rwlock_t lock
Definition: astobj2.c:127
struct ao2_weakproxy_notification::@320 list
ao2_weakproxy_notification_cb cb
Definition: astobj2.c:110
This struct should be opaque, but it's size is needed.
Definition: astobj2.h:530
struct ao2_weakproxy::@211 destroyed_cb
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Structure for mutex and tracking information.
Definition: lock.h:135
Structure for rwlock and tracking information.
Definition: lock.h:156
struct ao2_lock_priv mutex
Definition: astobj2.c:121
struct __priv_data priv_data
Definition: astobj2.c:122
void * user_data[0]
Definition: astobj2.c:123
struct __priv_data priv_data
Definition: astobj2.c:146
struct ao2_lockobj_priv lockobj
Definition: astobj2.c:145
void * user_data[0]
Definition: astobj2.c:147
struct ao2_rwlock_priv rwlock
Definition: astobj2.c:134
struct __priv_data priv_data
Definition: astobj2.c:135
void * user_data[0]
Definition: astobj2.c:136
struct __priv_data priv_data
Definition: astobj2.c:105
void * user_data[0]
Definition: astobj2.c:106
static struct test_options options
static struct test_val a
#define ast_assert(a)
Definition: utils.h:710
int ast_get_tid(void)
Get current thread ID.
Definition: main/utils.c:2504
#define ARRAY_LEN(a)
Definition: utils.h:639
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