summaryrefslogtreecommitdiff
path: root/main/channel.c
diff options
context:
space:
mode:
authorRichard Mudgett <rmudgett@digium.com>2017-01-31 18:28:15 -0600
committerRichard Mudgett <rmudgett@digium.com>2017-02-02 13:02:03 -0600
commit50029f585ece50a133180410b6c8fff66ad48e72 (patch)
tree2fe43ee00aabc8d3b29776b705f5e420fd277090 /main/channel.c
parent97c308471d2ead6473499b0026b72f8ed7b516eb (diff)
channel.c: Fix unbalanced read queue deadlocking local channels.
Using the timerfd timing module can cause channel freezing, lingering, or deadlock issues. The problem is because this is the only timing module that uses an associated alert-pipe. When the alert-pipe becomes unbalanced with respect to the number of frames in the read queue bad things can happen. If the alert-pipe has fewer alerts queued than the read queue then nothing might wake up the thread to handle received frames from the channel driver. For local channels this is the only way to wake up the thread to handle received frames. Being unbalanced in the other direction is less of an issue as it will cause unnecessary reads into the channel driver. ASTERISK-26716 is an example of this deadlock which was indirectly fixed by the change that found the need for this patch. * In channel.c:__ast_queue_frame(): Adding frame lists to the read queue did not add the same number of alerts to the alert-pipe. Correspondingly, when there is an exceptionally long queue event, any removed frames did not also remove the corresponding number of alerts from the alert-pipe. ASTERISK-26632 #close Change-Id: Ia98137c5bf6e9d6d202ce0eb36441851875863f6
Diffstat (limited to 'main/channel.c')
-rw-r--r--main/channel.c13
1 files changed, 10 insertions, 3 deletions
diff --git a/main/channel.c b/main/channel.c
index 1c7743a2f..234919336 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -1148,6 +1148,9 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in
}
AST_LIST_REMOVE_CURRENT(frame_list);
ast_frfree(cur);
+
+ /* Read from the alert pipe for each flushed frame. */
+ ast_channel_internal_alert_read(chan);
}
}
AST_LIST_TRAVERSE_SAFE_END;
@@ -1164,9 +1167,13 @@ static int __ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, in
}
if (ast_channel_alert_writable(chan)) {
- if (ast_channel_alert_write(chan)) {
- ast_log(LOG_WARNING, "Unable to write to alert pipe on %s (qlen = %u): %s!\n",
- ast_channel_name(chan), queued_frames, strerror(errno));
+ /* Write to the alert pipe for each added frame */
+ while (new_frames--) {
+ if (ast_channel_alert_write(chan)) {
+ ast_log(LOG_WARNING, "Unable to write to alert pipe on %s (qlen = %u): %s!\n",
+ ast_channel_name(chan), queued_frames, strerror(errno));
+ break;
+ }
}
} else if (ast_channel_timingfd(chan) > -1) {
ast_timer_enable_continuous(ast_channel_timer(chan));