summaryrefslogtreecommitdiff
path: root/channels/chan_dahdi.c
diff options
context:
space:
mode:
authorTzafrir Cohen <tzafrir.cohen@xorcom.com>2014-06-23 07:44:19 +0000
committerTzafrir Cohen <tzafrir.cohen@xorcom.com>2014-06-23 07:44:19 +0000
commit3451d6a72d0499a83d82ce03d00d2156a1258c8b (patch)
tree6b3bf6bf6b1c5c5b840d1083cdc92c86f508f1ed /channels/chan_dahdi.c
parent682357dced7caccaa7e11164bf2e3509acbd8c06 (diff)
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
Diffstat (limited to 'channels/chan_dahdi.c')
-rw-r--r--channels/chan_dahdi.c78
1 files changed, 75 insertions, 3 deletions
diff --git a/channels/chan_dahdi.c b/channels/chan_dahdi.c
index adc025ae0..0a0b330f2 100644
--- a/channels/chan_dahdi.c
+++ b/channels/chan_dahdi.c
@@ -780,6 +780,14 @@ static struct dahdi_pvt *iflist = NULL; /*!< Main interface list start */
static struct dahdi_pvt *ifend = NULL; /*!< Main interface list end */
#if defined(HAVE_PRI)
+struct doomed_pri {
+ struct sig_pri_span *pri;
+ AST_LIST_ENTRY(doomed_pri) list;
+};
+static AST_LIST_HEAD_STATIC(doomed_pris, doomed_pri);
+
+static void pri_destroy_span(struct sig_pri_span *pri);
+
static struct dahdi_parms_pseudo {
int buf_no; /*!< Number of buffers */
int buf_policy; /*!< Buffer policy */
@@ -1114,6 +1122,69 @@ static int analogsub_to_dahdisub(enum analog_sub analogsub)
/*!
* \internal
+ * \brief release all members on the doomed pris list
+ * \since 13.0
+ *
+ * Called priodically by the monitor threads to release spans marked for
+ * removal.
+ */
+static void release_doomed_pris(void)
+{
+#ifdef HAVE_PRI
+ struct doomed_pri *entry;
+
+ AST_LIST_LOCK(&doomed_pris);
+ while ((entry = AST_LIST_REMOVE_HEAD(&doomed_pris, list))) {
+ /* The span destruction must be done with this lock not held */
+ AST_LIST_UNLOCK(&doomed_pris);
+ ast_debug(4, "Destroying span %d from doomed queue.\n",
+ entry->pri->span);
+ pri_destroy_span(entry->pri);
+ ast_free(entry);
+ AST_LIST_LOCK(&doomed_pris);
+ }
+ AST_LIST_UNLOCK(&doomed_pris);
+#endif
+}
+
+#ifdef HAVE_PRI
+/*!
+ * \brief Queue a span for destruction
+ * \since 13.0
+ *
+ * \param pri the span to destroy
+ *
+ * Add a span to the list of spans to be destroyed later on
+ * by the monitor thread. Allows destroying a span while holding its
+ * lock.
+ */
+static void pri_queue_for_destruction(struct sig_pri_span *pri)
+{
+ struct doomed_pri *entry;
+
+ AST_LIST_LOCK(&doomed_pris);
+ AST_LIST_TRAVERSE(&doomed_pris, entry, list) {
+ if (entry->pri == pri) {
+ AST_LIST_UNLOCK(&doomed_pris);
+ return;
+ }
+ }
+ entry = ast_calloc(sizeof(struct doomed_pri), 1);
+ if (!entry) {
+ /* Nothing useful to do here. Panic? */
+ ast_log(LOG_WARNING, "Failed allocating memory for a doomed_pri.\n");
+ AST_LIST_UNLOCK(&doomed_pris);
+ return;
+ }
+ entry->pri = pri;
+ ast_debug(4, "Queue span %d for destruction.\n", pri->span);
+ AST_LIST_INSERT_TAIL(&doomed_pris, entry, list);
+ AST_LIST_UNLOCK(&doomed_pris);
+}
+#endif
+
+/*!
+ * \internal
* \brief Send a dial string to DAHDI.
* \since 12.0.0
*
@@ -2654,8 +2725,6 @@ static int sig_pri_tone_to_dahditone(enum sig_pri_tone tone)
#endif /* defined(HAVE_PRI) */
#if defined(HAVE_PRI)
-static void pri_destroy_span(struct sig_pri_span *pri);
-
static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
{
int x;
@@ -2684,7 +2753,7 @@ static void my_handle_dchan_exception(struct sig_pri_span *pri, int index)
pri_event_noalarm(pri, index, 0);
break;
case DAHDI_EVENT_REMOVED:
- pri_destroy_span(pri);
+ pri_queue_for_destruction(pri);
break;
default:
break;
@@ -2967,6 +3036,7 @@ struct sig_pri_callback sig_pri_callbacks =
.dial_digits = my_pri_dial_digits,
.open_media = my_pri_ss7_open_media,
.ami_channel_event = my_ami_channel_event,
+ .destroy_later = pri_queue_for_destruction,
};
#endif /* defined(HAVE_PRI) */
@@ -11469,6 +11539,7 @@ static void *do_monitor(void *data)
}
}
ast_mutex_unlock(&iflock);
+ release_doomed_pris();
}
/* Never reached */
pthread_cleanup_pop(1);
@@ -14217,6 +14288,7 @@ static void pri_destroy_span(struct sig_pri_span *pri)
for (i = 0; i < SIG_PRI_NUM_DCHANS; i++) {
ast_debug(4, "closing pri_fd %d\n", i);
dahdi_close_pri_fd(dahdi_pri, i);
+ dahdi_pri->dchannels[i] = 0;
}
sig_pri_init_pri(pri);
ast_debug(1, "PRI span %d destroyed\n", pri->span);