Asterisk - The Open Source Telephony Project GIT-master-67613d1
Data Structures | Macros | Functions | Variables
astobj2.c File Reference

Functions implementing astobj2 objects. More...

#include "asterisk.h"
#include "asterisk/_private.h"
#include "asterisk/astobj2.h"
#include "astobj2_private.h"
#include "astobj2_container_private.h"
#include "asterisk/cli.h"
#include "asterisk/paths.h"
Include dependency graph for astobj2.c:

Go to the source code of this file.

Data Structures

struct  __priv_data
 
struct  ao2_lock_priv
 
struct  ao2_lockobj_priv
 
struct  ao2_rwlock_priv
 
struct  ao2_weakproxy_notification
 
struct  astobj2
 
struct  astobj2_lock
 
struct  astobj2_lockobj
 
struct  astobj2_rwlock
 

Macros

#define __INTERNAL_OBJ_CHECK(user_data, file, line, func)
 convert from a pointer _p to a user-defined object More...
 
#define AO2_MAGIC   0xa70b123
 
#define AO2_WEAK   0xa70b122
 
#define ast_log   ast_log_safe
 
#define DEBUG_THREADS_LOOSE_ABI
 
#define EXCESSIVE_REF_COUNT   100000
 
#define EXTERNAL_OBJ(_p)   ((_p) == NULL ? NULL : (_p)->user_data)
 convert from a pointer _p to an astobj2 object More...
 
#define INTERNAL_OBJ(user_data)    (struct astobj2 *) ((char *) user_data - sizeof(struct astobj2))
 
#define INTERNAL_OBJ_CHECK(user_data)    __INTERNAL_OBJ_CHECK(user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
#define INTERNAL_OBJ_LOCKOBJ(user_data)    ((struct astobj2_lockobj *) (((char *) (user_data)) - sizeof(struct astobj2_lockobj)))
 
#define INTERNAL_OBJ_MUTEX(user_data)    ((struct astobj2_lock *) (((char *) (user_data)) - sizeof(struct astobj2_lock)))
 
#define INTERNAL_OBJ_RWLOCK(user_data)    ((struct astobj2_rwlock *) (((char *) (user_data)) - sizeof(struct astobj2_rwlock)))
 
#define IS_AO2_MAGIC_BAD(p)   (AO2_MAGIC != (p->priv_data.magic | 1))
 

Functions

enum ao2_lock_req __adjust_lock (void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
 
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)
 
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)
 
void __ao2_cleanup (void *obj)
 
void __ao2_cleanup_debug (void *obj, const char *tag, const char *file, int line, const char *function)
 
void * __ao2_get_weakproxy (void *obj, const char *tag, const char *file, int line, const char *func)
 
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. More...
 
int __ao2_ref (void *user_data, int delta, const char *tag, const char *file, int line, const char *func)
 
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) More...
 
int __ao2_unlock (void *user_data, const char *file, const char *func, int line, const char *var)
 Unlock an object. More...
 
void * __ao2_weakproxy_alloc (size_t data_size, ao2_destructor_fn destructor_fn, const char *tag, const char *file, int line, const char *func)
 
void * __ao2_weakproxy_get_object (void *weakproxy, int flags, const char *tag, const char *file, int line, const char *func)
 
int __ao2_weakproxy_ref_object (void *weakproxy, int delta, int flags, const char *tag, const char *file, int line, const char *func)
 
int __ao2_weakproxy_set_object (void *weakproxy, void *obj, int flags, const char *tag, const char *file, int line, const char *func)
 
void * ao2_object_get_lockaddr (void *user_data)
 Return the mutex lock address of an object. More...
 
unsigned int ao2_options_get (void *obj)
 Retrieve the ao2 options used to create the object. More...
 
int ao2_weakproxy_subscribe (void *weakproxy, ao2_weakproxy_notification_cb cb, void *data, int flags)
 Request notification when weakproxy points to NULL. More...
 
int ao2_weakproxy_unsubscribe (void *weakproxy, ao2_weakproxy_notification_cb destroyed_cb, void *data, int flags)
 Remove notification of real object destruction. More...
 
static void astobj2_cleanup (void)
 
int astobj2_init (void)
 
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)
 
int internal_is_ao2_object (void *user_data)
 
void log_bad_ao2 (void *user_data, const char *file, int line, const char *func)
 

Variables

static FILE * ref_log
 

Detailed Description

Functions implementing astobj2 objects.

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

Definition in file astobj2.c.

Macro Definition Documentation

◆ __INTERNAL_OBJ_CHECK

#define __INTERNAL_OBJ_CHECK (   user_data,
  file,
  line,
  func 
)

convert from a pointer _p to a user-defined object

Returns
the pointer to the astobj2 structure

Definition at line 171 of file astobj2.c.

◆ AO2_MAGIC

#define AO2_MAGIC   0xa70b123

Definition at line 96 of file astobj2.c.

◆ AO2_WEAK

#define AO2_WEAK   0xa70b122

Definition at line 97 of file astobj2.c.

◆ ast_log

#define ast_log   ast_log_safe
Examples
app_skel.c.

Definition at line 42 of file astobj2.c.

◆ DEBUG_THREADS_LOOSE_ABI

#define DEBUG_THREADS_LOOSE_ABI

Definition at line 30 of file astobj2.c.

◆ EXCESSIVE_REF_COUNT

#define EXCESSIVE_REF_COUNT   100000

◆ EXTERNAL_OBJ

#define EXTERNAL_OBJ (   _p)    ((_p) == NULL ? NULL : (_p)->user_data)

convert from a pointer _p to an astobj2 object

Returns
the pointer to the user-defined portion.

Definition at line 191 of file astobj2.c.

◆ INTERNAL_OBJ

#define INTERNAL_OBJ (   user_data)     (struct astobj2 *) ((char *) user_data - sizeof(struct astobj2))

Definition at line 163 of file astobj2.c.

◆ INTERNAL_OBJ_CHECK

#define INTERNAL_OBJ_CHECK (   user_data)     __INTERNAL_OBJ_CHECK(user_data, __FILE__, __LINE__, __PRETTY_FUNCTION__)

Definition at line 183 of file astobj2.c.

◆ INTERNAL_OBJ_LOCKOBJ

#define INTERNAL_OBJ_LOCKOBJ (   user_data)     ((struct astobj2_lockobj *) (((char *) (user_data)) - sizeof(struct astobj2_lockobj)))

Definition at line 160 of file astobj2.c.

◆ INTERNAL_OBJ_MUTEX

#define INTERNAL_OBJ_MUTEX (   user_data)     ((struct astobj2_lock *) (((char *) (user_data)) - sizeof(struct astobj2_lock)))

Definition at line 154 of file astobj2.c.

◆ INTERNAL_OBJ_RWLOCK

#define INTERNAL_OBJ_RWLOCK (   user_data)     ((struct astobj2_rwlock *) (((char *) (user_data)) - sizeof(struct astobj2_rwlock)))

Definition at line 157 of file astobj2.c.

◆ IS_AO2_MAGIC_BAD

#define IS_AO2_MAGIC_BAD (   p)    (AO2_MAGIC != (p->priv_data.magic | 1))

Definition at line 98 of file astobj2.c.

Function Documentation

◆ __adjust_lock()

enum ao2_lock_req __adjust_lock ( void *  user_data,
enum ao2_lock_req  lock_how,
int  keep_stronger 
)

Definition at line 425 of file astobj2.c.

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}
enum ao2_lock_req __adjust_lock(void *user_data, enum ao2_lock_req lock_how, int keep_stronger)
Definition: astobj2.c:425
#define INTERNAL_OBJ_LOCKOBJ(user_data)
Definition: astobj2.c:160
#define ast_log
Definition: astobj2.c:42
#define INTERNAL_OBJ_RWLOCK(user_data)
Definition: astobj2.c:157
#define INTERNAL_OBJ(user_data)
Definition: astobj2.c:163
#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
#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
#define ao2_unlock(a)
Definition: astobj2.h:729
#define LOG_ERROR
uint32_t options
The ao2 object option flags.
Definition: astobj2.c:70
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:105
void * user_data[0]
Definition: astobj2.c:106

References __adjust_lock(), AO2_ALLOC_OPT_LOCK_MASK, AO2_ALLOC_OPT_LOCK_MUTEX, AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_ALLOC_OPT_LOCK_OBJ, AO2_ALLOC_OPT_LOCK_RWLOCK, AO2_LOCK_REQ_MUTEX, AO2_LOCK_REQ_RDLOCK, AO2_LOCK_REQ_WRLOCK, ao2_rdlock, ao2_unlock, ao2_wrlock, ast_log, INTERNAL_OBJ, INTERNAL_OBJ_LOCKOBJ, INTERNAL_OBJ_RWLOCK, ao2_lockobj_priv::lock, astobj2_lockobj::lockobj, LOG_ERROR, ao2_rwlock_priv::num_lockers, __priv_data::options, astobj2::priv_data, astobj2_rwlock::rwlock, astobj2::user_data, and astobj2_lockobj::user_data.

Referenced by __adjust_lock(), __ao2_iterator_next(), __ao2_link(), __ao2_weakproxy_find(), ao2_iterator_restart(), hash_ao2_node_destructor(), internal_ao2_traverse(), and rb_ao2_node_destructor().

◆ __ao2_alloc()

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 at line 768 of file astobj2.c.

770{
771 return internal_ao2_alloc(data_size, destructor_fn, options, NULL, tag, file, line, func);
772}
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
#define NULL
Definition: resample.c:96
static struct test_options options

References make_ari_stubs::file, internal_ao2_alloc(), NULL, and options.

Referenced by __ao2_container_alloc_hash(), __ao2_container_alloc_rbtree(), __ao2_weakproxy_alloc(), __ast_channel_internal_alloc(), __ast_format_cap_alloc(), __ast_named_lock_get(), __ast_sorcery_open(), _moh_class_malloc(), and state_alloc().

◆ __ao2_alloc_with_lockobj()

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 at line 774 of file astobj2.c.

776{
777 return internal_ao2_alloc(data_size, destructor_fn, AO2_ALLOC_OPT_LOCK_OBJ, lockobj,
778 tag, file, line, func);
779}

References AO2_ALLOC_OPT_LOCK_OBJ, make_ari_stubs::file, and internal_ao2_alloc().

◆ __ao2_cleanup()

void __ao2_cleanup ( void *  obj)

gcc attribute(cleanup()) functions

Note
they must be able to handle NULL parameters because most of the allocation/find functions can fail and we don't want to try to tear down a NULL

Definition at line 677 of file astobj2.c.

678{
679 if (obj) {
680 ao2_ref(obj, -1);
681 }
682}
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459

References ao2_ref.

Referenced by agent_request_exec(), ast_ari_bridges_set_video_source(), bridge_agent_hold_push(), bridge_builtin_set_limits(), bridge_stasis_queue_join_action(), dial_bridge_after_cb(), internal_bridge_after_cb(), native_rtp_bridge_framehook_attach(), parking_set_duration(), and speech_observer_loaded().

◆ __ao2_cleanup_debug()

void __ao2_cleanup_debug ( void *  obj,
const char *  tag,
const char *  file,
int  line,
const char *  function 
)

Definition at line 670 of file astobj2.c.

671{
672 if (obj) {
673 __ao2_ref(obj, -1, tag, file, line, function);
674 }
675}
int __ao2_ref(void *user_data, int delta, const char *tag, const char *file, int line, const char *func)
Definition: astobj2.c:498

References __ao2_ref(), and make_ari_stubs::file.

◆ __ao2_get_weakproxy()

void * __ao2_get_weakproxy ( void *  obj,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Definition at line 917 of file astobj2.c.

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}
#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_MAGIC
Definition: astobj2.c:96
uint32_t magic
Definition: astobj2.c:93
void * weakptr
Definition: astobj2.c:57

References __ao2_ref(), __INTERNAL_OBJ_CHECK, AO2_MAGIC, make_ari_stubs::file, __priv_data::magic, NULL, astobj2::priv_data, and __priv_data::weakptr.

◆ __ao2_lock()

int __ao2_lock ( void *  a,
enum ao2_lock_req  lock_how,
const char *  file,
const char *  func,
int  line,
const char *  var 
)

Lock an object.

Parameters
aA pointer to the object we want to lock.
lock_how,file,func,line,var
Returns
0 on success, other values on error.

Definition at line 222 of file astobj2.c.

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}
#define var
Definition: ast_expr2f.c:605
static FILE * ref_log
Definition: astobj2.c:44
#define INTERNAL_OBJ_MUTEX(user_data)
Definition: astobj2.c:154
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 __LOG_ERROR
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_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
Definition: lock.h:757
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
int __ast_rwlock_rdlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:848
uint32_t lockused
Set to 1 when the lock is used if refdebug is enabled.
Definition: astobj2.c:77
ast_mutex_t lock
Definition: astobj2.c:116
ast_rwlock_t lock
Definition: astobj2.c:127
struct ao2_lock_priv mutex
Definition: astobj2.c:121

References __ao2_lock(), __ast_pthread_mutex_lock(), __ast_rwlock_rdlock(), __ast_rwlock_wrlock(), __INTERNAL_OBJ_CHECK, __LOG_ERROR, AO2_ALLOC_OPT_LOCK_MASK, AO2_ALLOC_OPT_LOCK_MUTEX, AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_ALLOC_OPT_LOCK_OBJ, AO2_ALLOC_OPT_LOCK_RWLOCK, AO2_LOCK_REQ_MUTEX, AO2_LOCK_REQ_RDLOCK, AO2_LOCK_REQ_WRLOCK, ast_atomic_fetchadd_int(), ast_log, make_ari_stubs::file, INTERNAL_OBJ_LOCKOBJ, INTERNAL_OBJ_MUTEX, INTERNAL_OBJ_RWLOCK, ao2_lock_priv::lock, ao2_rwlock_priv::lock, ao2_lockobj_priv::lock, astobj2_lockobj::lockobj, __priv_data::lockused, astobj2_lock::mutex, NULL, ao2_rwlock_priv::num_lockers, __priv_data::options, astobj2::priv_data, ref_log, astobj2_rwlock::rwlock, astobj2::user_data, astobj2_lockobj::user_data, and var.

Referenced by __ao2_lock(), _agent_lock(), _ast_bridge_channel_lock(), and _ast_bridge_lock().

◆ __ao2_ref()

int __ao2_ref ( void *  user_data,
int  delta,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Definition at line 498 of file astobj2.c.

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}
#define ast_free(a)
Definition: astmm.h:180
#define EXCESSIVE_REF_COUNT
#define INTERNAL_OBJ_CHECK(user_data)
Definition: astobj2.c:183
#define ao2_t_ref(o, delta, tag)
Definition: astobj2.h:460
@ AO2_ALLOC_OPT_NO_REF_DEBUG
Definition: astobj2.h:378
#define ao2_lock(a)
Definition: astobj2.h:717
int int32_t
Definition: db.h:60
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:833
#define ast_rwlock_destroy(rwlock)
Definition: lock.h:233
#define ast_mutex_destroy(a)
Definition: lock.h:188
#define ast_atomic_fetch_add(ptr, val, memorder)
Support for atomic instructions.
Definition: lock.h:669
int32_t ref_counter
Definition: astobj2.c:63
ao2_destructor_fn destructor_fn
Definition: astobj2.c:55
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
#define ast_assert(a)
Definition: utils.h:739
int ast_get_tid(void)
Get current thread ID.
Definition: utils.c:2752
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

References __ast_assert_failed(), __INTERNAL_OBJ_CHECK, __LOG_ERROR, AO2_ALLOC_OPT_LOCK_MASK, AO2_ALLOC_OPT_LOCK_MUTEX, AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_ALLOC_OPT_LOCK_OBJ, AO2_ALLOC_OPT_LOCK_RWLOCK, AO2_ALLOC_OPT_NO_REF_DEBUG, ao2_lock, AO2_MAGIC, ao2_ref, ao2_t_ref, ao2_unlock, ast_assert, ast_atomic_fetch_add, ast_atomic_fetchadd_int(), ast_free, ast_get_tid(), AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_REMOVE_HEAD, ast_log, ast_mutex_destroy, ast_rwlock_destroy, ao2_weakproxy_notification::cb, ao2_weakproxy_notification::data, ao2_weakproxy::destroyed_cb, __priv_data::destructor_fn, EXCESSIVE_REF_COUNT, make_ari_stubs::file, INTERNAL_OBJ_CHECK, INTERNAL_OBJ_LOCKOBJ, INTERNAL_OBJ_MUTEX, INTERNAL_OBJ_RWLOCK, ao2_weakproxy_notification::list, ao2_lock_priv::lock, ao2_rwlock_priv::lock, ao2_lockobj_priv::lock, astobj2_lockobj::lockobj, __priv_data::lockused, __priv_data::magic, astobj2_lock::mutex, NULL, __priv_data::options, astobj2::priv_data, __priv_data::ref_counter, ref_log, astobj2_rwlock::rwlock, astobj2::user_data, and __priv_data::weakptr.

Referenced by __ao2_cleanup_debug(), __ao2_container_clone(), __ao2_get_weakproxy(), __ao2_global_obj_ref(), __ao2_global_obj_replace(), __ao2_global_obj_replace_unref(), __ao2_iterator_next(), __ao2_weakproxy_get_object(), __ao2_weakproxy_ref_object(), __ao2_weakproxy_set_object(), __ast_format_cap_append(), __ast_module_ref(), __ast_module_unref(), __container_unlink_node_debug(), hash_ao2_new_node(), internal_ao2_traverse(), and rb_ao2_new_node().

◆ __ao2_trylock()

int __ao2_trylock ( void *  a,
enum ao2_lock_req  lock_how,
const char *  file,
const char *  func,
int  line,
const char *  var 
)

Try locking– (don't block if fail)

Parameters
aA pointer to the object we want to lock.
lock_how,file,func,line,var
Returns
0 on success, other values on error.

Definition at line 342 of file astobj2.c.

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}
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
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_pthread_mutex_trylock(const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
Definition: lock.c:393
int __ast_rwlock_tryrdlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:1219

References __ao2_trylock(), __ast_pthread_mutex_trylock(), __ast_rwlock_tryrdlock(), __ast_rwlock_trywrlock(), __INTERNAL_OBJ_CHECK, __LOG_ERROR, AO2_ALLOC_OPT_LOCK_MASK, AO2_ALLOC_OPT_LOCK_MUTEX, AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_ALLOC_OPT_LOCK_OBJ, AO2_ALLOC_OPT_LOCK_RWLOCK, AO2_LOCK_REQ_MUTEX, AO2_LOCK_REQ_RDLOCK, AO2_LOCK_REQ_WRLOCK, ast_atomic_fetchadd_int(), ast_log, make_ari_stubs::file, INTERNAL_OBJ_LOCKOBJ, INTERNAL_OBJ_MUTEX, INTERNAL_OBJ_RWLOCK, ao2_lock_priv::lock, ao2_rwlock_priv::lock, ao2_lockobj_priv::lock, astobj2_lockobj::lockobj, __priv_data::lockused, astobj2_lock::mutex, NULL, ao2_rwlock_priv::num_lockers, __priv_data::options, astobj2::priv_data, ref_log, astobj2_rwlock::rwlock, astobj2::user_data, astobj2_lockobj::user_data, and var.

Referenced by __ao2_trylock(), _ast_bridge_channel_trylock(), and _ast_bridge_trylock().

◆ __ao2_unlock()

int __ao2_unlock ( void *  a,
const char *  file,
const char *  func,
int  line,
const char *  var 
)

Unlock an object.

Parameters
aA pointer to the object we want unlock.
file,func,line,var
Returns
0 on success, other values on error.

Definition at line 288 of file astobj2.c.

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}
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_rwlock_unlock(const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
Definition: lock.c:777
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

References __ao2_unlock(), __ast_pthread_mutex_unlock(), __ast_rwlock_unlock(), __INTERNAL_OBJ_CHECK, __LOG_ERROR, AO2_ALLOC_OPT_LOCK_MASK, AO2_ALLOC_OPT_LOCK_MUTEX, AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_ALLOC_OPT_LOCK_OBJ, AO2_ALLOC_OPT_LOCK_RWLOCK, ast_atomic_fetchadd_int(), ast_log, make_ari_stubs::file, INTERNAL_OBJ_LOCKOBJ, INTERNAL_OBJ_MUTEX, INTERNAL_OBJ_RWLOCK, ao2_lock_priv::lock, ao2_rwlock_priv::lock, ao2_lockobj_priv::lock, astobj2_lockobj::lockobj, astobj2_lock::mutex, NULL, ao2_rwlock_priv::num_lockers, __priv_data::options, astobj2::priv_data, astobj2_rwlock::rwlock, astobj2::user_data, astobj2_lockobj::user_data, and var.

Referenced by __ao2_unlock(), _agent_unlock(), _ast_bridge_channel_unlock(), and _ast_bridge_unlock().

◆ __ao2_weakproxy_alloc()

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 at line 793 of file astobj2.c.

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}
#define AO2_WEAK
Definition: astobj2.c:97
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

References __ao2_alloc(), AO2_ALLOC_OPT_LOCK_MUTEX, AO2_WEAK, ast_assert, ast_log, make_ari_stubs::file, INTERNAL_OBJ, LOG_ERROR, __priv_data::magic, NULL, and astobj2::priv_data.

◆ __ao2_weakproxy_get_object()

void * __ao2_weakproxy_get_object ( void *  weakproxy,
int  flags,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Definition at line 889 of file astobj2.c.

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}
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063

References __ao2_ref(), __INTERNAL_OBJ_CHECK, ao2_lock, ao2_unlock, AO2_WEAK, make_ari_stubs::file, __priv_data::magic, NULL, OBJ_NOLOCK, astobj2::priv_data, and __priv_data::weakptr.

Referenced by __ao2_weakproxy_find().

◆ __ao2_weakproxy_ref_object()

int __ao2_weakproxy_ref_object ( void *  weakproxy,
int  delta,
int  flags,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Definition at line 862 of file astobj2.c.

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}

References __ao2_ref(), __INTERNAL_OBJ_CHECK, ao2_lock, ao2_unlock, AO2_WEAK, make_ari_stubs::file, __priv_data::magic, OBJ_NOLOCK, astobj2::priv_data, and __priv_data::weakptr.

◆ __ao2_weakproxy_set_object()

int __ao2_weakproxy_set_object ( void *  weakproxy,
void *  obj,
int  flags,
const char *  tag,
const char *  file,
int  line,
const char *  func 
)

Definition at line 818 of file astobj2.c.

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}

References __ao2_ref(), __INTERNAL_OBJ_CHECK, ao2_lock, AO2_MAGIC, ao2_unlock, AO2_WEAK, make_ari_stubs::file, __priv_data::magic, OBJ_NOLOCK, astobj2::priv_data, and __priv_data::weakptr.

◆ ao2_object_get_lockaddr()

void * ao2_object_get_lockaddr ( void *  obj)

Return the mutex lock address of an object.

Parameters
[in]objA pointer to the object we want.
Returns
the address of the mutex lock, else NULL.

This function comes in handy mainly for debugging locking situations, where the locking trace code reports the lock address, this allows you to correlate against object address, to match objects to reported locks.

Warning
AO2 lock objects do not include tracking fields when DEBUG_THREADS is not enabled.
Since
1.6.1

Definition at line 476 of file astobj2.c.

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}
void * user_data[0]
Definition: astobj2.c:123

References AO2_ALLOC_OPT_LOCK_MASK, AO2_ALLOC_OPT_LOCK_MUTEX, INTERNAL_OBJ_CHECK, INTERNAL_OBJ_MUTEX, ao2_lock_priv::lock, astobj2_lock::mutex, NULL, __priv_data::options, astobj2::priv_data, and astobj2_lock::user_data.

Referenced by ast_serializer_shutdown_group_join(), ast_sip_session_suspend(), bridge_channel_wait(), bridge_manager_thread(), consumer_should_stay(), consumer_wait_for(), consumer_wait_for_completion(), control_wait(), db_sync_thread(), pbx_outgoing_attempt(), rtp_deallocate_transport(), sip_session_suspend_task(), stasis_subscription_join(), transaction_wait(), and wait_for_stimulus().

◆ ao2_options_get()

unsigned int ao2_options_get ( void *  obj)

Retrieve the ao2 options used to create the object.

Parameters
objpointer to the (user-defined part) of an object.
Returns
options from enum ao2_alloc_opts.

Definition at line 781 of file astobj2.c.

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}

References INTERNAL_OBJ_CHECK, __priv_data::options, and astobj2::priv_data.

Referenced by __ast_named_lock_get(), hash_ao2_alloc_empty_clone(), and rb_ao2_alloc_empty_clone().

◆ ao2_weakproxy_subscribe()

int ao2_weakproxy_subscribe ( void *  weakproxy,
ao2_weakproxy_notification_cb  cb,
void *  data,
int  flags 
)

Request notification when weakproxy points to NULL.

Since
14.0.0
Parameters
weakproxyThe weak object
cbProcedure to call when no real object is associated
dataPassed to cb
flagsOBJ_NOLOCK to avoid locking weakproxy.
Return values
0Success
-1Failure
Note
Callbacks are run in the reverse order of subscriptions.
This procedure will allow the same cb / data pair to be added to the same weakproxy multiple times.
It is the caller's responsibility to ensure that *data is valid until after cb() is run or ao2_weakproxy_unsubscribe is called.
If the weakproxy currently points to NULL the callback will be run immediately, without being added to the subscriber list.

Definition at line 934 of file astobj2.c.

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}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:711
struct stasis_forward * sub
Definition: res_corosync.c:240

References ao2_lock, ao2_unlock, AO2_WEAK, ast_calloc, AST_LIST_INSERT_HEAD, ao2_weakproxy_notification::cb, ao2_weakproxy_notification::data, ao2_weakproxy::destroyed_cb, INTERNAL_OBJ_CHECK, ao2_weakproxy_notification::list, __priv_data::magic, NULL, OBJ_NOLOCK, astobj2::priv_data, sub, and __priv_data::weakptr.

Referenced by __ast_named_lock_get(), __ast_sorcery_open(), AST_TEST_DEFINE(), link_topic_proxy(), and state_alloc().

◆ ao2_weakproxy_unsubscribe()

int ao2_weakproxy_unsubscribe ( void *  weakproxy,
ao2_weakproxy_notification_cb  cb,
void *  data,
int  flags 
)

Remove notification of real object destruction.

Since
14.0.0
Parameters
weakproxyThe weak object
cbCallback to remove from destroy notification list
dataData pointer to match
flagsOBJ_NOLOCK to avoid locking weakproxy. OBJ_MULTIPLE to remove all copies of the same cb / data pair.
Returns
The number of subscriptions removed.
Return values
0cb / data pair not found, nothing removed.
-1Failure due to invalid parameters.
Note
Unless flags includes OBJ_MULTIPLE, this will only remove a single copy of the cb / data pair. If it was subscribed multiple times it must be unsubscribed as many times. The OBJ_MULTIPLE flag can be used to remove matching subscriptions.
When it's time to run callbacks they are copied to a temporary list so the weakproxy can be unlocked before running. That means it's possible for this function to find nothing before the callback is run in another thread.

Definition at line 973 of file astobj2.c.

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}
@ OBJ_MULTIPLE
Definition: astobj2.h:1049
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#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

References ao2_lock, ao2_unlock, AO2_WEAK, ast_free, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, ao2_weakproxy_notification::data, ao2_weakproxy::destroyed_cb, INTERNAL_OBJ_CHECK, ao2_weakproxy_notification::list, __priv_data::magic, OBJ_MULTIPLE, OBJ_NOLOCK, astobj2::priv_data, and sub.

Referenced by AST_TEST_DEFINE().

◆ astobj2_cleanup()

static void astobj2_cleanup ( void  )
static

Definition at line 1157 of file astobj2.c.

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}
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define ast_opt_ref_debug
Definition: options.h:135
#define ARRAY_LEN(a)
Definition: utils.h:666

References ARRAY_LEN, ast_cli_unregister_multiple(), ast_opt_ref_debug, NULL, and ref_log.

Referenced by astobj2_init().

◆ astobj2_init()

int astobj2_init ( void  )

Provided by astobj2.c

Definition at line 1169 of file astobj2.c.

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}
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition: clicompat.c:19
static void astobj2_cleanup(void)
Definition: astobj2.c:1157
int container_init(void)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
const char * ast_config_AST_LOG_DIR
Definition: options.c:159

References ARRAY_LEN, ast_cli_register_multiple, ast_config_AST_LOG_DIR, ast_log, ast_opt_ref_debug, ast_register_cleanup(), astobj2_cleanup(), container_init(), LOG_ERROR, NULL, and ref_log.

Referenced by asterisk_daemon().

◆ internal_ao2_alloc()

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 
)
static

Definition at line 684 of file astobj2.c.

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}
void * __ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func) attribute_malloc
Definition: astmm.c:1603
#define EXTERNAL_OBJ(_p)
convert from a pointer _p to an astobj2 object
Definition: astobj2.c:191
#define ao2_t_bump(obj, tag)
Definition: astobj2.h:483
#define __LOG_DEBUG
#define ast_mutex_init(pmutex)
Definition: lock.h:186
#define ast_rwlock_init(rwlock)
wrapper for rwlock with tracking enabled
Definition: lock.h:224
struct __priv_data priv_data
Definition: astobj2.c:122
struct __priv_data priv_data
Definition: astobj2.c:146
struct __priv_data priv_data
Definition: astobj2.c:135

References __ast_calloc(), __LOG_DEBUG, __LOG_ERROR, AO2_ALLOC_OPT_LOCK_MASK, AO2_ALLOC_OPT_LOCK_MUTEX, AO2_ALLOC_OPT_LOCK_NOLOCK, AO2_ALLOC_OPT_LOCK_OBJ, AO2_ALLOC_OPT_LOCK_RWLOCK, AO2_ALLOC_OPT_NO_REF_DEBUG, AO2_MAGIC, ao2_t_bump, ao2_t_ref, ast_atomic_fetchadd_int(), ast_get_tid(), ast_log, ast_mutex_init, ast_rwlock_init, __priv_data::destructor_fn, EXTERNAL_OBJ, make_ari_stubs::file, ao2_lock_priv::lock, ao2_rwlock_priv::lock, ao2_lockobj_priv::lock, astobj2_lockobj::lockobj, __priv_data::magic, astobj2_lock::mutex, NULL, __priv_data::options, options, astobj2::priv_data, astobj2_lock::priv_data, astobj2_rwlock::priv_data, astobj2_lockobj::priv_data, __priv_data::ref_counter, ref_log, and astobj2_rwlock::rwlock.

Referenced by __ao2_alloc(), and __ao2_alloc_with_lockobj().

◆ internal_is_ao2_object()

int internal_is_ao2_object ( void *  user_data)

Definition at line 193 of file astobj2.c.

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}
#define IS_AO2_MAGIC_BAD(p)
Definition: astobj2.c:98

References INTERNAL_OBJ, IS_AO2_MAGIC_BAD, and astobj2::user_data.

◆ log_bad_ao2()

void log_bad_ao2 ( void *  user_data,
const char *  file,
int  line,
const char *  func 
)

Definition at line 206 of file astobj2.c.

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}

References __ast_assert_failed(), make_ari_stubs::file, INTERNAL_OBJ, __priv_data::magic, astobj2::priv_data, and astobj2::user_data.

Variable Documentation

◆ ref_log

FILE* ref_log
static