mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-29 23:39:35 +00:00
Fix race condition for CEL LINKEDID_END event
This patch fixes to situations that could cause the CEL LINKEDID_END event to be missed. 1) During a core stop gracefully, modules are unloaded when ast_active_channels == 0. The LINKDEDID_END event fires during the channel destructor. This means that occasionally, the cel_* module will be unloaded before the channel is destroyed. It seemed generally useful to wait until the refcount of all channels == 0 before unloading, so I added a channel counter and used it in the shutdown code. 2) During a masquerade, ast_channel_change_linkedid is called. It calls ast_cel_check_retire_linkedid which unrefs the linkedid in the linkedids container in cel.c. It didn't ref the new linkedid. Now it does. Review: https://reviewboard.asterisk.org/r/1900/ ........ Merged revisions 367292 from http://svn.asterisk.org/svn/asterisk/branches/1.8 ........ Merged revisions 367299 from http://svn.asterisk.org/svn/asterisk/branches/10 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@367309 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -94,6 +94,7 @@ struct ast_epoll_data {
|
||||
static int shutting_down;
|
||||
|
||||
static int uniqueint;
|
||||
static int chancount;
|
||||
|
||||
unsigned long global_fin, global_fout;
|
||||
|
||||
@@ -645,6 +646,11 @@ int ast_active_channels(void)
|
||||
return channels ? ao2_container_count(channels) : 0;
|
||||
}
|
||||
|
||||
int ast_undestroyed_channels(void)
|
||||
{
|
||||
return ast_atomic_fetchadd_int(&chancount, 0);
|
||||
}
|
||||
|
||||
/*! \brief Cancel a shutdown in progress */
|
||||
void ast_cancel_shutdown(void)
|
||||
{
|
||||
@@ -1095,6 +1101,7 @@ __ast_channel_alloc_ap(int needqueue, int state, const char *cid_num, const char
|
||||
ast_cdr_init(ast_channel_cdr(tmp), tmp);
|
||||
ast_cdr_start(ast_channel_cdr(tmp));
|
||||
|
||||
ast_atomic_fetchadd_int(&chancount, +1);
|
||||
ast_cel_report_event(tmp, AST_CEL_CHANNEL_START, NULL, NULL, NULL);
|
||||
|
||||
headp = ast_channel_varshead(tmp);
|
||||
@@ -2302,6 +2309,7 @@ static void ast_channel_destructor(void *obj)
|
||||
if (callid) {
|
||||
ast_callid_unref(callid);
|
||||
}
|
||||
ast_atomic_fetchadd_int(&chancount, -1);
|
||||
}
|
||||
|
||||
/*! \brief Free a dummy channel structure */
|
||||
@@ -6357,15 +6365,17 @@ static const char *oldest_linkedid(const char *a, const char *b)
|
||||
* see if the channel's old linkedid is now being retired */
|
||||
static void ast_channel_change_linkedid(struct ast_channel *chan, const char *linkedid)
|
||||
{
|
||||
ast_assert(linkedid != NULL);
|
||||
/* if the linkedid for this channel is being changed from something, check... */
|
||||
if (!ast_strlen_zero(ast_channel_linkedid(chan)) && 0 != strcmp(ast_channel_linkedid(chan), linkedid)) {
|
||||
ast_cel_check_retire_linkedid(chan);
|
||||
if (ast_channel_linkedid(chan) && !strcmp(ast_channel_linkedid(chan), linkedid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ast_cel_check_retire_linkedid(chan);
|
||||
ast_channel_linkedid_set(chan, linkedid);
|
||||
ast_cel_linkedid_ref(linkedid);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
\brief Propagate the oldest linkedid between associated channels
|
||||
|
||||
|
||||
Reference in New Issue
Block a user