[PATCH v2] sink-input, source-output: don't allow moving streams that are connected to moving filter devices

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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
---

This is an old patch that was not applied on the first submission,
because it was not necessary for fixing the bug at hand at that time.
Here's the v1 (there are no changes in the code):
https://patchwork.freedesktop.org/patch/68741/

Changes in v2:
 - rewrote the commit message


 src/pulsecore/sink-input.c    | 26 ++++++++++++++++++++++++++
 src/pulsecore/source-output.c | 27 +++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

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;
-- 
2.11.0



[Index of Archives]     [Linux Audio Users]     [AMD Graphics]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux