Asterisk - The Open Source Telephony Project GIT-master-27fb039
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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:2983

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:2982
#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 536 of file lock.c.

538{
540}
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 542 of file lock.c.

544{
546}
#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 524 of file lock.c.

526{
527 return pthread_cond_init(cond, cond_attr);
528}
#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 530 of file lock.c.

532{
534}
#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 636 of file lock.c.

639{
640 int res;
641
642#ifdef DEBUG_THREADS
643 struct ast_lock_track *lt = NULL;
644 struct ast_lock_track lt_orig;
645 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
646
647#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
648 if ((t->mutex) == ((pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER)) {
649 log_mutex_error(canlog, "%s line %d (%s): Error: mutex '%s' is uninitialized.\n",
650 filename, lineno, func, mutex_name);
651 DO_THREAD_CRASH;
652 return EINVAL;
653 }
654#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
655
656 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
657 if (lt) {
658 ast_reentrancy_lock(lt);
659 if (lt->reentrancy && (lt->thread_id[ROFFSET] != pthread_self())) {
660 log_mutex_error(canlog, "%s line %d (%s): attempted wait using mutex '%s' without owning it!\n",
661 filename, lineno, func, mutex_name);
662 log_mutex_error(canlog, "%s line %d (%s): '%s' was locked here.\n",
663 lt->file[ROFFSET], lt->lineno[ROFFSET], lt->func[ROFFSET], mutex_name);
664#ifdef HAVE_BKTR
665 __dump_backtrace(&lt->backtrace[ROFFSET], canlog);
666#endif
667 DO_THREAD_CRASH;
668 } else if (lt->reentrancy <= 0) {
669 log_mutex_error(canlog, "%s line %d (%s): attempted wait using an unlocked mutex '%s'\n",
670 filename, lineno, func, mutex_name);
671 DO_THREAD_CRASH;
672 }
673
674 /* Waiting on a condition completely suspends a recursive mutex,
675 * even if it's been recursively locked multiple times. Make a
676 * copy of the lock tracking, and reset reentrancy to zero */
677 lt_orig = *lt;
678 lt->reentrancy = 0;
679 ast_reentrancy_unlock(lt);
680
681 ast_suspend_lock_info(t);
682 }
683#endif /* DEBUG_THREADS */
684
685 res = pthread_cond_timedwait(cond, &t->mutex, abstime);
686
687#ifdef DEBUG_THREADS
688 if (res && (res != ETIMEDOUT)) {
689 log_mutex_error(canlog, "%s line %d (%s): Error waiting on condition mutex '%s'\n",
690 filename, lineno, func, strerror(res));
691 DO_THREAD_CRASH;
692 } else if (lt) {
693 restore_lock_tracking(lt, &lt_orig);
694 ast_restore_lock_info(t);
695 }
696#endif /* DEBUG_THREADS */
697
698 return res;
699}
#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 571 of file lock.c.

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

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#ifdef DEBUG_THREADS
513 if (res) {
514 log_mutex_error(canlog, "%s line %d (%s): Error releasing mutex: %s\n",
515 filename, lineno, func, strerror(res));
516 DO_THREAD_CRASH;
517 }
518#endif /* DEBUG_THREADS */
519
520 return res;
521}

References AST_MAX_REENTRANCY, ast_lock_track::backtrace, ast_lock_track::file, ast_lock_track::func, ast_lock_track::lineno, 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 735 of file lock.c.

736{
737 int res;
738
739#ifdef DEBUG_THREADS
740 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 1);
741 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
742
743#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
744 if (t->lock == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
745 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
746 filename, lineno, func, rwlock_name);
747 DO_THREAD_CRASH;
748 res = EINVAL;
749 goto lt_cleanup;
750 }
751#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
752#endif /* DEBUG_THREADS */
753
754 res = pthread_rwlock_destroy(&t->lock);
755
756#ifdef DEBUG_THREADS
757 if (res) {
758 log_mutex_error(canlog, "%s line %d (%s): Error destroying rwlock %s: %s\n",
759 filename, lineno, func, rwlock_name, strerror(res));
760 }
761#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
762lt_cleanup:
763#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
764 if (lt) {
765 ast_reentrancy_lock(lt);
766 lt->file[0] = filename;
767 lt->lineno[0] = lineno;
768 lt->func[0] = func;
769 lt->reentrancy = 0;
770 lt->thread_id[0] = 0;
771#ifdef HAVE_BKTR
772 memset(&lt->backtrace[0], 0, sizeof(lt->backtrace[0]));
773#endif
774 ast_reentrancy_unlock(lt);
775 delete_reentrancy_cs(&t->track);
776 }
777#endif /* DEBUG_THREADS */
778
779 return res;
780}
#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 701 of file lock.c.

703{
704 int res;
705 pthread_rwlockattr_t attr;
706
707#if defined(DEBUG_THREADS) && defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && \
708 defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
709 if (t->lock != ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
710 int canlog = tracking && strcmp(filename, "logger.c");
711
712 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is already initialized.\n",
713 filename, lineno, func, rwlock_name);
714 DO_THREAD_CRASH;
715 return EBUSY;
716 }
717#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
718
719#if defined(DEBUG_THREADS) || defined(DETECT_DEADLOCKS)
720 t->track = NULL;
721 t->flags.tracking = tracking;
722 t->flags.setup = 0;
723#endif /* DEBUG_THREADS */
724
725 pthread_rwlockattr_init(&attr);
726#ifdef HAVE_PTHREAD_RWLOCK_PREFER_WRITER_NP
727 pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP);
728#endif
729 res = pthread_rwlock_init(&t->lock, &attr);
730 pthread_rwlockattr_destroy(&attr);
731
732 return res;
733}

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 853 of file lock.c.

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

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

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

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 1224 of file lock.c.

1225{
1226 int res;
1227
1228#ifdef DEBUG_THREADS
1229 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1230 struct ast_bt *bt = NULL;
1231
1232 if (lt) {
1233#ifdef HAVE_BKTR
1234 struct ast_bt tmp;
1235
1236 /* The implementation of backtrace() may have its own locks.
1237 * Capture the backtrace outside of the reentrancy lock to
1238 * avoid deadlocks. See ASTERISK-22455. */
1240
1241 ast_reentrancy_lock(lt);
1242 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1243 lt->backtrace[lt->reentrancy] = tmp;
1244 bt = &lt->backtrace[lt->reentrancy];
1245 }
1246 ast_reentrancy_unlock(lt);
1247#endif
1248 ast_store_lock_info(AST_RDLOCK, filename, line, func, name, t, bt);
1249 }
1250#endif /* DEBUG_THREADS */
1251
1252 res = pthread_rwlock_tryrdlock(&t->lock);
1253
1254#ifdef DEBUG_THREADS
1255 if (!res && lt) {
1256 ast_reentrancy_lock(lt);
1257 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1258 lt->file[lt->reentrancy] = filename;
1259 lt->lineno[lt->reentrancy] = line;
1260 lt->func[lt->reentrancy] = func;
1261 lt->thread_id[lt->reentrancy] = pthread_self();
1262 lt->reentrancy++;
1263 }
1264 ast_reentrancy_unlock(lt);
1265 ast_mark_lock_acquired(t);
1266 } else if (lt) {
1268 }
1269#endif /* DEBUG_THREADS */
1270
1271 return res;
1272}

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 1274 of file lock.c.

1275{
1276 int res;
1277
1278#ifdef DEBUG_THREADS
1279 struct ast_lock_track *lt = ast_get_reentrancy(&t->track, &t->flags, 0);
1280 struct ast_bt *bt = NULL;
1281
1282 if (lt) {
1283#ifdef HAVE_BKTR
1284 struct ast_bt tmp;
1285
1286 /* The implementation of backtrace() may have its own locks.
1287 * Capture the backtrace outside of the reentrancy lock to
1288 * avoid deadlocks. See ASTERISK-22455. */
1290
1291 ast_reentrancy_lock(lt);
1292 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1293 lt->backtrace[lt->reentrancy] = tmp;
1294 bt = &lt->backtrace[lt->reentrancy];
1295 }
1296 ast_reentrancy_unlock(lt);
1297#endif
1298 ast_store_lock_info(AST_WRLOCK, filename, line, func, name, t, bt);
1299 }
1300#endif /* DEBUG_THREADS */
1301
1302 res = pthread_rwlock_trywrlock(&t->lock);
1303
1304#ifdef DEBUG_THREADS
1305 if (!res && lt) {
1306 ast_reentrancy_lock(lt);
1307 if (lt->reentrancy < AST_MAX_REENTRANCY) {
1308 lt->file[lt->reentrancy] = filename;
1309 lt->lineno[lt->reentrancy] = line;
1310 lt->func[lt->reentrancy] = func;
1311 lt->thread_id[lt->reentrancy] = pthread_self();
1312 lt->reentrancy++;
1313 }
1314 ast_reentrancy_unlock(lt);
1315 ast_mark_lock_acquired(t);
1316 } else if (lt) {
1318 }
1319#endif /* DEBUG_THREADS */
1320
1321 return res;
1322}

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 782 of file lock.c.

783{
784 int res;
785
786#ifdef DEBUG_THREADS
787 struct ast_lock_track *lt = NULL;
788 int canlog = t->flags.tracking && strcmp(filename, "logger.c");
789 struct ast_bt *bt = NULL;
790 int lock_found = 0;
791
792#if defined(AST_MUTEX_INIT_W_CONSTRUCTORS) && defined(CAN_COMPARE_MUTEX_TO_INIT_VALUE)
793 if ((t->lock) == ((pthread_rwlock_t) __AST_RWLOCK_INIT_VALUE)) {
794 log_mutex_error(canlog, "%s line %d (%s): Warning: rwlock '%s' is uninitialized.\n",
795 filename, line, func, name);
796 DO_THREAD_CRASH;
797 return EINVAL;
798 }
799#endif /* AST_MUTEX_INIT_W_CONSTRUCTORS */
800
801 lt = ast_get_reentrancy(&t->track, &t->flags, 0);
802 if (lt) {
803 ast_reentrancy_lock(lt);
804 if (lt->reentrancy) {
805 int i;
806 pthread_t self = pthread_self();
807 for (i = lt->reentrancy - 1; i >= 0; --i) {
808 if (lt->thread_id[i] == self) {
809 lock_found = 1;
810 if (i != lt->reentrancy - 1) {
811 lt->file[i] = lt->file[lt->reentrancy - 1];
812 lt->lineno[i] = lt->lineno[lt->reentrancy - 1];
813 lt->func[i] = lt->func[lt->reentrancy - 1];
814 lt->thread_id[i] = lt->thread_id[lt->reentrancy - 1];
815 }
816#ifdef HAVE_BKTR
817 bt = &lt->backtrace[i];
818#endif
819 lt->file[lt->reentrancy - 1] = NULL;
820 lt->lineno[lt->reentrancy - 1] = 0;
821 lt->func[lt->reentrancy - 1] = NULL;
823 break;
824 }
825 }
826 }
827
828 if (lock_found && --lt->reentrancy < 0) {
829 log_mutex_error(canlog, "%s line %d (%s): rwlock '%s' freed more times than we've locked!\n",
830 filename, line, func, name);
831 lt->reentrancy = 0;
832 }
833
834 ast_reentrancy_unlock(lt);
835
836 ast_remove_lock_info(t, bt);
837 }
838#endif /* DEBUG_THREADS */
839
840 res = pthread_rwlock_unlock(&t->lock);
841
842#ifdef DEBUG_THREADS
843 if (res) {
844 log_mutex_error(canlog, "%s line %d (%s): Error releasing rwlock: %s\n",
845 filename, line, func, strerror(res));
846 DO_THREAD_CRASH;
847 }
848#endif /* DEBUG_THREADS */
849
850 return res;
851}
#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 957 of file lock.c.

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

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(), action_login(), admin_exec(), advance_event(), ao2_container_count(), append_event(), 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(), grab_last(), 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_destructor(), 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().