Asterisk - The Open Source Telephony Project GIT-master-266378a
Loading...
Searching...
No Matches
Data Structures | Macros | Typedefs | Functions
lock.h File Reference

Asterisk locking-related definitions: More...

#include <pthread.h>
#include <time.h>
#include <sys/param.h>
#include <execinfo.h>
#include "asterisk/backtrace.h"
#include "asterisk/logger.h"
#include "asterisk/compiler.h"
#include "asterisk/inline_api.h"
Include dependency graph for lock.h:

Go to the source code of this file.

Data Structures

struct  ast_lock_track
 Lock tracking information. More...
 
struct  ast_lock_track_flags
 
struct  ast_mutex_info
 Structure for mutex and tracking information. More...
 
struct  ast_rwlock_info
 Structure for rwlock and tracking information. More...
 

Macros

#define __AST_MUTEX_DEFINE(scope, mutex, init_val, track)   scope ast_mutex_t mutex = init_val
 
#define __AST_RWLOCK_DEFINE(scope, rwlock, init_val, track)   scope ast_rwlock_t rwlock = init_val
 
#define __AST_RWLOCK_INIT_VALUE   PTHREAD_RWLOCK_INITIALIZER
 
#define AO2_DEADLOCK_AVOIDANCE(obj)
 
#define ast_cond_broadcast(cond)   __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
 
#define ast_cond_destroy(cond)   __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
 
#define ast_cond_init(cond, attr)   __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)
 
#define ast_cond_signal(cond)   __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)
 
#define ast_cond_timedwait(cond, mutex, time)   __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)
 
#define ast_cond_wait(cond, mutex)   __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)
 
#define AST_LOCK_TRACK_INIT_VALUE   { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_MUTEX_INIT_VALUE }
 
#define AST_MAX_REENTRANCY   10
 
#define AST_MUTEX_DEFINE_STATIC(mutex)   __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
 
#define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex)   __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
 
#define ast_mutex_destroy(a)   __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
 
#define ast_mutex_init(pmutex)   __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
 
#define ast_mutex_init_notracking(pmutex)   __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)
 
#define AST_MUTEX_INIT_VALUE   { PTHREAD_MUTEX_INIT_VALUE, NULL, {1, 0} }
 
#define AST_MUTEX_INIT_VALUE_NOTRACKING   { PTHREAD_MUTEX_INIT_VALUE, NULL, {0, 0} }
 
#define AST_MUTEX_INITIALIZER   __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
 
#define AST_MUTEX_KIND   PTHREAD_MUTEX_RECURSIVE_NP
 
#define ast_mutex_lock(a)   __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
 
#define ast_mutex_trylock(a)   __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
 
#define ast_mutex_unlock(a)   __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)
 
#define AST_PTHREADT_NULL   (pthread_t) -1
 
#define AST_PTHREADT_STOP   (pthread_t) -2
 
#define AST_RWLOCK_DEFINE_STATIC(rwlock)   __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE, 1)
 
#define AST_RWLOCK_DEFINE_STATIC_NOTRACKING(rwlock)   __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE_NOTRACKING, 0)
 
#define ast_rwlock_destroy(rwlock)   __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
 
#define ast_rwlock_init(rwlock)   __ast_rwlock_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
 wrapper for rwlock with tracking enabled
 
#define ast_rwlock_init_notracking(rwlock)   __ast_rwlock_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)
 wrapper for ast_rwlock_init with tracking disabled
 
#define AST_RWLOCK_INIT_VALUE   { __AST_RWLOCK_INIT_VALUE, NULL, {1, 0} }
 
#define AST_RWLOCK_INIT_VALUE_NOTRACKING   { __AST_RWLOCK_INIT_VALUE, NULL, {0, 0} }
 
#define ast_rwlock_rdlock(a)   __ast_rwlock_rdlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a)
 
#define ast_rwlock_timedrdlock(a, b)   __ast_rwlock_timedrdlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a, b)
 
#define ast_rwlock_timedwrlock(a, b)   __ast_rwlock_timedwrlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a, b)
 
#define ast_rwlock_tryrdlock(a)   __ast_rwlock_tryrdlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a)
 
#define ast_rwlock_trywrlock(a)   __ast_rwlock_trywrlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a)
 
#define ast_rwlock_unlock(a)   __ast_rwlock_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a)
 
#define ast_rwlock_wrlock(a)   __ast_rwlock_wrlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a)
 
#define CHANNEL_DEADLOCK_AVOIDANCE(chan)
 
#define DEADLOCK_AVOIDANCE(lock)
 
#define DLA_LOCK(lock)   ast_mutex_lock(lock)
 
#define DLA_UNLOCK(lock)   ast_mutex_unlock(lock)
 
#define gethostbyname   __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
 
#define pthread_cond_broadcast   use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
 
#define pthread_cond_destroy   use_ast_cond_destroy_instead_of_pthread_cond_destroy
 
#define pthread_cond_init   use_ast_cond_init_instead_of_pthread_cond_init
 
#define pthread_cond_signal   use_ast_cond_signal_instead_of_pthread_cond_signal
 
#define pthread_cond_t   use_ast_cond_t_instead_of_pthread_cond_t
 
#define pthread_cond_timedwait   use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
 
#define pthread_cond_wait   use_ast_cond_wait_instead_of_pthread_cond_wait
 
#define pthread_create   __use_ast_pthread_create_instead__
 
#define pthread_mutex_destroy   use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
 
#define pthread_mutex_init   use_ast_mutex_init_instead_of_pthread_mutex_init
 
#define PTHREAD_MUTEX_INIT_VALUE   PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
 
#define pthread_mutex_lock   use_ast_mutex_lock_instead_of_pthread_mutex_lock
 
#define pthread_mutex_t   use_ast_mutex_t_instead_of_pthread_mutex_t
 
#define pthread_mutex_trylock   use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
 
#define pthread_mutex_unlock   use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
 
#define ROFFSET   ((lt->reentrancy > 0) ? (lt->reentrancy-1) : 0)
 
#define SCOPED_AO2LOCK(varname, obj)   SCOPED_LOCK(varname, (obj), ao2_lock, ao2_unlock)
 scoped lock specialization for ao2 mutexes.
 
#define SCOPED_AO2RDLOCK(varname, obj)   SCOPED_LOCK(varname, (obj), ao2_rdlock, ao2_unlock)
 scoped lock specialization for ao2 read locks.
 
#define SCOPED_AO2WRLOCK(varname, obj)   SCOPED_LOCK(varname, (obj), ao2_wrlock, ao2_unlock)
 scoped lock specialization for ao2 write locks.
 
#define SCOPED_CHANNELLOCK(varname, chan)   SCOPED_LOCK(varname, (chan), ast_channel_lock, ast_channel_unlock)
 scoped lock specialization for channels.
 
#define SCOPED_LOCK(varname, lock, lockfunc, unlockfunc)    RAII_VAR(typeof((lock)), varname, ({lockfunc((lock)); (lock); }), unlockfunc)
 Scoped Locks.
 
#define SCOPED_MUTEX(varname, lock)   SCOPED_LOCK(varname, (lock), ast_mutex_lock, ast_mutex_unlock)
 scoped lock specialization for mutexes
 
#define SCOPED_RDLOCK(varname, lock)   SCOPED_LOCK(varname, (lock), ast_rwlock_rdlock, ast_rwlock_unlock)
 scoped lock specialization for read locks
 
#define SCOPED_WRLOCK(varname, lock)   SCOPED_LOCK(varname, (lock), ast_rwlock_wrlock, ast_rwlock_unlock)
 scoped lock specialization for write locks
 

Typedefs

typedef pthread_cond_t ast_cond_t
 
typedef struct ast_mutex_info ast_mutex_t
 
typedef struct ast_rwlock_info ast_rwlock_t
 

Functions

int __ast_cond_broadcast (const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
 
int __ast_cond_destroy (const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
 
int __ast_cond_init (const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond, pthread_condattr_t *cond_attr)
 
int __ast_cond_signal (const char *filename, int lineno, const char *func, const char *cond_name, ast_cond_t *cond)
 
int __ast_cond_timedwait (const char *filename, int lineno, const char *func, const char *cond_name, const char *mutex_name, ast_cond_t *cond, ast_mutex_t *t, const struct timespec *abstime)
 
int __ast_cond_wait (const char *filename, int lineno, const char *func, const char *cond_name, const char *mutex_name, ast_cond_t *cond, ast_mutex_t *t)
 
int __ast_pthread_mutex_destroy (const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
 
int __ast_pthread_mutex_init (int tracking, const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
 
int __ast_pthread_mutex_lock (const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
 
int __ast_pthread_mutex_trylock (const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
 
int __ast_pthread_mutex_unlock (const char *filename, int lineno, const char *func, const char *mutex_name, ast_mutex_t *t)
 
int __ast_rwlock_destroy (const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
 
int __ast_rwlock_init (int tracking, const char *filename, int lineno, const char *func, const char *rwlock_name, ast_rwlock_t *t)
 
int __ast_rwlock_rdlock (const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
 
int __ast_rwlock_timedrdlock (const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name, const struct timespec *abs_timeout)
 
int __ast_rwlock_timedwrlock (const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name, const struct timespec *abs_timeout)
 
int __ast_rwlock_tryrdlock (const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
 
int __ast_rwlock_trywrlock (const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
 
int __ast_rwlock_unlock (const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
 
int __ast_rwlock_wrlock (const char *filename, int lineno, const char *func, ast_rwlock_t *t, const char *name)
 
#define ast_atomic_add_fetch(ptr, val, memorder)   __atomic_add_fetch((ptr), (val), (memorder))
 
#define ast_atomic_and_fetch(ptr, val, memorder)   __atomic_and_fetch((ptr), (val), (memorder))
 
int ast_atomic_dec_and_test (volatile int *p)
 decrement *p by 1 and return true if the variable has reached 0.
 
#define ast_atomic_fetch_add(ptr, val, memorder)   __atomic_fetch_add((ptr), (val), (memorder))
 Support for atomic instructions.
 
#define ast_atomic_fetch_and(ptr, val, memorder)   __atomic_fetch_and((ptr), (val), (memorder))
 
#define ast_atomic_fetch_or(ptr, val, memorder)   __atomic_fetch_or((ptr), (val), (memorder))
 
#define ast_atomic_fetch_sub(ptr, val, memorder)   __atomic_fetch_sub((ptr), (val), (memorder))
 
#define ast_atomic_fetch_xor(ptr, val, memorder)   __atomic_fetch_xor((ptr), (val), (memorder))
 
int ast_atomic_fetchadd_int (volatile int *p, int v)
 Atomically add v to *p and return the previous value of *p.
 
#define ast_atomic_flag_clear(ptr, val, memorder)   ast_atomic_fetch_and((ptr), ~(val), (memorder))
 
#define ast_atomic_flag_set(ptr, val, memorder)   ast_atomic_fetch_or((ptr), (val), (memorder))
 
#define ast_atomic_or_fetch(ptr, val, memorder)   __atomic_or_fetch((ptr), (val), (memorder))
 
#define ast_atomic_sub_fetch(ptr, val, memorder)   __atomic_sub_fetch((ptr), (val), (memorder))
 
#define ast_atomic_xor_fetch(ptr, val, memorder)   __atomic_xor_fetch((ptr), (val), (memorder))
 

Detailed Description

Asterisk locking-related definitions:

Magic number.

This is used to verify that a pointer is a valid astobj2 or ao2_weak reference.

Note
This field is constant after object creation. It shares a uint32_t with options and lockused.
Warning
Stealing bits for any additional writable fields would cause reentrancy issues if using bitfields. If any additional writable bits are required in the future we will need to put all bitfields into a single 'uint32_t flags' field and use atomic operations from to perform writes.

Definition in file lock.h.

Macro Definition Documentation

◆ __AST_MUTEX_DEFINE

#define __AST_MUTEX_DEFINE (   scope,
  mutex,
  init_val,
  track 
)    scope ast_mutex_t mutex = init_val

Definition at line 524 of file lock.h.

◆ __AST_RWLOCK_DEFINE

#define __AST_RWLOCK_DEFINE (   scope,
  rwlock,
  init_val,
  track 
)    scope ast_rwlock_t rwlock = init_val

Definition at line 547 of file lock.h.

◆ __AST_RWLOCK_INIT_VALUE

#define __AST_RWLOCK_INIT_VALUE   PTHREAD_RWLOCK_INITIALIZER

Definition at line 91 of file lock.h.

◆ AO2_DEADLOCK_AVOIDANCE

#define AO2_DEADLOCK_AVOIDANCE (   obj)
Value:
ao2_unlock(obj); \
usleep(1); \
ao2_lock(obj);
#define ao2_unlock(a)
Definition astobj2.h:729

Definition at line 476 of file lock.h.

486 { \
487 int __res; \
488 if (!(__res = ast_mutex_unlock(lock))) { \
489 usleep(1); \
490 ast_mutex_lock(lock); \
491 } else { \
492 ast_log(LOG_WARNING, "Failed to unlock mutex '%s' (%s). I will NOT try to relock. {{{ THIS IS A BUG. }}}\n", #lock, strerror(__res)); \
493 } \
494 } while (0)
495
496#define DLA_UNLOCK(lock) ast_mutex_unlock(lock)
497
498#define DLA_LOCK(lock) ast_mutex_lock(lock)
499
500#endif /* !DEBUG_THREADS */
501
502#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS)
503/*
504 * If AST_MUTEX_INIT_W_CONSTRUCTORS is defined, use file scope constructors
505 * and destructors to create/destroy global mutexes.
506 */
507#define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) \
508 scope ast_mutex_t mutex = init_val; \
509static void __attribute__((constructor)) init_##mutex(void) \
510{ \
511 if (track) \
512 ast_mutex_init(&mutex); \
513 else \
514 ast_mutex_init_notracking(&mutex); \
515} \
516 \
517static void __attribute__((destructor)) fini_##mutex(void) \
518{ \
519 ast_mutex_destroy(&mutex); \
520}
521#else /* !AST_MUTEX_INIT_W_CONSTRUCTORS */
522/* By default, use static initialization of mutexes. */
523#define __AST_MUTEX_DEFINE(scope, mutex, init_val, track) scope ast_mutex_t mutex = init_val
524#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
525
526#define AST_MUTEX_DEFINE_STATIC(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)
527#define AST_MUTEX_DEFINE_STATIC_NOTRACKING(mutex) __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)
528
529
530/* Statically declared read/write locks */
531#ifdef AST_MUTEX_INIT_W_CONSTRUCTORS
532#define __AST_RWLOCK_DEFINE(scope, rwlock, init_val, track) \
533 scope ast_rwlock_t rwlock = init_val; \
534static void __attribute__((constructor)) init_##rwlock(void) \
535{ \
536 if (track) \
537 ast_rwlock_init(&rwlock); \
538 else \
539 ast_rwlock_init_notracking(&rwlock); \
540} \
541static void __attribute__((destructor)) fini_##rwlock(void) \
542{ \
543 ast_rwlock_destroy(&rwlock); \
544}
545#else
546#define __AST_RWLOCK_DEFINE(scope, rwlock, init_val, track) scope ast_rwlock_t rwlock = init_val
547#endif
548
549#define AST_RWLOCK_DEFINE_STATIC(rwlock) __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE, 1)
550#define AST_RWLOCK_DEFINE_STATIC_NOTRACKING(rwlock) __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE_NOTRACKING, 0)
551
552/*!
553 * \brief Scoped Locks
554 *
555 * Scoped locks provide a way to use RAII locks. In other words,
556 * declaration of a scoped lock will automatically define and lock
557 * the lock. When the lock goes out of scope, it will automatically
558 * be unlocked.
559 *
560 * \code
561 * int some_function(struct ast_channel *chan)
562 * {
563 * SCOPED_LOCK(lock, chan, ast_channel_lock, ast_channel_unlock);
564 *
565 * if (!strcmp(ast_channel_name(chan, "foo")) {
566 * return 0;
567 * }
568 *
569 * return -1;
570 * }
571 * \endcode
572 *
573 * In the above example, neither return path requires explicit unlocking
574 * of the channel.
575 *
576 * \note
577 * Care should be taken when using SCOPED_LOCKS in conjunction with ao2 objects.
578 * ao2 objects should be unlocked before they are unreffed. Since SCOPED_LOCK runs
579 * once the variable goes out of scope, this can easily lead to situations where the
580 * variable gets unlocked after it is unreffed.
581 *
582 * \param varname The unique name to give to the scoped lock. You are not likely to reference
583 * this outside of the SCOPED_LOCK invocation.
584 * \param lock The variable to lock. This can be anything that can be passed to a locking
585 * or unlocking function.
586 * \param lockfunc The function to call to lock the lock
587 * \param unlockfunc The function to call to unlock the lock
588 */
589#define SCOPED_LOCK(varname, lock, lockfunc, unlockfunc) \
590 RAII_VAR(typeof((lock)), varname, ({lockfunc((lock)); (lock); }), unlockfunc)
591
592/*!
593 * \brief scoped lock specialization for mutexes
594 */
595#define SCOPED_MUTEX(varname, lock) SCOPED_LOCK(varname, (lock), ast_mutex_lock, ast_mutex_unlock)
596
597/*!
598 * \brief scoped lock specialization for read locks
599 */
600#define SCOPED_RDLOCK(varname, lock) SCOPED_LOCK(varname, (lock), ast_rwlock_rdlock, ast_rwlock_unlock)
601
602/*!
603 * \brief scoped lock specialization for write locks
604 */
605#define SCOPED_WRLOCK(varname, lock) SCOPED_LOCK(varname, (lock), ast_rwlock_wrlock, ast_rwlock_unlock)
606
607/*!
608 * \brief scoped lock specialization for ao2 mutexes.
609 */
610#define SCOPED_AO2LOCK(varname, obj) SCOPED_LOCK(varname, (obj), ao2_lock, ao2_unlock)
611
612/*!
613 * \brief scoped lock specialization for ao2 read locks.
614 */
615#define SCOPED_AO2RDLOCK(varname, obj) SCOPED_LOCK(varname, (obj), ao2_rdlock, ao2_unlock)
616
617/*!
618 * \brief scoped lock specialization for ao2 write locks.
619 */
620#define SCOPED_AO2WRLOCK(varname, obj) SCOPED_LOCK(varname, (obj), ao2_wrlock, ao2_unlock)
621
622/*!
623 * \brief scoped lock specialization for channels.
624 */
625#define SCOPED_CHANNELLOCK(varname, chan) SCOPED_LOCK(varname, (chan), ast_channel_lock, ast_channel_unlock)
626
627#ifndef __CYGWIN__ /* temporary disabled for cygwin */
628#define pthread_mutex_t use_ast_mutex_t_instead_of_pthread_mutex_t
629#define pthread_cond_t use_ast_cond_t_instead_of_pthread_cond_t
630#endif
631#define pthread_mutex_lock use_ast_mutex_lock_instead_of_pthread_mutex_lock
632#define pthread_mutex_unlock use_ast_mutex_unlock_instead_of_pthread_mutex_unlock
633#define pthread_mutex_trylock use_ast_mutex_trylock_instead_of_pthread_mutex_trylock
634#define pthread_mutex_init use_ast_mutex_init_instead_of_pthread_mutex_init
635#define pthread_mutex_destroy use_ast_mutex_destroy_instead_of_pthread_mutex_destroy
636#define pthread_cond_init use_ast_cond_init_instead_of_pthread_cond_init
637#define pthread_cond_destroy use_ast_cond_destroy_instead_of_pthread_cond_destroy
638#define pthread_cond_signal use_ast_cond_signal_instead_of_pthread_cond_signal
639#define pthread_cond_broadcast use_ast_cond_broadcast_instead_of_pthread_cond_broadcast
640#define pthread_cond_wait use_ast_cond_wait_instead_of_pthread_cond_wait
641#define pthread_cond_timedwait use_ast_cond_timedwait_instead_of_pthread_cond_timedwait
642
643#define AST_MUTEX_INITIALIZER __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__
644
645#define gethostbyname __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__
646
647#ifndef __linux__
648#define pthread_create __use_ast_pthread_create_instead__
649#endif
650
651/*!
652 * \brief Support for atomic instructions.
653 *
654 * These macros implement a uniform interface to use built-in atomic functionality.
655 * If available __atomic built-ins are prefered. Legacy __sync built-ins are used
656 * as a fallback for older compilers.
657 *
658 * Detailed documentation can be found in the GCC manual, all API's are modeled after
659 * the __atomic interfaces but using the namespace ast_atomic.
660 *
661 * The memorder argument is always ignored by legacy __sync functions. Invalid
662 * memorder arguments do not produce errors unless __atomic functions are supported
663 * as the argument is erased by the preprocessor.
664 *
665 * \note ast_atomic_fetch_nand and ast_atomic_nand_fetch purposely do not exist.
666 * It's implementation was broken prior to gcc-4.4.
667 *
668 * @{
669 */
670
671#include "asterisk/inline_api.h"
672
673#if defined(HAVE_C_ATOMICS)
674/*! Atomic += */
675#define ast_atomic_fetch_add(ptr, val, memorder) __atomic_fetch_add((ptr), (val), (memorder))
676#define ast_atomic_add_fetch(ptr, val, memorder) __atomic_add_fetch((ptr), (val), (memorder))
677
678/*! Atomic -= */
679#define ast_atomic_fetch_sub(ptr, val, memorder) __atomic_fetch_sub((ptr), (val), (memorder))
680#define ast_atomic_sub_fetch(ptr, val, memorder) __atomic_sub_fetch((ptr), (val), (memorder))
681
682/*! Atomic &= */
683#define ast_atomic_fetch_and(ptr, val, memorder) __atomic_fetch_and((ptr), (val), (memorder))
684#define ast_atomic_and_fetch(ptr, val, memorder) __atomic_and_fetch((ptr), (val), (memorder))
685
686/*! Atomic |= */
687#define ast_atomic_fetch_or(ptr, val, memorder) __atomic_fetch_or((ptr), (val), (memorder))
688#define ast_atomic_or_fetch(ptr, val, memorder) __atomic_or_fetch((ptr), (val), (memorder))
689
690/*! Atomic xor = */
691#define ast_atomic_fetch_xor(ptr, val, memorder) __atomic_fetch_xor((ptr), (val), (memorder))
692#define ast_atomic_xor_fetch(ptr, val, memorder) __atomic_xor_fetch((ptr), (val), (memorder))
693
694#if 0
695/* Atomic compare and swap
696 *
697 * See comments near the __atomic implementation for why this is disabled.
698 */
699#define ast_atomic_compare_exchange_n(ptr, expected, desired, success_memorder, failure_memorder) \
700 __atomic_compare_exchange_n((ptr), (expected), (desired), 0, success_memorder, failure_memorder)
701
702#define ast_atomic_compare_exchange(ptr, expected, desired, success_memorder, failure_memorder) \
703 __atomic_compare_exchange((ptr), (expected), (desired), 0, success_memorder, failure_memorder)
704#endif
705
706#elif defined(HAVE_GCC_ATOMICS)
707/*! Atomic += */
708#define ast_atomic_fetch_add(ptr, val, memorder) __sync_fetch_and_add((ptr), (val))
709#define ast_atomic_add_fetch(ptr, val, memorder) __sync_add_and_fetch((ptr), (val))
710
711/*! Atomic -= */
712#define ast_atomic_fetch_sub(ptr, val, memorder) __sync_fetch_and_sub((ptr), (val))
713#define ast_atomic_sub_fetch(ptr, val, memorder) __sync_sub_and_fetch((ptr), (val))
714
715/*! Atomic &= */
716#define ast_atomic_fetch_and(ptr, val, memorder) __sync_fetch_and_and((ptr), (val))
717#define ast_atomic_and_fetch(ptr, val, memorder) __sync_and_and_fetch((ptr), (val))
718
719/*! Atomic |= */
720#define ast_atomic_fetch_or(ptr, val, memorder) __sync_fetch_and_or((ptr), (val))
721#define ast_atomic_or_fetch(ptr, val, memorder) __sync_or_and_fetch((ptr), (val))
722
723/*! Atomic xor = */
724#define ast_atomic_fetch_xor(ptr, val, memorder) __sync_fetch_and_xor((ptr), (val))
725#define ast_atomic_xor_fetch(ptr, val, memorder) __sync_xor_and_fetch((ptr), (val))
726
727#if 0
728/* Atomic compare and swap
729 *
730 * The \a expected argument is a pointer, I'm guessing __atomic built-ins
731 * perform all memory reads/writes in a single atomic operation. I don't
732 * believe this is possible to exactly replicate using __sync built-ins.
733 * Will need to determine potential use cases of this feature and write a
734 * wrapper which provides consistant behavior between __sync and __atomic
735 * implementations.
736 */
737#define ast_atomic_compare_exchange_n(ptr, expected, desired, success_memorder, failure_memorder) \
738 __sync_bool_compare_and_swap((ptr), *(expected), (desired))
739
740#define ast_atomic_compare_exchange(ptr, expected, desired, success_memorder, failure_memorder) \
741 __sync_bool_compare_and_swap((ptr), *(expected), *(desired))
742#endif
743
744#else
745#error "Atomics not available."
746#endif
747
748/*! Atomic flag set */
749#define ast_atomic_flag_set(ptr, val, memorder) ast_atomic_fetch_or((ptr), (val), (memorder))
750
751/*! Atomic flag clear */
752#define ast_atomic_flag_clear(ptr, val, memorder) ast_atomic_fetch_and((ptr), ~(val), (memorder))
753
754/*!
755 * \brief Atomically add v to *p and return the previous value of *p.
756 *
757 * This can be used to handle reference counts, and the return value
758 * can be used to generate unique identifiers.
759 */
760AST_INLINE_API(int ast_atomic_fetchadd_int(volatile int *p, int v),
761{
762 return ast_atomic_fetch_add(p, v, __ATOMIC_RELAXED);
763})
764
765/*!
766 * \brief decrement *p by 1 and return true if the variable has reached 0.
767 *
768 * Useful e.g. to check if a refcount has reached 0.
769 */
770AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
771{
772 return ast_atomic_sub_fetch(p, 1, __ATOMIC_RELAXED) == 0;
773})
774
775#if defined(__cplusplus) || defined(c_plusplus)
776}
777#endif
778
779/*! @} */
780
781#endif /* _ASTERISK_LOCK_H */
ast_mutex_t lock
Definition app_sla.c:337
#define LOG_WARNING
Inlinable API function macro.
#define AST_INLINE_API(hdr, body)
Definition inline_api.h:54
#define ast_mutex_unlock(a)
Definition lock.h:197
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:764
#define ast_atomic_sub_fetch(ptr, val, memorder)
Definition lock.h:681
int ast_atomic_dec_and_test(volatile int *p)
decrement *p by 1 and return true if the variable has reached 0.
Definition lock.h:774
#define ast_atomic_fetch_add(ptr, val, memorder)
Support for atomic instructions.
Definition lock.h:676

◆ ast_atomic_add_fetch

#define ast_atomic_add_fetch (   ptr,
  val,
  memorder 
)    __atomic_add_fetch((ptr), (val), (memorder))

Definition at line 677 of file lock.h.

◆ ast_atomic_and_fetch

#define ast_atomic_and_fetch (   ptr,
  val,
  memorder 
)    __atomic_and_fetch((ptr), (val), (memorder))

Definition at line 685 of file lock.h.

◆ ast_atomic_fetch_add

#define ast_atomic_fetch_add (   ptr,
  val,
  memorder 
)    __atomic_fetch_add((ptr), (val), (memorder))

Support for atomic instructions.

These macros implement a uniform interface to use built-in atomic functionality. If available __atomic built-ins are prefered. Legacy __sync built-ins are used as a fallback for older compilers.

Detailed documentation can be found in the GCC manual, all API's are modeled after the __atomic interfaces but using the namespace ast_atomic.

The memorder argument is always ignored by legacy __sync functions. Invalid memorder arguments do not produce errors unless __atomic functions are supported as the argument is erased by the preprocessor.

Note
ast_atomic_fetch_nand and ast_atomic_nand_fetch purposely do not exist. It's implementation was broken prior to gcc-4.4.

Atomic +=

Definition at line 676 of file lock.h.

◆ ast_atomic_fetch_and

#define ast_atomic_fetch_and (   ptr,
  val,
  memorder 
)    __atomic_fetch_and((ptr), (val), (memorder))

Atomic &=

Definition at line 684 of file lock.h.

◆ ast_atomic_fetch_or

#define ast_atomic_fetch_or (   ptr,
  val,
  memorder 
)    __atomic_fetch_or((ptr), (val), (memorder))

Atomic |=

Definition at line 688 of file lock.h.

◆ ast_atomic_fetch_sub

#define ast_atomic_fetch_sub (   ptr,
  val,
  memorder 
)    __atomic_fetch_sub((ptr), (val), (memorder))

Atomic -=

Definition at line 680 of file lock.h.

◆ ast_atomic_fetch_xor

#define ast_atomic_fetch_xor (   ptr,
  val,
  memorder 
)    __atomic_fetch_xor((ptr), (val), (memorder))

Atomic xor =

Definition at line 692 of file lock.h.

◆ ast_atomic_flag_clear

#define ast_atomic_flag_clear (   ptr,
  val,
  memorder 
)    ast_atomic_fetch_and((ptr), ~(val), (memorder))

Atomic flag clear

Definition at line 753 of file lock.h.

◆ ast_atomic_flag_set

#define ast_atomic_flag_set (   ptr,
  val,
  memorder 
)    ast_atomic_fetch_or((ptr), (val), (memorder))

Atomic flag set

Definition at line 750 of file lock.h.

◆ ast_atomic_or_fetch

#define ast_atomic_or_fetch (   ptr,
  val,
  memorder 
)    __atomic_or_fetch((ptr), (val), (memorder))

Definition at line 689 of file lock.h.

◆ ast_atomic_sub_fetch

#define ast_atomic_sub_fetch (   ptr,
  val,
  memorder 
)    __atomic_sub_fetch((ptr), (val), (memorder))

Definition at line 681 of file lock.h.

◆ ast_atomic_xor_fetch

#define ast_atomic_xor_fetch (   ptr,
  val,
  memorder 
)    __atomic_xor_fetch((ptr), (val), (memorder))

Definition at line 693 of file lock.h.

◆ ast_cond_broadcast

#define ast_cond_broadcast (   cond)    __ast_cond_broadcast(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)

Definition at line 211 of file lock.h.

◆ ast_cond_destroy

#define ast_cond_destroy (   cond)    __ast_cond_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)

Definition at line 209 of file lock.h.

◆ ast_cond_init

#define ast_cond_init (   cond,
  attr 
)    __ast_cond_init(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond, attr)

Definition at line 208 of file lock.h.

◆ ast_cond_signal

#define ast_cond_signal (   cond)    __ast_cond_signal(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, cond)

Definition at line 210 of file lock.h.

◆ ast_cond_timedwait

#define ast_cond_timedwait (   cond,
  mutex,
  time 
)    __ast_cond_timedwait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex, time)

Definition at line 213 of file lock.h.

◆ ast_cond_wait

#define ast_cond_wait (   cond,
  mutex 
)    __ast_cond_wait(__FILE__, __LINE__, __PRETTY_FUNCTION__, #cond, #mutex, cond, mutex)

Definition at line 212 of file lock.h.

◆ AST_LOCK_TRACK_INIT_VALUE

#define AST_LOCK_TRACK_INIT_VALUE   { { NULL }, { 0 }, 0, { NULL }, { 0 }, {{{ 0 }}}, PTHREAD_MUTEX_INIT_VALUE }

Definition at line 97 of file lock.h.

◆ AST_MAX_REENTRANCY

#define AST_MAX_REENTRANCY   10

Definition at line 108 of file lock.h.

◆ AST_MUTEX_DEFINE_STATIC

#define AST_MUTEX_DEFINE_STATIC (   mutex)    __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE, 1)

Definition at line 527 of file lock.h.

◆ AST_MUTEX_DEFINE_STATIC_NOTRACKING

#define AST_MUTEX_DEFINE_STATIC_NOTRACKING (   mutex)    __AST_MUTEX_DEFINE(static, mutex, AST_MUTEX_INIT_VALUE_NOTRACKING, 0)

Definition at line 528 of file lock.h.

◆ ast_mutex_destroy

#define ast_mutex_destroy (   a)    __ast_pthread_mutex_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)

Definition at line 195 of file lock.h.

◆ ast_mutex_init

#define ast_mutex_init (   pmutex)    __ast_pthread_mutex_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)

Definition at line 193 of file lock.h.

◆ ast_mutex_init_notracking

#define ast_mutex_init_notracking (   pmutex)    __ast_pthread_mutex_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #pmutex, pmutex)

Definition at line 194 of file lock.h.

◆ AST_MUTEX_INIT_VALUE

#define AST_MUTEX_INIT_VALUE   { PTHREAD_MUTEX_INIT_VALUE, NULL, {1, 0} }

Definition at line 102 of file lock.h.

◆ AST_MUTEX_INIT_VALUE_NOTRACKING

#define AST_MUTEX_INIT_VALUE_NOTRACKING   { PTHREAD_MUTEX_INIT_VALUE, NULL, {0, 0} }

Definition at line 103 of file lock.h.

◆ AST_MUTEX_INITIALIZER

#define AST_MUTEX_INITIALIZER   __use_AST_MUTEX_DEFINE_STATIC_rather_than_AST_MUTEX_INITIALIZER__

Definition at line 644 of file lock.h.

◆ AST_MUTEX_KIND

#define AST_MUTEX_KIND   PTHREAD_MUTEX_RECURSIVE_NP

Definition at line 84 of file lock.h.

◆ ast_mutex_lock

#define ast_mutex_lock (   a)    __ast_pthread_mutex_lock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)

Definition at line 196 of file lock.h.

◆ ast_mutex_trylock

#define ast_mutex_trylock (   a)    __ast_pthread_mutex_trylock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)

Definition at line 198 of file lock.h.

◆ ast_mutex_unlock

#define ast_mutex_unlock (   a)    __ast_pthread_mutex_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, #a, a)

Definition at line 197 of file lock.h.

◆ AST_PTHREADT_NULL

#define AST_PTHREADT_NULL   (pthread_t) -1

Definition at line 73 of file lock.h.

◆ AST_PTHREADT_STOP

#define AST_PTHREADT_STOP   (pthread_t) -2

Definition at line 74 of file lock.h.

◆ AST_RWLOCK_DEFINE_STATIC

#define AST_RWLOCK_DEFINE_STATIC (   rwlock)    __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE, 1)

Definition at line 550 of file lock.h.

◆ AST_RWLOCK_DEFINE_STATIC_NOTRACKING

#define AST_RWLOCK_DEFINE_STATIC_NOTRACKING (   rwlock)    __AST_RWLOCK_DEFINE(static, rwlock, AST_RWLOCK_INIT_VALUE_NOTRACKING, 0)

Definition at line 551 of file lock.h.

◆ ast_rwlock_destroy

#define ast_rwlock_destroy (   rwlock)    __ast_rwlock_destroy(__FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)

Definition at line 240 of file lock.h.

◆ ast_rwlock_init

#define ast_rwlock_init (   rwlock)    __ast_rwlock_init(1, __FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)

wrapper for rwlock with tracking enabled

Returns
0 on success, non zero for error
Since
1.6.1

Definition at line 231 of file lock.h.

◆ ast_rwlock_init_notracking

#define ast_rwlock_init_notracking (   rwlock)    __ast_rwlock_init(0, __FILE__, __LINE__, __PRETTY_FUNCTION__, #rwlock, rwlock)

wrapper for ast_rwlock_init with tracking disabled

Returns
0 on success, non zero for error
Since
1.6.1

Definition at line 238 of file lock.h.

◆ AST_RWLOCK_INIT_VALUE

#define AST_RWLOCK_INIT_VALUE   { __AST_RWLOCK_INIT_VALUE, NULL, {1, 0} }

Definition at line 105 of file lock.h.

◆ AST_RWLOCK_INIT_VALUE_NOTRACKING

#define AST_RWLOCK_INIT_VALUE_NOTRACKING   { __AST_RWLOCK_INIT_VALUE, NULL, {0, 0} }

Definition at line 106 of file lock.h.

◆ ast_rwlock_rdlock

#define ast_rwlock_rdlock (   a)    __ast_rwlock_rdlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a)

Definition at line 242 of file lock.h.

◆ ast_rwlock_timedrdlock

#define ast_rwlock_timedrdlock (   a,
  b 
)    __ast_rwlock_timedrdlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a, b)

Definition at line 246 of file lock.h.

◆ ast_rwlock_timedwrlock

#define ast_rwlock_timedwrlock (   a,
  b 
)    __ast_rwlock_timedwrlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a, b)

Definition at line 247 of file lock.h.

◆ ast_rwlock_tryrdlock

#define ast_rwlock_tryrdlock (   a)    __ast_rwlock_tryrdlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a)

Definition at line 244 of file lock.h.

◆ ast_rwlock_trywrlock

#define ast_rwlock_trywrlock (   a)    __ast_rwlock_trywrlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a)

Definition at line 245 of file lock.h.

◆ ast_rwlock_unlock

#define ast_rwlock_unlock (   a)    __ast_rwlock_unlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a)

Definition at line 241 of file lock.h.

◆ ast_rwlock_wrlock

#define ast_rwlock_wrlock (   a)    __ast_rwlock_wrlock(__FILE__, __LINE__, __PRETTY_FUNCTION__, a, #a)

Definition at line 243 of file lock.h.

◆ CHANNEL_DEADLOCK_AVOIDANCE

#define CHANNEL_DEADLOCK_AVOIDANCE (   chan)
Value:
usleep(1); \
ast_channel_lock(chan);
#define ast_channel_unlock(chan)
Definition channel.h:2984

Definition at line 481 of file lock.h.

◆ DEADLOCK_AVOIDANCE

#define DEADLOCK_AVOIDANCE (   lock)

Definition at line 486 of file lock.h.

487 { \
488 int __res; \
489 if (!(__res = ast_mutex_unlock(lock))) { \
490 usleep(1); \
491 ast_mutex_lock(lock); \
492 } else { \
493 ast_log(LOG_WARNING, "Failed to unlock mutex '%s' (%s). I will NOT try to relock. {{{ THIS IS A BUG. }}}\n", #lock, strerror(__res)); \
494 } \
495 } while (0)

◆ DLA_LOCK

#define DLA_LOCK (   lock)    ast_mutex_lock(lock)

Definition at line 499 of file lock.h.

◆ DLA_UNLOCK

#define DLA_UNLOCK (   lock)    ast_mutex_unlock(lock)

Definition at line 497 of file lock.h.

◆ gethostbyname

#define gethostbyname   __gethostbyname__is__not__reentrant__use__ast_gethostbyname__instead__

Definition at line 646 of file lock.h.

◆ pthread_cond_broadcast

#define pthread_cond_broadcast   use_ast_cond_broadcast_instead_of_pthread_cond_broadcast

Definition at line 640 of file lock.h.

◆ pthread_cond_destroy

#define pthread_cond_destroy   use_ast_cond_destroy_instead_of_pthread_cond_destroy

Definition at line 638 of file lock.h.

◆ pthread_cond_init

#define pthread_cond_init   use_ast_cond_init_instead_of_pthread_cond_init

Definition at line 637 of file lock.h.

◆ pthread_cond_signal

#define pthread_cond_signal   use_ast_cond_signal_instead_of_pthread_cond_signal

Definition at line 639 of file lock.h.

◆ pthread_cond_t

#define pthread_cond_t   use_ast_cond_t_instead_of_pthread_cond_t

Definition at line 630 of file lock.h.

◆ pthread_cond_timedwait

#define pthread_cond_timedwait   use_ast_cond_timedwait_instead_of_pthread_cond_timedwait

Definition at line 642 of file lock.h.

◆ pthread_cond_wait

#define pthread_cond_wait   use_ast_cond_wait_instead_of_pthread_cond_wait

Definition at line 641 of file lock.h.

◆ pthread_create

#define pthread_create   __use_ast_pthread_create_instead__

Definition at line 649 of file lock.h.

◆ pthread_mutex_destroy

#define pthread_mutex_destroy   use_ast_mutex_destroy_instead_of_pthread_mutex_destroy

Definition at line 636 of file lock.h.

◆ pthread_mutex_init

#define pthread_mutex_init   use_ast_mutex_init_instead_of_pthread_mutex_init

Definition at line 635 of file lock.h.

◆ PTHREAD_MUTEX_INIT_VALUE

#define PTHREAD_MUTEX_INIT_VALUE   PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP

Definition at line 83 of file lock.h.

◆ pthread_mutex_lock

#define pthread_mutex_lock   use_ast_mutex_lock_instead_of_pthread_mutex_lock

Definition at line 632 of file lock.h.

◆ pthread_mutex_t

#define pthread_mutex_t   use_ast_mutex_t_instead_of_pthread_mutex_t

Definition at line 629 of file lock.h.

◆ pthread_mutex_trylock

#define pthread_mutex_trylock   use_ast_mutex_trylock_instead_of_pthread_mutex_trylock

Definition at line 634 of file lock.h.

◆ pthread_mutex_unlock

#define pthread_mutex_unlock   use_ast_mutex_unlock_instead_of_pthread_mutex_unlock

Definition at line 633 of file lock.h.

◆ ROFFSET

#define ROFFSET   ((lt->reentrancy > 0) ? (lt->reentrancy-1) : 0)

Definition at line 249 of file lock.h.

◆ SCOPED_AO2LOCK

#define SCOPED_AO2LOCK (   varname,
  obj 
)    SCOPED_LOCK(varname, (obj), ao2_lock, ao2_unlock)

scoped lock specialization for ao2 mutexes.

Definition at line 611 of file lock.h.

◆ SCOPED_AO2RDLOCK

#define SCOPED_AO2RDLOCK (   varname,
  obj 
)    SCOPED_LOCK(varname, (obj), ao2_rdlock, ao2_unlock)

scoped lock specialization for ao2 read locks.

Definition at line 616 of file lock.h.

◆ SCOPED_AO2WRLOCK

#define SCOPED_AO2WRLOCK (   varname,
  obj 
)    SCOPED_LOCK(varname, (obj), ao2_wrlock, ao2_unlock)

scoped lock specialization for ao2 write locks.

Definition at line 621 of file lock.h.

◆ SCOPED_CHANNELLOCK

#define SCOPED_CHANNELLOCK (   varname,
  chan 
)    SCOPED_LOCK(varname, (chan), ast_channel_lock, ast_channel_unlock)

scoped lock specialization for channels.

Definition at line 626 of file lock.h.

◆ SCOPED_LOCK

#define SCOPED_LOCK (   varname,
  lock,
  lockfunc,
  unlockfunc 
)     RAII_VAR(typeof((lock)), varname, ({lockfunc((lock)); (lock); }), unlockfunc)

Scoped Locks.

Scoped locks provide a way to use RAII locks. In other words, declaration of a scoped lock will automatically define and lock the lock. When the lock goes out of scope, it will automatically be unlocked.

int some_function(struct ast_channel *chan)
{
if (!strcmp(ast_channel_name(chan, "foo")) {
return 0;
}
return -1;
}
const char * ast_channel_name(const struct ast_channel *chan)
#define ast_channel_lock(chan)
Definition channel.h:2983
#define SCOPED_LOCK(varname, lock, lockfunc, unlockfunc)
Scoped Locks.
Definition lock.h:590
Main Channel structure associated with a channel.

In the above example, neither return path requires explicit unlocking of the channel.

Note
Care should be taken when using SCOPED_LOCKS in conjunction with ao2 objects. ao2 objects should be unlocked before they are unreffed. Since SCOPED_LOCK runs once the variable goes out of scope, this can easily lead to situations where the variable gets unlocked after it is unreffed.
Parameters
varnameThe unique name to give to the scoped lock. You are not likely to reference this outside of the SCOPED_LOCK invocation.
lockThe variable to lock. This can be anything that can be passed to a locking or unlocking function.
lockfuncThe function to call to lock the lock
unlockfuncThe function to call to unlock the lock

Definition at line 590 of file lock.h.

591 {lockfunc((lock)); (lock); }), unlockfunc)

◆ SCOPED_MUTEX

#define SCOPED_MUTEX (   varname,
  lock 
)    SCOPED_LOCK(varname, (lock), ast_mutex_lock, ast_mutex_unlock)

scoped lock specialization for mutexes

Definition at line 596 of file lock.h.

◆ SCOPED_RDLOCK

#define SCOPED_RDLOCK (   varname,
  lock 
)    SCOPED_LOCK(varname, (lock), ast_rwlock_rdlock, ast_rwlock_unlock)

scoped lock specialization for read locks

Definition at line 601 of file lock.h.

◆ SCOPED_WRLOCK

#define SCOPED_WRLOCK (   varname,
  lock 
)    SCOPED_LOCK(varname, (lock), ast_rwlock_wrlock, ast_rwlock_unlock)

scoped lock specialization for write locks

Definition at line 606 of file lock.h.

Typedef Documentation

◆ ast_cond_t

Definition at line 185 of file lock.h.

◆ ast_mutex_t

typedef struct ast_mutex_info ast_mutex_t

Definition at line 181 of file lock.h.

◆ ast_rwlock_t

typedef struct ast_rwlock_info ast_rwlock_t

Definition at line 183 of file lock.h.

Function Documentation

◆ __ast_cond_broadcast()

int __ast_cond_broadcast ( const char *  filename,
int  lineno,
const char *  func,
const char *  cond_name,
ast_cond_t *  cond 
)

Definition at line 549 of file lock.c.

551{
553}
ast_cond_t cond
Definition app_sla.c:336
#define pthread_cond_broadcast
Definition lock.h:640

References cond, and pthread_cond_broadcast.

◆ __ast_cond_destroy()

int __ast_cond_destroy ( const char *  filename,
int  lineno,
const char *  func,
const char *  cond_name,
ast_cond_t *  cond 
)

Definition at line 555 of file lock.c.

557{
559}
#define pthread_cond_destroy
Definition lock.h:638

References cond, and pthread_cond_destroy.

◆ __ast_cond_init()

int __ast_cond_init ( const char *  filename,
int  lineno,
const char *  func,
const char *  cond_name,
ast_cond_t *  cond,
pthread_condattr_t *  cond_attr 
)

Definition at line 537 of file lock.c.

539{
540 return pthread_cond_init(cond, cond_attr);
541}
#define pthread_cond_init
Definition lock.h:637

References cond, and pthread_cond_init.

◆ __ast_cond_signal()

int __ast_cond_signal ( const char *  filename,
int  lineno,
const char *  func,
const char *  cond_name,
ast_cond_t *  cond 
)

Definition at line 543 of file lock.c.

545{
547}
#define pthread_cond_signal
Definition lock.h:639

References cond, and pthread_cond_signal.

◆ __ast_cond_timedwait()

int __ast_cond_timedwait ( const char *  filename,
int  lineno,
const char *  func,
const char *  cond_name,
const char *  mutex_name,
ast_cond_t *  cond,
ast_mutex_t *  t,
const struct timespec *  abstime 
)

Definition at line 649 of file lock.c.

652{
653 int res;
654
655#ifdef DEBUG_THREADS
656 struct ast_lock_track *lt = NULL;
657 struct ast_lock_track lt_orig;
658 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
659
660#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
661 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
662 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
663 filename, lineno, func, mutex_name);
664 DO_THREAD_CRASH;
665 return EINVAL;
666 }
667#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
668
669 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
670 if (lt) {
671 ast_reentrancy_lock(lt);
672 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
673 log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
674 filename, lineno, func, mutex_name);
675 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
676 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
677#ifdef HAVE_BKTR
678 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
679#endif
680 DO_THREAD_CRASH;
681 } else if (lt->reentrancy <= 0) {
682 log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
683 filename, lineno, func, mutex_name);
684 DO_THREAD_CRASH;
685 }
686
687 /* Waiting on a condition completely suspends a recursive mutex,
688 * even if it's been recursively locked multiple times. Make a
689 * copy of the lock tracking, and reset reentrancy to zero */
690 lt_orig = *lt;
691 lt->reentrancy = 0;
692 ast_reentrancy_unlock(lt);
693
694 ast_suspend_lock_info(t);
695 }
696#endif /* DEBUG_THREADS */
697
698 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
699
700#ifdef DEBUG_THREADS
701 if (res && (res != ETIMEDOUT)) {
702 log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
703 filename, lineno, func, strerror(res));
704 DO_THREAD_CRASH;
705 } else if (lt) {
706 restore_lock_tracking(lt, &lt_orig);
707 ast_restore_lock_info(t);
708 }
709#endif /* DEBUG_THREADS */
710
711 return res;
712}
#define ROFFSET
Definition lock.h:249
#define pthread_mutex_t
Definition lock.h:629
#define pthread_cond_timedwait
Definition lock.h:642
#define NULL
Definition resample.c:96
Lock tracking information.
Definition lock.h:118
int reentrancy
Definition lock.h:121
struct ast_bt backtrace[AST_MAX_REENTRANCY]
Definition lock.h:125
pthread_t thread_id[AST_MAX_REENTRANCY]
Definition lock.h:123
int lineno[AST_MAX_REENTRANCY]
Definition lock.h:120
const char * file[AST_MAX_REENTRANCY]
Definition lock.h:119
const char * func[AST_MAX_REENTRANCY]
Definition lock.h:122
pthread_mutex_t mutex
Definition lock.h:143

References ast_lock_track::backtrace, cond, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_cond_timedwait, pthread_mutex_t, ast_lock_track::reentrancy, ROFFSET, and ast_lock_track::thread_id.

◆ __ast_cond_wait()

int __ast_cond_wait ( const char *  filename,
int  lineno,
const char *  func,
const char *  cond_name,
const char *  mutex_name,
ast_cond_t *  cond,
ast_mutex_t *  t 
)

Definition at line 584 of file lock.c.

587{
588 int res;
589
590#ifdef DEBUG_THREADS
591 struct ast_lock_track *lt = NULL;
592 struct ast_lock_track lt_orig;
593 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
594
595#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
596 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
597 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
598 filename, lineno, func, mutex_name);
599 DO_THREAD_CRASH;
600 return EINVAL;
601 }
602#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
603
604 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
605 if (lt) {
606 ast_reentrancy_lock(lt);
607 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
608 log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
609 filename, lineno, func, mutex_name);
610 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
611 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
612#ifdef HAVE_BKTR
613 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
614#endif
615 DO_THREAD_CRASH;
616 } else if (lt->reentrancy <= 0) {
617 log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
618 filename, lineno, func, mutex_name);
619 DO_THREAD_CRASH;
620 }
621
622 /* Waiting on a condition completely suspends a recursive mutex,
623 * even if it's been recursively locked multiple times. Make a
624 * copy of the lock tracking, and reset reentrancy to zero */
625 lt_orig = *lt;
626 lt->reentrancy = 0;
627 ast_reentrancy_unlock(lt);
628
629 ast_suspend_lock_info(t);
630 }
631#endif /* DEBUG_THREADS */
632
633 res = pthread_cond_wait(cond, &t->mutex);
634
635#ifdef DEBUG_THREADS
636 if (res) {
637 log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
638 filename, lineno, func, strerror(res));
639 DO_THREAD_CRASH;
640 } else if (lt) {
641 restore_lock_tracking(lt, &lt_orig);
642 ast_restore_lock_info(t);
643 }
644#endif /* DEBUG_THREADS */
645
646 return res;
647}
#define pthread_cond_wait
Definition lock.h:641

References ast_lock_track::backtrace, cond, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_cond_wait, pthread_mutex_t, ast_lock_track::reentrancy, ROFFSET, and ast_lock_track::thread_id.

◆ __ast_pthread_mutex_destroy()

int __ast_pthread_mutex_destroy ( const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t *  t 
)

Definition at line 177 of file lock.c.

179{
180 int res;
181
182#ifdef DEBUG_THREADS
183 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
184 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
185
186#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
187 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
188 /* Don't try to uninitialize an uninitialized mutex
189 * This may have no effect on linux
190 * but it always generates a core on *BSD when
191 * linked with libpthread.
192 * This is not an error condition if the mutex is created on the fly.
193 */
194 log_mutex_error(canlog, "%s line %d (%s): NOTICE: mutex '%s' is uninitialized.\n",
195 filename, lineno, func, mutex_name);
196 DO_THREAD_CRASH;
197 res = EINVAL;
198 goto lt_cleanup;
199 }
200#endif
201
202 res = pthread_mutex_trylock(&t->mutex);
203 switch (res) {
204 case 0:
206 break;
207 case EINVAL:
208 log_mutex_error(canlog, "%s line %d (%s): Error: attempt to destroy invalid mutex '%s'.\n",
209 filename, lineno, func, mutex_name);
210 break;
211 case EBUSY:
212 log_mutex_error(canlog, "%s line %d (%s): Error: attempt to destroy locked mutex '%s'.\n",
213 filename, lineno, func, mutex_name);
214 if (lt) {
215 ast_reentrancy_lock(lt);
216 log_mutex_error(canlog, "%s line %d (%s): Error: '%s' was locked here.\n",
217 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
218#ifdef HAVE_BKTR
219 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
220#endif
221 ast_reentrancy_unlock(lt);
222 }
223 break;
224 }
225#endif /* DEBUG_THREADS */
226
227 res = pthread_mutex_destroy(&t->mutex);
228
229#ifdef DEBUG_THREADS
230 if (res) {
231 log_mutex_error(canlog, "%s line %d (%s): Error destroying mutex %s: %s\n",
232 filename, lineno, func, mutex_name, strerror(res));
233 }
234#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
235lt_cleanup:
236#endif
237 if (lt) {
238 ast_reentrancy_lock(lt);
239 lt->file[0] = filename;
240 lt->lineno[0] = lineno;
241 lt->func[0] = func;
242 lt->reentrancy = 0;
243 lt->thread_id[0] = 0;
244#ifdef HAVE_BKTR
245 memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
246#endif
247 ast_reentrancy_unlock(lt);
248 delete_reentrancy_cs(&t->track);
249 }
250#endif /* DEBUG_THREADS */
251
252 return res;
253}
#define pthread_mutex_trylock
Definition lock.h:634
#define pthread_mutex_unlock
Definition lock.h:633
#define pthread_mutex_destroy
Definition lock.h:636

References ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, pthread_mutex_destroy, pthread_mutex_t, pthread_mutex_trylock, pthread_mutex_unlock, ast_lock_track::reentrancy, ROFFSET, and ast_lock_track::thread_id.

◆ __ast_pthread_mutex_init()

int __ast_pthread_mutex_init ( int  tracking,
const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t *  t 
)

Definition at line 145 of file lock.c.

147{
148 int res;
149 pthread_mutexattr_t attr;
150
151#if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
152 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
153 if ((t->mutex) != ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
154 int canlog = tracking && strcmp(filename, "logger.c");
155
156 log_mutex_error(canlog, "%s line %d (%s): NOTICE: mutex '%s' is already initialized.\n",
157 filename, lineno, func, mutex_name);
158 DO_THREAD_CRASH;
159 return EBUSY;
160 }
161#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
162
163#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
164 t->track = NULL;
165 t->flags.tracking = tracking;
166 t->flags.setup = 0;
167#endif /* DEBUG_THREADS */
168
169 pthread_mutexattr_init(&attr);
170 pthread_mutexattr_settype(&attr, AST_MUTEX_KIND);
171 res = pthread_mutex_init(&t->mutex, &attr);
172 pthread_mutexattr_destroy(&attr);
173
174 return res;
175}
#define AST_MUTEX_KIND
Definition lock.h:84
#define pthread_mutex_init
Definition lock.h:635

References AST_MUTEX_KIND, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_mutex_init, and pthread_mutex_t.

◆ __ast_pthread_mutex_lock()

int __ast_pthread_mutex_lock ( const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t *  t 
)

Definition at line 255 of file lock.c.

257{
258 int res;
259
260#if defined(DETECT_DEADLOCKS) || defined(DEBUG_THREADS)
261 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
262#endif
263
264#ifdef DEBUG_THREADS
265 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
266 struct ast_bt *bt = NULL;
267
268 if (lt) {
269#ifdef HAVE_BKTR
270 struct ast_bt tmp;
271
272 /* The implementation of backtrace() may have its own locks.
273 * Capture the backtrace outside of the reentrancy lock to
274 * avoid deadlocks. See ASTERISK-22455. */
276
277 ast_reentrancy_lock(lt);
278 if (lt->reentrancy < AST_MAX_REENTRANCY) {
279 lt->backtrace[lt->reentrancy] = tmp;
280 bt = &lt->backtrace[lt->reentrancy];
281 }
282 ast_reentrancy_unlock(lt);
283#endif
284 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
285 }
286#endif /* DEBUG_THREADS */
287
288#if defined(DETECT_DEADLOCKS)
289 {
290 time_t seconds = time(NULL);
291 time_t wait_time, reported_wait = 0;
292 do {
293#ifdef HAVE_MTX_PROFILE
294 ast_mark(mtx_prof, 1);
295#endif
296 res = pthread_mutex_trylock(&t->mutex);
297#ifdef HAVE_MTX_PROFILE
298 ast_mark(mtx_prof, 0);
299#endif
300 if (res == EBUSY) {
301 wait_time = time(NULL) - seconds;
302 if (wait_time > reported_wait && (wait_time % 5) == 0) {
303 log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for mutex '%s'?\n",
304 filename, lineno, func, (int) wait_time, mutex_name);
305#ifdef DEBUG_THREADS
306 if (lt) {
307 ast_reentrancy_lock(lt);
308#ifdef HAVE_BKTR
309 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
310#endif
311 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
312 lt->file[ROFFSET], lt->lineno[ROFFSET],
313 lt->func[ROFFSET], mutex_name);
314#ifdef HAVE_BKTR
315 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
316#endif
317 ast_reentrancy_unlock(lt);
318 }
319#endif
320 reported_wait = wait_time;
321 if ((int) wait_time < 10) { /* Only emit an event when a deadlock starts, not every 5 seconds */
322 /*** DOCUMENTATION
323 <managerEvent language="en_US" name="DeadlockStart">
324 <managerEventInstance class="EVENT_FLAG_SYSTEM">
325 <since>
326 <version>16.29.0</version>
327 <version>18.15.0</version>
328 <version>19.7.0</version>
329 </since>
330 <synopsis>Raised when a probable deadlock has started.
331 Delivery of this event is attempted but not guaranteed,
332 and could fail for example if the manager itself is deadlocked.
333 </synopsis>
334 <syntax>
335 <parameter name="Mutex">
336 <para>The mutex involved in the deadlock.</para>
337 </parameter>
338 </syntax>
339 </managerEventInstance>
340 </managerEvent>
341 ***/
342 manager_event(EVENT_FLAG_SYSTEM, "DeadlockStart",
343 "Mutex: %s\r\n",
344 mutex_name);
345 }
346 }
347 usleep(200);
348 }
349 } while (res == EBUSY);
350 }
351#else /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
352#ifdef HAVE_MTX_PROFILE
353 ast_mark(mtx_prof, 1);
354 res = pthread_mutex_trylock(&t->mutex);
355 ast_mark(mtx_prof, 0);
356 if (res)
357#endif
358 res = pthread_mutex_lock(&t->mutex);
359#endif /* !DETECT_DEADLOCKS || !DEBUG_THREADS */
360
361#ifdef DEBUG_THREADS
362 if (lt && !res) {
363 ast_reentrancy_lock(lt);
364 if (lt->reentrancy < AST_MAX_REENTRANCY) {
365 lt->file[lt->reentrancy] = filename;
366 lt->lineno[lt->reentrancy] = lineno;
367 lt->func[lt->reentrancy] = func;
368 lt->thread_id[lt->reentrancy] = pthread_self();
369 lt->reentrancy++;
370 } else {
371 log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
372 filename, lineno, func, mutex_name);
373 }
374 ast_reentrancy_unlock(lt);
375 ast_mark_lock_acquired(t);
376 } else if (lt) {
377#ifdef HAVE_BKTR
378 if (lt->reentrancy) {
379 ast_reentrancy_lock(lt);
380 bt = &lt->backtrace[lt->reentrancy-1];
381 ast_reentrancy_unlock(lt);
382 } else {
383 bt = NULL;
384 }
385#endif
386 ast_remove_lock_info(t, bt);
387 }
388 if (res) {
389 log_mutex_error(canlog, "%s line %d (%s): Error obtaining mutex: %s\n",
390 filename, lineno, func, strerror(res));
391 DO_THREAD_CRASH;
392 }
393#endif /* DEBUG_THREADS */
394
395 return res;
396}
int64_t ast_mark(int, int start1_stop0)
Definition astman.c:103
#define ast_bt_get_addresses(bt)
Definition backtrace.h:38
@ AST_MUTEX
Definition check_expr.c:36
#define AST_MAX_REENTRANCY
Definition lock.h:108
#define pthread_mutex_lock
Definition lock.h:632
#define manager_event(category, event, contents,...)
External routines may send asterisk manager events this way.
Definition manager.h:255
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
A structure to hold backtrace information. This structure provides an easy means to store backtrace i...
Definition backtrace.h:50

References ast_bt_get_addresses, ast_mark(), AST_MAX_REENTRANCY, AST_MUTEX, ast_lock_track::backtrace, EVENT_FLAG_SYSTEM, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, manager_event, ast_mutex_info::mutex, NULL, pthread_mutex_lock, pthread_mutex_trylock, ast_lock_track::reentrancy, ROFFSET, and ast_lock_track::thread_id.

Referenced by __ao2_lock().

◆ __ast_pthread_mutex_trylock()

int __ast_pthread_mutex_trylock ( const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t *  t 
)

Definition at line 398 of file lock.c.

400{
401 int res;
402
403#ifdef DEBUG_THREADS
404 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
405 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
406 struct ast_bt *bt = NULL;
407
408 if (lt) {
409#ifdef HAVE_BKTR
410 struct ast_bt tmp;
411
412 /* The implementation of backtrace() may have its own locks.
413 * Capture the backtrace outside of the reentrancy lock to
414 * avoid deadlocks. See ASTERISK-22455. */
416
417 ast_reentrancy_lock(lt);
418 if (lt->reentrancy < AST_MAX_REENTRANCY) {
419 lt->backtrace[lt->reentrancy] = tmp;
420 bt = &lt->backtrace[lt->reentrancy];
421 }
422 ast_reentrancy_unlock(lt);
423#endif
424 ast_store_lock_info(AST_MUTEX, filename, lineno, func, mutex_name, t, bt);
425 }
426#endif /* DEBUG_THREADS */
427
428 res = pthread_mutex_trylock(&t->mutex);
429
430#ifdef DEBUG_THREADS
431 if (lt && !res) {
432 ast_reentrancy_lock(lt);
433 if (lt->reentrancy < AST_MAX_REENTRANCY) {
434 lt->file[lt->reentrancy] = filename;
435 lt->lineno[lt->reentrancy] = lineno;
436 lt->func[lt->reentrancy] = func;
437 lt->thread_id[lt->reentrancy] = pthread_self();
438 lt->reentrancy++;
439 } else {
440 log_mutex_error(canlog, "%s line %d (%s): '%s' really deep reentrancy!\n",
441 filename, lineno, func, mutex_name);
442 }
443 ast_reentrancy_unlock(lt);
444 ast_mark_lock_acquired(t);
445 } else if (lt) {
447 }
448#endif /* DEBUG_THREADS */
449
450 return res;
451}
void ast_mark_lock_failed(void *lock_addr)
Definition extconf.c:2309

References ast_bt_get_addresses, ast_mark_lock_failed(), AST_MAX_REENTRANCY, AST_MUTEX, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_mutex_info::mutex, NULL, pthread_mutex_trylock, ast_lock_track::reentrancy, and ast_lock_track::thread_id.

Referenced by __ao2_trylock().

◆ __ast_pthread_mutex_unlock()

int __ast_pthread_mutex_unlock ( const char *  filename,
int  lineno,
const char *  func,
const char *  mutex_name,
ast_mutex_t *  t 
)

Definition at line 453 of file lock.c.

455{
456 int res;
457
458#ifdef DEBUG_THREADS
459 struct ast_lock_track *lt = NULL;
460 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
461 struct ast_bt *bt = NULL;
462
463#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
464 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
465 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
466 filename, lineno, func, mutex_name);
467 DO_THREAD_CRASH;
468 return EINVAL;
469 }
470#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
471
472 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
473 if (lt) {
474 ast_reentrancy_lock(lt);
475 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
476 log_mutex_error(canlog, "%s line %d (%s): attempted unlock mutex '%s' without owning it!\n",
477 filename, lineno, func, mutex_name);
478 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
479 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
480#ifdef HAVE_BKTR
481 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
482#endif
483 DO_THREAD_CRASH;
484 }
485
486 if (--lt->reentrancy < 0) {
487 log_mutex_error(canlog, "%s line %d (%s): mutex '%s' freed more times than we've locked!\n",
488 filename, lineno, func, mutex_name);
489 lt->reentrancy = 0;
490 }
491
492 if (lt->reentrancy < AST_MAX_REENTRANCY) {
493 lt->file[lt->reentrancy] = NULL;
494 lt->lineno[lt->reentrancy] = 0;
495 lt->func[lt->reentrancy] = NULL;
496 lt->thread_id[lt->reentrancy] = 0;
497 }
498
499#ifdef HAVE_BKTR
500 if (lt->reentrancy) {
501 bt = &lt->backtrace[lt->reentrancy - 1];
502 }
503#endif
504 ast_reentrancy_unlock(lt);
505
506 ast_remove_lock_info(t, bt);
507 }
508#endif /* DEBUG_THREADS */
509
510 res = pthread_mutex_unlock(&t->mutex);
511
512#ifndef DEBUG_THREADS
513 /*
514 * An unlock failure (e.g. EPERM) means the mutex may stay locked.
515 * The strcmp only runs when the unlock failed, so there is no
516 * performance impact on normal unlocks. It avoids recursion if the
517 * logger's own mutex fails to unlock.
518 */
519 if (res && strcmp(filename, "logger.c")) {
520 ast_log(LOG_ERROR, "Failed to unlock mutex '%s' at %s:%d (%s): %s\n",
521 mutex_name, filename, lineno, func, strerror(res));
522 }
523#endif
524
525#ifdef DEBUG_THREADS
526 if (res) {
527 log_mutex_error(canlog, "%s line %d (%s): Error releasing mutex: %s\n",
528 filename, lineno, func, strerror(res));
529 DO_THREAD_CRASH;
530 }
531#endif /* DEBUG_THREADS */
532
533 return res;
534}
#define ast_log
Definition astobj2.c:42
#define LOG_ERROR

References ast_log, AST_MAX_REENTRANCY, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, LOG_ERROR, ast_mutex_info::mutex, NULL, pthread_mutex_t, pthread_mutex_unlock, ast_lock_track::reentrancy, ROFFSET, and ast_lock_track::thread_id.

Referenced by __ao2_unlock().

◆ __ast_rwlock_destroy()

int __ast_rwlock_destroy ( const char *  filename,
int  lineno,
const char *  func,
const char *  rwlock_name,
ast_rwlock_t *  t 
)

Definition at line 748 of file lock.c.

749{
750 int res;
751
752#ifdef DEBUG_THREADS
753 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
754 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
755
756#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
757 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
758 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
759 filename, lineno, func, rwlock_name);
760 DO_THREAD_CRASH;
761 res = EINVAL;
762 goto lt_cleanup;
763 }
764#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
765#endif /* DEBUG_THREADS */
766
767 res = pthread_rwlock_destroy(&t->lock);
768
769#ifdef DEBUG_THREADS
770 if (res) {
771 log_mutex_error(canlog, "%s line %d (%s): Error destroying rwlock %s: %s\n",
772 filename, lineno, func, rwlock_name, strerror(res));
773 }
774#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
775lt_cleanup:
776#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
777 if (lt) {
778 ast_reentrancy_lock(lt);
779 lt->file[0] = filename;
780 lt->lineno[0] = lineno;
781 lt->func[0] = func;
782 lt->reentrancy = 0;
783 lt->thread_id[0] = 0;
784#ifdef HAVE_BKTR
785 memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
786#endif
787 ast_reentrancy_unlock(lt);
788 delete_reentrancy_cs(&t->track);
789 }
790#endif /* DEBUG_THREADS */
791
792 return res;
793}
#define __AST_RWLOCK_INIT_VALUE
Definition lock.h:91
pthread_rwlock_t lock
Definition lock.h:165

References __AST_RWLOCK_INIT_VALUE, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, ast_lock_track::reentrancy, and ast_lock_track::thread_id.

◆ __ast_rwlock_init()

int __ast_rwlock_init ( int  tracking,
const char *  filename,
int  lineno,
const char *  func,
const char *  rwlock_name,
ast_rwlock_t *  t 
)

Definition at line 714 of file lock.c.

716{
717 int res;
718 pthread_rwlockattr_t attr;
719
720#if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
721 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
722 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
723 int canlog = tracking && strcmp(filename, "logger.c");
724
725 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
726 filename, lineno, func, rwlock_name);
727 DO_THREAD_CRASH;
728 return EBUSY;
729 }
730#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
731
732#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
733 t->track = NULL;
734 t->flags.tracking = tracking;
735 t->flags.setup = 0;
736#endif /* DEBUG_THREADS */
737
738 pthread_rwlockattr_init(&attr);
739#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
740 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
741#endif
742 res = pthread_rwlock_init(&t->lock, &attr);
743 pthread_rwlockattr_destroy(&attr);
744
745 return res;
746}

References __AST_RWLOCK_INIT_VALUE, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, and NULL.

◆ __ast_rwlock_rdlock()

int __ast_rwlock_rdlock ( const char *  filename,
int  lineno,
const char *  func,
ast_rwlock_t *  t,
const char *  name 
)

Definition at line 866 of file lock.c.

868{
869 int res;
870
871#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
872 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
873#endif
874
875#ifdef DEBUG_THREADS
876 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
877 struct ast_bt *bt = NULL;
878
879 if (lt) {
880#ifdef HAVE_BKTR
881 struct ast_bt tmp;
882
883 /* The implementation of backtrace() may have its own locks.
884 * Capture the backtrace outside of the reentrancy lock to
885 * avoid deadlocks. See ASTERISK-22455. */
887
888 ast_reentrancy_lock(lt);
889 if (lt->reentrancy < AST_MAX_REENTRANCY) {
890 lt->backtrace[lt->reentrancy] = tmp;
891 bt = &lt->backtrace[lt->reentrancy];
892 }
893 ast_reentrancy_unlock(lt);
894#endif
895 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
896 }
897#endif /* DEBUG_THREADS */
898
899#if defined(DETECT_DEADLOCKS)
900 {
901 time_t seconds = time(NULL);
902 time_t wait_time, reported_wait = 0;
903 do {
904 res = pthread_rwlock_tryrdlock(&t->lock);
905 if (res == EBUSY) {
906 wait_time = time(NULL) - seconds;
907 if (wait_time > reported_wait && (wait_time % 5) == 0) {
908 log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for readlock '%s'?\n",
909 filename, line, func, (int)wait_time, name);
910#ifdef DEBUG_THREADS
911 if (lt) {
912 ast_reentrancy_lock(lt);
913#ifdef HAVE_BKTR
914 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
915#endif
916 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
917 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
918 lt->func[lt->reentrancy-1], name);
919#ifdef HAVE_BKTR
920 __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
921#endif
922 ast_reentrancy_unlock(lt);
923 }
924#endif
925 reported_wait = wait_time;
926 }
927 usleep(200);
928 }
929 } while (res == EBUSY);
930 }
931#else /* !DETECT_DEADLOCKS */
932 res = pthread_rwlock_rdlock(&t->lock);
933#endif /* !DETECT_DEADLOCKS */
934
935#ifdef DEBUG_THREADS
936 if (!res && lt) {
937 ast_reentrancy_lock(lt);
938 if (lt->reentrancy < AST_MAX_REENTRANCY) {
939 lt->file[lt->reentrancy] = filename;
940 lt->lineno[lt->reentrancy] = line;
941 lt->func[lt->reentrancy] = func;
942 lt->thread_id[lt->reentrancy] = pthread_self();
943 lt->reentrancy++;
944 }
945 ast_reentrancy_unlock(lt);
946 ast_mark_lock_acquired(t);
947 } else if (lt) {
948#ifdef HAVE_BKTR
949 if (lt->reentrancy) {
950 ast_reentrancy_lock(lt);
951 bt = &lt->backtrace[lt->reentrancy-1];
952 ast_reentrancy_unlock(lt);
953 } else {
954 bt = NULL;
955 }
956#endif
957 ast_remove_lock_info(t, bt);
958 }
959
960 if (res) {
961 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
962 filename, line, func, strerror(res));
963 DO_THREAD_CRASH;
964 }
965#endif /* DEBUG_THREADS */
966
967 return res;
968}
@ AST_RDLOCK
Definition check_expr.c:37
static const char name[]
Definition format_mp3.c:68

References ast_bt_get_addresses, AST_MAX_REENTRANCY, AST_RDLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, and ast_lock_track::thread_id.

Referenced by __ao2_global_obj_ref(), __ao2_lock(), and __ast_heap_rdlock().

◆ __ast_rwlock_timedrdlock()

int __ast_rwlock_timedrdlock ( const char *  filename,
int  lineno,
const char *  func,
ast_rwlock_t *  t,
const char *  name,
const struct timespec *  abs_timeout 
)

Definition at line 1073 of file lock.c.

1075{
1076 int res;
1077
1078#ifdef DEBUG_THREADS
1079 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1080 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
1081 struct ast_bt *bt = NULL;
1082
1083 if (lt) {
1084#ifdef HAVE_BKTR
1085 struct ast_bt tmp;
1086
1087 /* The implementation of backtrace() may have its own locks.
1088 * Capture the backtrace outside of the reentrancy lock to
1089 * avoid deadlocks. See ASTERISK-22455. */
1091
1092 ast_reentrancy_lock(lt);
1093 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1094 lt->backtrace[lt->reentrancy] = tmp;
1095 bt = &lt->backtrace[lt->reentrancy];
1096 }
1097 ast_reentrancy_unlock(lt);
1098#endif
1099 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1100 }
1101#endif /* DEBUG_THREADS */
1102
1103#ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1104 res = pthread_rwlock_timedrdlock(&t->lock, abs_timeout);
1105#else
1106 do {
1107 struct timeval _now;
1108 for (;;) {
1109 if (!(res = pthread_rwlock_tryrdlock(&t->lock))) {
1110 break;
1111 }
1112 _now = ast_tvnow();
1113 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1114 break;
1115 }
1116 usleep(1);
1117 }
1118 } while (0);
1119#endif
1120
1121#ifdef DEBUG_THREADS
1122 if (!res && lt) {
1123 ast_reentrancy_lock(lt);
1124 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1125 lt->file[lt->reentrancy] = filename;
1126 lt->lineno[lt->reentrancy] = line;
1127 lt->func[lt->reentrancy] = func;
1128 lt->thread_id[lt->reentrancy] = pthread_self();
1129 lt->reentrancy++;
1130 }
1131 ast_reentrancy_unlock(lt);
1132 ast_mark_lock_acquired(t);
1133 } else if (lt) {
1134#ifdef HAVE_BKTR
1135 if (lt->reentrancy) {
1136 ast_reentrancy_lock(lt);
1137 bt = &lt->backtrace[lt->reentrancy-1];
1138 ast_reentrancy_unlock(lt);
1139 } else {
1140 bt = NULL;
1141 }
1142#endif
1143 ast_remove_lock_info(t, bt);
1144 }
1145 if (res) {
1146 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
1147 filename, line, func, strerror(res));
1148 DO_THREAD_CRASH;
1149 }
1150#endif /* DEBUG_THREADS */
1151
1152 return res;
1153}
@ AST_WRLOCK
Definition check_expr.c:38
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159

References ast_bt_get_addresses, AST_MAX_REENTRANCY, ast_tvnow(), AST_WRLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, and ast_lock_track::thread_id.

◆ __ast_rwlock_timedwrlock()

int __ast_rwlock_timedwrlock ( const char *  filename,
int  lineno,
const char *  func,
ast_rwlock_t *  t,
const char *  name,
const struct timespec *  abs_timeout 
)

Definition at line 1155 of file lock.c.

1157{
1158 int res;
1159
1160#ifdef DEBUG_THREADS
1161 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1162 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
1163 struct ast_bt *bt = NULL;
1164
1165 if (lt) {
1166#ifdef HAVE_BKTR
1167 struct ast_bt tmp;
1168
1169 /* The implementation of backtrace() may have its own locks.
1170 * Capture the backtrace outside of the reentrancy lock to
1171 * avoid deadlocks. See ASTERISK-22455. */
1173
1174 ast_reentrancy_lock(lt);
1175 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1176 lt->backtrace[lt->reentrancy] = tmp;
1177 bt = &lt->backtrace[lt->reentrancy];
1178 }
1179 ast_reentrancy_unlock(lt);
1180#endif
1181 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1182 }
1183#endif /* DEBUG_THREADS */
1184
1185#ifdef HAVE_PTHREAD_RWLOCK_TIMEDWRLOCK
1186 res = pthread_rwlock_timedwrlock(&t->lock, abs_timeout);
1187#else
1188 do {
1189 struct timeval _now;
1190 for (;;) {
1191 if (!(res = pthread_rwlock_trywrlock(&t->lock))) {
1192 break;
1193 }
1194 _now = ast_tvnow();
1195 if (_now.tv_sec > abs_timeout->tv_sec || (_now.tv_sec == abs_timeout->tv_sec && _now.tv_usec * 1000 > abs_timeout->tv_nsec)) {
1196 break;
1197 }
1198 usleep(1);
1199 }
1200 } while (0);
1201#endif
1202
1203#ifdef DEBUG_THREADS
1204 if (!res && lt) {
1205 ast_reentrancy_lock(lt);
1206 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1207 lt->file[lt->reentrancy] = filename;
1208 lt->lineno[lt->reentrancy] = line;
1209 lt->func[lt->reentrancy] = func;
1210 lt->thread_id[lt->reentrancy] = pthread_self();
1211 lt->reentrancy++;
1212 }
1213 ast_reentrancy_unlock(lt);
1214 ast_mark_lock_acquired(t);
1215 } else if (lt) {
1216#ifdef HAVE_BKTR
1217 if (lt->reentrancy) {
1218 ast_reentrancy_lock(lt);
1219 bt = &lt->backtrace[lt->reentrancy-1];
1220 ast_reentrancy_unlock(lt);
1221 } else {
1222 bt = NULL;
1223 }
1224#endif
1225 ast_remove_lock_info(t, bt);
1226 }
1227 if (res) {
1228 log_mutex_error(canlog, "%s line %d (%s): Error obtaining read lock: %s\n",
1229 filename, line, func, strerror(res));
1230 DO_THREAD_CRASH;
1231 }
1232#endif /* DEBUG_THREADS */
1233
1234 return res;
1235}

References ast_bt_get_addresses, AST_MAX_REENTRANCY, ast_tvnow(), AST_WRLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, and ast_lock_track::thread_id.

◆ __ast_rwlock_tryrdlock()

int __ast_rwlock_tryrdlock ( const char *  filename,
int  lineno,
const char *  func,
ast_rwlock_t *  t,
const char *  name 
)

Definition at line 1237 of file lock.c.

1238{
1239 int res;
1240
1241#ifdef DEBUG_THREADS
1242 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1243 struct ast_bt *bt = NULL;
1244
1245 if (lt) {
1246#ifdef HAVE_BKTR
1247 struct ast_bt tmp;
1248
1249 /* The implementation of backtrace() may have its own locks.
1250 * Capture the backtrace outside of the reentrancy lock to
1251 * avoid deadlocks. See ASTERISK-22455. */
1253
1254 ast_reentrancy_lock(lt);
1255 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1256 lt->backtrace[lt->reentrancy] = tmp;
1257 bt = &lt->backtrace[lt->reentrancy];
1258 }
1259 ast_reentrancy_unlock(lt);
1260#endif
1261 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1262 }
1263#endif /* DEBUG_THREADS */
1264
1265 res = pthread_rwlock_tryrdlock(&t->lock);
1266
1267#ifdef DEBUG_THREADS
1268 if (!res && lt) {
1269 ast_reentrancy_lock(lt);
1270 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1271 lt->file[lt->reentrancy] = filename;
1272 lt->lineno[lt->reentrancy] = line;
1273 lt->func[lt->reentrancy] = func;
1274 lt->thread_id[lt->reentrancy] = pthread_self();
1275 lt->reentrancy++;
1276 }
1277 ast_reentrancy_unlock(lt);
1278 ast_mark_lock_acquired(t);
1279 } else if (lt) {
1281 }
1282#endif /* DEBUG_THREADS */
1283
1284 return res;
1285}

References ast_bt_get_addresses, ast_mark_lock_failed(), AST_MAX_REENTRANCY, AST_RDLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, and ast_lock_track::thread_id.

Referenced by __ao2_trylock().

◆ __ast_rwlock_trywrlock()

int __ast_rwlock_trywrlock ( const char *  filename,
int  lineno,
const char *  func,
ast_rwlock_t *  t,
const char *  name 
)

Definition at line 1287 of file lock.c.

1288{
1289 int res;
1290
1291#ifdef DEBUG_THREADS
1292 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1293 struct ast_bt *bt = NULL;
1294
1295 if (lt) {
1296#ifdef HAVE_BKTR
1297 struct ast_bt tmp;
1298
1299 /* The implementation of backtrace() may have its own locks.
1300 * Capture the backtrace outside of the reentrancy lock to
1301 * avoid deadlocks. See ASTERISK-22455. */
1303
1304 ast_reentrancy_lock(lt);
1305 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1306 lt->backtrace[lt->reentrancy] = tmp;
1307 bt = &lt->backtrace[lt->reentrancy];
1308 }
1309 ast_reentrancy_unlock(lt);
1310#endif
1311 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1312 }
1313#endif /* DEBUG_THREADS */
1314
1315 res = pthread_rwlock_trywrlock(&t->lock);
1316
1317#ifdef DEBUG_THREADS
1318 if (!res && lt) {
1319 ast_reentrancy_lock(lt);
1320 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1321 lt->file[lt->reentrancy] = filename;
1322 lt->lineno[lt->reentrancy] = line;
1323 lt->func[lt->reentrancy] = func;
1324 lt->thread_id[lt->reentrancy] = pthread_self();
1325 lt->reentrancy++;
1326 }
1327 ast_reentrancy_unlock(lt);
1328 ast_mark_lock_acquired(t);
1329 } else if (lt) {
1331 }
1332#endif /* DEBUG_THREADS */
1333
1334 return res;
1335}

References ast_bt_get_addresses, ast_mark_lock_failed(), AST_MAX_REENTRANCY, AST_WRLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, and ast_lock_track::thread_id.

Referenced by __ao2_trylock().

◆ __ast_rwlock_unlock()

int __ast_rwlock_unlock ( const char *  filename,
int  lineno,
const char *  func,
ast_rwlock_t *  t,
const char *  name 
)

Definition at line 795 of file lock.c.

796{
797 int res;
798
799#ifdef DEBUG_THREADS
800 struct ast_lock_track *lt = NULL;
801 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
802 struct ast_bt *bt = NULL;
803 int lock_found = 0;
804
805#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
806 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
807 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
808 filename, line, func, name);
809 DO_THREAD_CRASH;
810 return EINVAL;
811 }
812#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
813
814 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
815 if (lt) {
816 ast_reentrancy_lock(lt);
817 if (lt->reentrancy) {
818 int i;
819 pthread_t self = pthread_self();
820 for (i = lt->reentrancy - 1; i >= 0; --i) {
821 if (lt->thread_id[i] == self) {
822 lock_found = 1;
823 if (i != lt->reentrancy - 1) {
824 lt->file[i] = lt->file[lt->reentrancy - 1];
825 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
826 lt->func[i] = lt->func[lt->reentrancy - 1];
827 lt->thread_id[i] = lt->thread_id[lt->reentrancy - 1];
828 }
829#ifdef HAVE_BKTR
830 bt = &lt->backtrace[i];
831#endif
832 lt->file[lt->reentrancy - 1] = NULL;
833 lt->lineno[lt->reentrancy - 1] = 0;
834 lt->func[lt->reentrancy - 1] = NULL;
836 break;
837 }
838 }
839 }
840
841 if (lock_found && --lt->reentrancy < 0) {
842 log_mutex_error(canlog, "%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
843 filename, line, func, name);
844 lt->reentrancy = 0;
845 }
846
847 ast_reentrancy_unlock(lt);
848
849 ast_remove_lock_info(t, bt);
850 }
851#endif /* DEBUG_THREADS */
852
853 res = pthread_rwlock_unlock(&t->lock);
854
855#ifdef DEBUG_THREADS
856 if (res) {
857 log_mutex_error(canlog, "%s line %d (%s): Error releasing rwlock: %s\n",
858 filename, line, func, strerror(res));
859 DO_THREAD_CRASH;
860 }
861#endif /* DEBUG_THREADS */
862
863 return res;
864}
#define AST_PTHREADT_NULL
Definition lock.h:73

References __AST_RWLOCK_INIT_VALUE, AST_PTHREADT_NULL, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, and ast_lock_track::thread_id.

Referenced by __ao2_global_obj_ref(), __ao2_global_obj_replace(), __ao2_unlock(), and __ast_heap_unlock().

◆ __ast_rwlock_wrlock()

int __ast_rwlock_wrlock ( const char *  filename,
int  lineno,
const char *  func,
ast_rwlock_t *  t,
const char *  name 
)

Definition at line 970 of file lock.c.

972{
973 int res;
974
975#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
976 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
977#endif
978
979#ifdef DEBUG_THREADS
980 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
981 struct ast_bt *bt = NULL;
982
983 if (lt) {
984#ifdef HAVE_BKTR
985 struct ast_bt tmp;
986
987 /* The implementation of backtrace() may have its own locks.
988 * Capture the backtrace outside of the reentrancy lock to
989 * avoid deadlocks. See ASTERISK-22455. */
991
992 ast_reentrancy_lock(lt);
993 if (lt->reentrancy < AST_MAX_REENTRANCY) {
994 lt->backtrace[lt->reentrancy] = tmp;
995 bt = &lt->backtrace[lt->reentrancy];
996 }
997 ast_reentrancy_unlock(lt);
998#endif
999 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1000 }
1001#endif /* DEBUG_THREADS */
1002
1003#ifdef DETECT_DEADLOCKS
1004 {
1005 time_t seconds = time(NULL);
1006 time_t wait_time, reported_wait = 0;
1007 do {
1008 res = pthread_rwlock_trywrlock(&t->lock);
1009 if (res == EBUSY) {
1010 wait_time = time(NULL) - seconds;
1011 if (wait_time > reported_wait && (wait_time % 5) == 0) {
1012 log_mutex_error(canlog, "%s line %d (%s): Deadlock? waited %d sec for writelock '%s'?\n",
1013 filename, line, func, (int)wait_time, name);
1014#ifdef DEBUG_THREADS
1015 if (lt) {
1016 ast_reentrancy_lock(lt);
1017#ifdef HAVE_BKTR
1018 __dump_backtrace(&lt->backtrace[lt->reentrancy], canlog);
1019#endif
1020 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
1021 lt->file[lt->reentrancy-1], lt->lineno[lt->reentrancy-1],
1022 lt->func[lt->reentrancy-1], name);
1023#ifdef HAVE_BKTR
1024 __dump_backtrace(&lt->backtrace[lt->reentrancy-1], canlog);
1025#endif
1026 ast_reentrancy_unlock(lt);
1027 }
1028#endif
1029 reported_wait = wait_time;
1030 }
1031 usleep(200);
1032 }
1033 } while (res == EBUSY);
1034 }
1035#else /* !DETECT_DEADLOCKS */
1036 res = pthread_rwlock_wrlock(&t->lock);
1037#endif /* !DETECT_DEADLOCKS */
1038
1039#ifdef DEBUG_THREADS
1040 if (!res && lt) {
1041 ast_reentrancy_lock(lt);
1042 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1043 lt->file[lt->reentrancy] = filename;
1044 lt->lineno[lt->reentrancy] = line;
1045 lt->func[lt->reentrancy] = func;
1046 lt->thread_id[lt->reentrancy] = pthread_self();
1047 lt->reentrancy++;
1048 }
1049 ast_reentrancy_unlock(lt);
1050 ast_mark_lock_acquired(t);
1051 } else if (lt) {
1052#ifdef HAVE_BKTR
1053 if (lt->reentrancy) {
1054 ast_reentrancy_lock(lt);
1055 bt = &lt->backtrace[lt->reentrancy-1];
1056 ast_reentrancy_unlock(lt);
1057 } else {
1058 bt = NULL;
1059 }
1060#endif
1061 ast_remove_lock_info(t, bt);
1062 }
1063 if (res) {
1064 log_mutex_error(canlog, "%s line %d (%s): Error obtaining write lock: %s\n",
1065 filename, line, func, strerror(res));
1066 DO_THREAD_CRASH;
1067 }
1068#endif /* DEBUG_THREADS */
1069
1070 return res;
1071}

References ast_bt_get_addresses, AST_MAX_REENTRANCY, AST_WRLOCK, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, ast_rwlock_info::lock, name, NULL, ast_lock_track::reentrancy, and ast_lock_track::thread_id.

Referenced by __ao2_global_obj_replace(), __ao2_lock(), and __ast_heap_wrlock().

◆ ast_atomic_dec_and_test()

int ast_atomic_dec_and_test ( volatile int *  p)
inline

decrement *p by 1 and return true if the variable has reached 0.

Useful e.g. to check if a refcount has reached 0.

Definition at line 774 of file lock.h.

Referenced by dispose_conf(), iax2_process_thread_cleanup(), run_station(), and sla_station_exec().

◆ ast_atomic_fetchadd_int()

int ast_atomic_fetchadd_int ( volatile int *  p,
int  v 
)
inline

Atomically add v to *p and return the previous value of *p.

This can be used to handle reference counts, and the return value can be used to generate unique identifiers.

Definition at line 764 of file lock.h.

Referenced by __ao2_link(), __ao2_lock(), __ao2_ref(), __ao2_trylock(), __ao2_unlock(), __ast_channel_alloc_ap(), __ast_channel_internal_alloc_with_initializers(), __ast_module_ref(), __ast_module_unref(), __ast_module_user_add(), __ast_module_user_hangup_all(), __ast_module_user_remove(), __container_unlink_node_debug(), __manager_event_sessions_va(), acf_odbc_read(), acl_change_stasis_cb(), action_login(), admin_exec(), ao2_container_count(), ast_bridge_interval_hook(), ast_channel_destructor(), ast_channel_internal_setup_topics(), ast_cli_command_full(), ast_create_callid(), ast_odbc_execute_sql(), ast_odbc_prepare(), ast_odbc_prepare_and_execute(), ast_odbc_smart_execute(), ast_sip_schedule_task(), ast_taskprocessor_seq_num(), AST_TEST_DEFINE(), AST_TEST_DEFINE(), ast_undestroyed_channels(), ast_unreal_new_channels(), authenticate_verify(), bridge_channel_handle_interval(), bridge_channel_queue_action_data_sync(), build_conf(), cc_device_monitor_init(), cc_extension_monitor_init(), cc_interfaces_datastore_init(), cdr_object_alloc(), chan_pjsip_new(), container_destruct(), dahdi_destroy(), dahdi_request(), dahdi_translate(), destroy_session(), dial_append_common(), dispatch_message(), dns_query_set_callback(), dundi_query_read(), efficiency_task(), efficiency_task(), enum_query_read(), fax_session_new(), fax_session_release(), fax_session_reserve(), find_idle_thread(), find_load_queue_rt_friendly(), find_session(), find_transcoders(), generate_msg_id(), generic_fax_exec(), hash_ao2_container_init(), hash_test_grow(), hash_test_grow(), hash_test_lookup(), hash_test_lookup(), hook_read(), ht_delete(), ht_new(), httpd_helper_thread(), iax2_destroy_helper(), iax2_process_thread(), iax_frame_free(), iax_frame_new(), inprocess_count(), internal_ao2_alloc(), internal_stasis_subscribe(), pjsip_history_entry_alloc(), publish_msg(), pubsub_on_rx_publish_request(), rb_ao2_container_init(), rec_request(), receivefax_exec(), reload_single_queue(), run_station(), sendfax_exec(), serializer_efficiency_task(), serializer_efficiency_task(), session_do(), sip_create_publication(), sla_add_trunk_to_station(), sla_handle_hold_event(), sla_station_exec(), smdi_msg_retrieve_read(), spandsp_fax_switch_to_t38(), stasis_app_control_snoop(), stasis_caching_topic_create(), stasis_cp_all_create(), stasis_message_type_create(), transport_create(), try_merge_optimize_out(), try_swap_optimize_out(), update_stats(), and worker_thread_alloc().