audiod: Make mode switching (on, off, sb) work again.
authorAndre Noll <maan@systemlinux.org>
Tue, 12 Jan 2010 23:23:54 +0000 (00:23 +0100)
committerAndre Noll <maan@systemlinux.org>
Tue, 12 Jan 2010 23:23:54 +0000 (00:23 +0100)
It is not sufficient to set the task status to an error value. We
also have to remove the btr node from the buffer tree.

audiod.c

index 128f7b424828c4c1b5966912d32a931427accc51..2819091b80a2c27991df0ae0f3a95290e7423916 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -389,6 +389,20 @@ static void close_filters(struct slot_info *s)
        s->fns = NULL;
 }
 
+/*
+ * Whenever a task commits suicide by returning from post_select with t->error
+ * < 0, it also removes its btr node. We do exactly that to kill a running
+ * task. Note that the scheduler checks t->error also _before_ each pre/post
+ * select call, so the victim will never be scheduled again.
+ */
+static void kill_btrn(struct btr_node *btrn, struct task *t, int error)
+{
+       if (t->error < 0)
+               return;
+       t->error = error;
+       btr_remove_node(btrn);
+}
+
 static void kill_all_decoders(int error)
 {
        int i, j;
@@ -401,12 +415,13 @@ static void kill_all_decoders(int error)
                a = afi + s->format;
                if (s->wns)
                        for (j = 0; j < a->num_writers; j++)
-                               s->wns[j].task.error = error;
+                               kill_btrn(s->wns[j].btrn, &s->wns[j].task, error);
                if (s->fns)
                        for (j = 0; j < a->num_writers; j++)
-                               s->fns[j].task.error = error;
+                               kill_btrn(s->fns[j].btrn, &s->wns[j].task, error);
                if (s->receiver_node)
-                       s->receiver_node->task.error = error;
+                       kill_btrn(s->receiver_node->btrn, &s->receiver_node->task,
+                               error);
        }
 }
 
@@ -1091,9 +1106,9 @@ static void start_stop_decoders(struct sched *s)
        FOR_EACH_SLOT(i)
                if (try_to_close_slot(i))
                        sched_min_delay(s);
-//     if (audiod_status != AUDIOD_ON ||
-//                     !(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING))
-//             return kill_all_decoders(-E_NOT_PLAYING);
+       if (audiod_status != AUDIOD_ON ||
+                       !(stat_task->vss_status & VSS_STATUS_FLAG_PLAYING))
+               return kill_all_decoders(-E_NOT_PLAYING);
        ret = open_current_receiver(s);
        if (ret < 0)
                return;