suspended destructions of pri spans on events

If a DAHDI span disappears, we wish for its representation in Asterisk
to be destroyed as well.

The information about the span's removal may come from several paths:

1. DAHDI sends DAHDI_EVENT_REMOVE on every channel.
2. An extra DAHDI_EVENT_REMOVED is sent on every subsequent call to
   DAHDI_GET_EVENT.
3. Every read (including the internal one by libpri on the D-channel)
   returns -ENODEV.

Asterisk responsds to DAHDI_EVENT_REMOVE on a channel by destroying it.

Destroying a channel requires holding the channel list lock (iflock).
Destroying a channel that is part of a span requires holding the span's
lock. Destroying a channel from a context that holds the span lock,
while at the same time another channel is destroyed directly, leads to a
deadlock. Solution: don't destroy span while holding the channels list
lock.

Thus changes in this patch:
* Deferring removal of PRI spans in response to events: doomed spans
  are collected on a list.
* Doomed spans are removed periodically by the monitor thread.
* ENODEV reads from the D-channel will warant the same deferred removal.

Review: https://reviewboard.asterisk.org/r/3548/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@417059 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Tzafrir Cohen
2014-06-23 07:44:19 +00:00
parent 682357dced
commit 3451d6a72d
3 changed files with 106 additions and 3 deletions

View File

@@ -1450,6 +1450,27 @@ static int pri_find_principle_by_call(struct sig_pri_span *pri, q931_call *call)
return -1;
}
/*!
* \internal
* \brief Queue the span for destruction
* \since 13.0
*
* \param pri PRI span control structure.
*
* Asks the channel driver to queue the span for destruction at a
* possibly later time, if (e.g.) locking considerations don't allow
* destroying it right now.
*
* \return Nothing
*/
static void pri_destroy_later(struct sig_pri_span *pri)
{
if (!sig_pri_callbacks.destroy_later) {
return;
}
sig_pri_callbacks.destroy_later(pri);
}
/*!
* \internal
* \brief Kill the call.
@@ -6427,6 +6448,14 @@ static void *pri_dchannel(void *vpri)
}
if (e)
break;
if ((errno != 0) && (errno != EINTR)) {
ast_log(LOG_NOTICE, "pri_check_event returned error %d (%s)\n",
errno, strerror(errno));
}
if (errno == ENODEV) {
pri_destroy_later(pri);
}
}
} else if (errno != EINTR)
ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));