Asterisk - The Open Source Telephony Project GIT-master-67613d1
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
44static 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 */
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 \p lockused and \p 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 \p options and \p 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 */
104struct astobj2 {
106 void *user_data[0];
107};
108
111 void *data;
113};
114
117};
118
119/* AstObj2 with recursive lock. */
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. */
136 void *user_data[0];
137};
138
140 void *lock;
141};
142
143/* AstObj2 with locking provided by a separate object. */
147 void *user_data[0];
148};
149
150#ifdef AO2_DEBUG
151struct 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
193int internal_is_ao2_object(void *user_data)
194{
195 struct astobj2 *p;
196
197 if (!user_data) {
198 return 0;
199 }
200
202
203 return !p || IS_AO2_MAGIC_BAD(p) ? 0 : 1;
204}
205
206void 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
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
222int __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
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) {
253 res = __ast_rwlock_wrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
254 if (!res) {
256#ifdef AO2_DEBUG
257 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
258#endif
259 }
260 break;
262 res = __ast_rwlock_rdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
263 if (!res) {
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
288int __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
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
342int __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
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) {
373 res = __ast_rwlock_trywrlock(file, line, func, &obj_rwlock->rwlock.lock, var);
374 if (!res) {
376#ifdef AO2_DEBUG
377 ast_atomic_fetchadd_int(&ao2.total_locked, 1);
378#endif
379 }
380 break;
382 res = __ast_rwlock_tryrdlock(file, line, func, &obj_rwlock->rwlock.lock, var);
383 if (!res) {
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 */
425enum 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
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) {
442 lock_how = AO2_LOCK_REQ_WRLOCK;
443 /* Fall through */
445 if (lock_how != orig_lock) {
446 /* Switch from read lock to write lock. */
449 }
450 break;
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
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
498int __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
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
670void __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
677void __ao2_cleanup(void *obj)
678{
679 if (obj) {
680 ao2_ref(obj, -1);
681 }
682}
683
684static 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
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;
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
768void *__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
774void *__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
781unsigned 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
793void *__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
818int __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
862int __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
889void *__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
917void *__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
934int 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
973int 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
1010static 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 */
1022static 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 */
1044static 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);
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 }
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 }
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)
1151static 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
1157static 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
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:605
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:180
void * __ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) attribute_malloc
Definition: astmm.c:1603
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
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_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
#define EXCESSIVE_REF_COUNT
#define INTERNAL_OBJ_LOCKOBJ(user_data)
Definition: astobj2.c:160
void * __ao2_weakproxy_alloc(size_t data_size, ao2_destructor_fn destructor_fn, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:793
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_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
int __ao2_weakproxy_ref_object(void *weakproxy, int delta, int flags, const char *tag, const char *file, int line, const char *func)
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
void * __ao2_weakproxy_get_object(void *weakproxy, int flags, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:889
int __ao2_weakproxy_set_object(void *weakproxy, void *obj, int flags, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:818
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 __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
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
int __ao2_unlock(void *user_data, const char *file, const char *func, int line, const char *var)
Unlock an object.
Definition: astobj2.c:288
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
void * __ao2_get_weakproxy(void *obj, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:917
#define AO2_MAGIC
Definition: astobj2.c:96
#define ao2_t_ref(o, delta, tag)
Definition: astobj2.h:460
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ao2_rdlock(a)
Definition: astobj2.h:718
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_OBJ
Definition: astobj2.h:376
@ AO2_ALLOC_OPT_LOCK_RWLOCK
Definition: astobj2.h:365
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
@ AO2_ALLOC_OPT_LOCK_MASK
Definition: astobj2.h:369
@ AO2_ALLOC_OPT_NO_REF_DEBUG
Definition: astobj2.h:378
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1909
#define ao2_wrlock(a)
Definition: astobj2.h:719
ao2_lock_req
Which lock to request.
Definition: astobj2.h:700
@ AO2_LOCK_REQ_MUTEX
Definition: astobj2.h:702
@ AO2_LOCK_REQ_WRLOCK
Definition: astobj2.h:706
@ AO2_LOCK_REQ_RDLOCK
Definition: astobj2.h:704
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:526
void(* ao2_destructor_fn)(void *vdoomed)
Typedef for an object destructor.
Definition: astobj2.h:358
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)
Definition: astobj2.h:1330
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_t_bump(obj, tag)
Definition: astobj2.h:483
#define ao2_t_unlink(container, obj, tag)
Definition: astobj2.h:1580
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:407
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
Definition: astobj2.h:1696
#define ao2_container_clone(orig, flags)
Create a clone/copy of the given container.
Definition: astobj2.h:1419
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:2206
long int flag
Definition: f2c.h:83
#define __LOG_ERROR
#define __LOG_DEBUG
#define LOG_ERROR
#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:952
int __ast_rwlock_trywrlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:1269
int __ast_rwlock_unlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:777
#define ast_mutex_init(pmutex)
Definition: lock.h:186
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:757
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
Definition: lock.h:224
int __ast_pthread_mutex_lock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:255
#define ast_rwlock_destroy(rwlock)
Definition: lock.h:233
int __ast_pthread_mutex_trylock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:393
#define ast_mutex_destroy(a)
Definition: lock.h:188
int __ast_rwlock_tryrdlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:1219
int __ast_pthread_mutex_unlock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:448
int __ast_rwlock_rdlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:848
#define ast_atomic_fetch_add(ptr, val, memorder)
Support for atomic instructions.
Definition: lock.h:669
#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:1821
ast_mutex_t lock
Definition: astobj2.c:116
ast_rwlock_t lock
Definition: astobj2.c:127
ao2_weakproxy_notification_cb cb
Definition: astobj2.c:110
struct ao2_weakproxy_notification::@299 list
This struct should be opaque, but it's size is needed.
Definition: astobj2.h:529
struct ao2_weakproxy::@186 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:157
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:739
int ast_get_tid(void)
Get current thread ID.
Definition: utils.c:2752
#define ARRAY_LEN(a)
Definition: utils.h:666
void DO_CRASH_NORETURN __ast_assert_failed(int condition, const char *condition_str, const char *file, int line, const char *function)
Definition: utils.c:2816