summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTanu Kaskinen <tanuk@iki.fi>2017-05-08 12:58:49 +0300
committerTanu Kaskinen <tanuk@iki.fi>2017-05-18 23:32:32 +0300
commita7017b831e0d5b6f699fe05bc1b67a14c151ef12 (patch)
treee4452a6641aa8ffdcf57942d024270dbb4bb9a97
parente08124f6ba09d553e3a9a3b8fee16f3a83571122 (diff)
downloadpulseaudio-a7017b831e0d5b6f699fe05bc1b67a14c151ef12.tar.gz
sink-input, source-output: don't allow moving streams that are connected to moving filter devices
When a filter sink is moving, it's not connected to any master sink, and therefore it's not connected to any IO thread either. In this situation trying to move a stream that is connected to the filter sink is likely to result in crashing, because starting the move involves sending a message to the IO thread. Sometimes this works by accident (the asyncmsgq of the filter sink still points to the old master sink's asyncmsgq), but we really should never attempt it. This patch blocks all moves where the moving stream is connected to a filter sink that itself is in the middle of a move. BugLink: https://bugs.freedesktop.org/show_bug.cgi?id=100277
-rw-r--r--src/pulsecore/sink-input.c26
-rw-r--r--src/pulsecore/source-output.c27
2 files changed, 53 insertions, 0 deletions
diff --git a/src/pulsecore/sink-input.c b/src/pulsecore/sink-input.c
index 2ceed412d..4155b69a5 100644
--- a/src/pulsecore/sink-input.c
+++ b/src/pulsecore/sink-input.c
@@ -1627,6 +1627,22 @@ static bool find_filter_sink_input(pa_sink_input *target, pa_sink *s) {
return false;
}
+static bool is_filter_sink_moving(pa_sink_input *i) {
+ pa_sink *sink = i->sink;
+
+ if (!sink)
+ return false;
+
+ while (sink->input_to_master) {
+ sink = sink->input_to_master->sink;
+
+ if (!sink)
+ return true;
+ }
+
+ return false;
+}
+
/* Called from main context */
bool pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) {
pa_sink_input_assert_ref(i);
@@ -1649,6 +1665,16 @@ bool pa_sink_input_may_move_to(pa_sink_input *i, pa_sink *dest) {
return false;
}
+ /* If this sink input is connected to a filter sink that itself is moving,
+ * then don't allow the move. Moving requires sending a message to the IO
+ * thread of the old sink, and if the old sink is a filter sink that is
+ * moving, there's no IO thread associated to the old sink. */
+ if (is_filter_sink_moving(i)) {
+ pa_log_debug("Can't move input from filter sink %s, because the filter sink itself is currently moving.",
+ i->sink->name);
+ return false;
+ }
+
if (pa_idxset_size(dest->inputs) >= PA_MAX_INPUTS_PER_SINK) {
pa_log_warn("Failed to move sink input: too many inputs per sink.");
return false;
diff --git a/src/pulsecore/source-output.c b/src/pulsecore/source-output.c
index fa32a5666..a4c99af0e 100644
--- a/src/pulsecore/source-output.c
+++ b/src/pulsecore/source-output.c
@@ -1265,6 +1265,22 @@ static bool find_filter_source_output(pa_source_output *target, pa_source *s) {
return false;
}
+static bool is_filter_source_moving(pa_source_output *o) {
+ pa_source *source = o->source;
+
+ if (!source)
+ return false;
+
+ while (source->output_from_master) {
+ source = source->output_from_master->source;
+
+ if (!source)
+ return true;
+ }
+
+ return false;
+}
+
/* Called from main context */
bool pa_source_output_may_move_to(pa_source_output *o, pa_source *dest) {
pa_source_output_assert_ref(o);
@@ -1286,6 +1302,17 @@ bool pa_source_output_may_move_to(pa_source_output *o, pa_source *dest) {
return false;
}
+ /* If this source output is connected to a filter source that itself is
+ * moving, then don't allow the move. Moving requires sending a message to
+ * the IO thread of the old source, and if the old source is a filter
+ * source that is moving, there's no IO thread associated to the old
+ * source. */
+ if (is_filter_source_moving(o)) {
+ pa_log_debug("Can't move output from filter source %s, because the filter source itself is currently moving.",
+ o->source->name);
+ return false;
+ }
+
if (pa_idxset_size(dest->outputs) >= PA_MAX_OUTPUTS_PER_SOURCE) {
pa_log_warn("Failed to move source output: too many outputs per source.");
return false;