mirror of
https://github.com/asterisk/asterisk.git
synced 2025-12-04 20:21:55 +00:00
New functions for locking a channel - these simplify debugging
when you have channel locking issues. (Part of the SIP transfer patch, where I had a *lot* of channel locking problems) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@20264 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
4
Makefile
4
Makefile
@@ -90,6 +90,10 @@ WITH_SMDI = 1
|
|||||||
# Optional debugging parameters
|
# Optional debugging parameters
|
||||||
DEBUG_THREADS = #-DDUMP_SCHEDULER #-DDEBUG_SCHEDULER #-DDEBUG_THREADS #-DDO_CRASH #-DDETECT_DEADLOCKS
|
DEBUG_THREADS = #-DDUMP_SCHEDULER #-DDEBUG_SCHEDULER #-DDEBUG_THREADS #-DDO_CRASH #-DDETECT_DEADLOCKS
|
||||||
|
|
||||||
|
# If you want to debug channel locking, try this (depends on code using
|
||||||
|
# ast_channel_lock and companions to work)
|
||||||
|
DEBUG_THREADS += #-DDEBUG_CHANNEL_LOCKS
|
||||||
|
|
||||||
# Uncomment next one to enable ast_frame tracing (for debugging)
|
# Uncomment next one to enable ast_frame tracing (for debugging)
|
||||||
TRACE_FRAMES = #-DTRACE_FRAMES
|
TRACE_FRAMES = #-DTRACE_FRAMES
|
||||||
|
|
||||||
|
|||||||
124
channel.c
124
channel.c
@@ -4187,3 +4187,127 @@ const char *channelreloadreason2txt(enum channelreloadreason reason)
|
|||||||
return "MANAGERRELOAD (Channel module reload by manager)";
|
return "MANAGERRELOAD (Channel module reload by manager)";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef DEBUG_CHANNEL_LOCKS
|
||||||
|
|
||||||
|
/*! \brief Unlock AST channel (and print debugging output)
|
||||||
|
\note You need to enable DEBUG_CHANNEL_LOCKS for this function
|
||||||
|
*/
|
||||||
|
int ast_channel_unlock(struct ast_channel *chan)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
if (option_debug > 2)
|
||||||
|
ast_log(LOG_DEBUG, "::::==== Unlocking AST channel %s\n", chan->name);
|
||||||
|
|
||||||
|
if (!chan) {
|
||||||
|
ast_log(LOG_DEBUG, "::::==== Unlocking non-existing channel \n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = ast_mutex_unlock(&chan->lock);
|
||||||
|
|
||||||
|
if (option_debug > 2) {
|
||||||
|
/* Try to find counter if possible on your platform
|
||||||
|
I've only found out how to do this on Linux
|
||||||
|
DEBUG_THREADS changes the lock structure
|
||||||
|
*/
|
||||||
|
#ifdef __linux__
|
||||||
|
int count = 0;
|
||||||
|
#ifdef DEBUG_THREADS
|
||||||
|
if ((count = chan->lock.mutex.__m_count))
|
||||||
|
#else
|
||||||
|
if ((count = chan->lock.__m_count))
|
||||||
|
#endif
|
||||||
|
ast_log(LOG_DEBUG, ":::=== Still have %d locks (recursive)\n", count);
|
||||||
|
#endif
|
||||||
|
if (!res)
|
||||||
|
ast_log(LOG_DEBUG, "::::==== Channel %s was unlocked\n", chan->name);
|
||||||
|
if (res == EINVAL) {
|
||||||
|
ast_log(LOG_DEBUG, "::::==== Channel %s had no lock by this thread. Failed unlocking\n", chan->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res == EPERM) {
|
||||||
|
/* We had no lock, so okay any way*/
|
||||||
|
if (option_debug > 3)
|
||||||
|
ast_log(LOG_DEBUG, "::::==== Channel %s was not locked at all \n", chan->name);
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Lock AST channel (and print debugging output)
|
||||||
|
\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
|
||||||
|
int ast_channel_lock(struct ast_channel *chan)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (option_debug > 3)
|
||||||
|
ast_log(LOG_DEBUG, "====:::: Locking AST channel %s\n", chan->name);
|
||||||
|
|
||||||
|
res = ast_mutex_lock(&chan->lock);
|
||||||
|
|
||||||
|
if (option_debug > 3) {
|
||||||
|
#ifdef __linux__
|
||||||
|
int count = 0;
|
||||||
|
#ifdef DEBUG_THREADS
|
||||||
|
if ((count = chan->lock.mutex.__m_count))
|
||||||
|
#else
|
||||||
|
if ((count = chan->lock.__m_count))
|
||||||
|
#endif
|
||||||
|
ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
|
||||||
|
#endif
|
||||||
|
if (!res)
|
||||||
|
ast_log(LOG_DEBUG, "::::==== Channel %s was locked\n", chan->name);
|
||||||
|
if (res == EDEADLK) {
|
||||||
|
/* We had no lock, so okey any way */
|
||||||
|
if (option_debug > 3)
|
||||||
|
ast_log(LOG_DEBUG, "::::==== Channel %s was not locked by us. Lock would cause deadlock.\n", chan->name);
|
||||||
|
}
|
||||||
|
if (res == EINVAL) {
|
||||||
|
if (option_debug > 3)
|
||||||
|
ast_log(LOG_DEBUG, "::::==== Channel %s lock failed. No mutex.\n", chan->name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! \brief Lock AST channel (and print debugging output)
|
||||||
|
\note You need to enable DEBUG_CHANNEL_LOCKS for this function */
|
||||||
|
int __ast_channel_trylock(struct ast_channel *chan)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
|
||||||
|
if (option_debug > 2)
|
||||||
|
ast_log(LOG_DEBUG, "====:::: Trying to lock AST channel %s\n", chan->name);
|
||||||
|
|
||||||
|
res = ast_mutex_trylock(&chan->lock);
|
||||||
|
|
||||||
|
if (option_debug > 2) {
|
||||||
|
#ifdef __linux__
|
||||||
|
int count = 0;
|
||||||
|
#ifdef DEBUG_THREADS
|
||||||
|
if ((count = chan->lock.mutex.__m_count))
|
||||||
|
#else
|
||||||
|
if ((count = chan->lock.__m_count))
|
||||||
|
#endif
|
||||||
|
ast_log(LOG_DEBUG, ":::=== Now have %d locks (recursive)\n", count);
|
||||||
|
#endif
|
||||||
|
if (!res)
|
||||||
|
ast_log(LOG_DEBUG, "::::==== Channel %s was locked\n", chan->name);
|
||||||
|
if (res == EBUSY) {
|
||||||
|
/* We failed to lock */
|
||||||
|
if (option_debug > 2)
|
||||||
|
ast_log(LOG_DEBUG, "::::==== Channel %s failed to lock. Not waiting around...\n", chan->name);
|
||||||
|
}
|
||||||
|
if (res == EDEADLK) {
|
||||||
|
/* We had no lock, so okey any way*/
|
||||||
|
if (option_debug > 2)
|
||||||
|
ast_log(LOG_DEBUG, "::::==== Channel %s was not locked. Lock would cause deadlock.\n", chan->name);
|
||||||
|
}
|
||||||
|
if (res == EINVAL && option_debug > 2)
|
||||||
|
ast_log(LOG_DEBUG, "::::==== Channel %s lock failed. No mutex.\n", chan->name);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -1344,7 +1344,7 @@ static int retrans_pkt(void *data)
|
|||||||
int reschedule = DEFAULT_RETRANS;
|
int reschedule = DEFAULT_RETRANS;
|
||||||
|
|
||||||
/* Lock channel */
|
/* Lock channel */
|
||||||
ast_mutex_lock(&pkt->owner->lock);
|
ast_channel_lock(&pkt->owner);
|
||||||
|
|
||||||
if (pkt->retrans < MAX_RETRANS) {
|
if (pkt->retrans < MAX_RETRANS) {
|
||||||
pkt->retrans++;
|
pkt->retrans++;
|
||||||
@@ -1381,7 +1381,7 @@ static int retrans_pkt(void *data)
|
|||||||
|
|
||||||
append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data);
|
append_history(pkt->owner, "ReTx", "%d %s", reschedule, pkt->data);
|
||||||
__sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
|
__sip_xmit(pkt->owner, pkt->data, pkt->packetlen);
|
||||||
ast_mutex_unlock(&pkt->owner->lock);
|
ast_channel_unlock(&pkt->owner);
|
||||||
return reschedule;
|
return reschedule;
|
||||||
}
|
}
|
||||||
/* Too many retries */
|
/* Too many retries */
|
||||||
|
|||||||
@@ -761,4 +761,16 @@ AST_INLINE_API(int ast_atomic_dec_and_test(volatile int *p),
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#ifndef DEBUG_CHANNEL_LOCKS
|
||||||
|
/*! \brief Lock a channel. If DEBUG_CHANNEL_LOCKS is defined
|
||||||
|
in the Makefile, print relevant output for debugging */
|
||||||
|
#define ast_channel_lock(x) ast_mutex_lock(x->lock);
|
||||||
|
/*! \brief Unlock a channel. If DEBUG_CHANNEL_LOCKS is defined
|
||||||
|
in the Makefile, print relevant output for debugging */
|
||||||
|
#define ast_channel_unlock(x) ast_mutex_unlock(x->lock);
|
||||||
|
/*! \brief Try locking a channel. If DEBUG_CHANNEL_LOCKS is defined
|
||||||
|
in the Makefile, print relevant output for debugging */
|
||||||
|
#define ast_channel_trylock(x) ast_mutex_trylock(x->lock);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _ASTERISK_LOCK_H */
|
#endif /* _ASTERISK_LOCK_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user