More audiod fixes
authorAndre <maan@p133.(none)>
Sun, 4 Jun 2006 20:59:38 +0000 (22:59 +0200)
committerAndre <maan@p133.(none)>
Sun, 4 Jun 2006 20:59:38 +0000 (22:59 +0200)
The bug-quality rises. This patch fixes

the select timeout after receiver open. As the pre_select
function of the receiver just opened will be called _after_
the upcoming select call, we might block for the time of that
call. Only afterwards, the receiver can change the timeout. Fix
this problem by changing the timeout to a minimum from within
start_receiver() (which gets called by audiod_pre_select()).

Resume on server restart. This was broken by design as it
used sleep() and also caused problems with the alsa writer
being restarted too early. We can do much better with the
new scheduler, so introduce a new field "restart_barrier" in
struct status_task and restart para_client and the receivers
not before this time.

Also, set the default timeout to a ridiculous value to detect further
timeout problems and do not kill the decoders even if the status pipe
went south.

audiod.c

index 29ceda5..f653c4f 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -137,6 +137,8 @@ struct status_task {
        unsigned loaded;
        /** the associated task structure */
        struct task task;
+       /** do not restart client command until this time */
+       struct timeval restart_barrier;
 };
 static struct status_task status_task_struct, *stat_task = &status_task_struct;
 
@@ -584,7 +586,7 @@ static void close_stat_pipe(void)
        close(stat_task->fd);
        del_close_on_fork_list(stat_task->fd);
        stat_task->fd = -1;
-       kill_all_decoders();
+//     kill_all_decoders();
        for (i = 0; i < NUM_STAT_ITEMS; i++) {
                free(stat_item_values[i]);
                stat_item_values[i] = NULL;
@@ -798,7 +800,7 @@ static int is_frozen(int format)
        return (tv_diff(now, &a->restart_barrier, NULL) > 0)? 0 : 1;
 }
 
-static void open_current_receiver(void)
+static void open_current_receiver(struct sched *s)
 {
        int i;
 
@@ -810,6 +812,13 @@ static void open_current_receiver(void)
        if (decoder_running(i) || is_frozen(i))
                return;
        open_receiver(i);
+       /*
+        * the receiver didn't get a chance to put his fd to the fd set.
+        * Make the upcoming select() return immediately to avoid a long
+        * timeout.
+        */
+       s->timeout.tv_sec = 0;
+       s->timeout.tv_usec = 1;
 }
 
 static void compute_time_diff(const struct timeval *status_time)
@@ -947,7 +956,7 @@ static void audiod_pre_select(struct sched *s, __a_unused struct task *t)
        if (audiod_status != AUDIOD_ON || !playing)
                kill_all_decoders();
        else if (playing)
-               open_current_receiver();
+               open_current_receiver(s);
        FOR_EACH_SLOT(i) {
                struct slot_info *s = &slot[i];
                struct audio_format_info *a;
@@ -1612,12 +1621,16 @@ static void init_command_task(struct command_task *ct)
 
 static void status_event_handler(__a_unused struct task *t)
 {
+       struct timeval delay = {1, 0};
+       int i;
+       struct status_task *st = t->private_data;
+
        PARA_ERROR_LOG("%s\n", PARA_STRERROR(-t->ret));
        close_stat_pipe();
        /* avoid busy loop if server is down */
-       while (sleep(1) > 0) /* FIXME */
-               ; /* try again*/
-
+       tv_add(now, &delay, &st->restart_barrier);
+       FOR_EACH_AUDIO_FORMAT(i)
+               afi[i].restart_barrier = st->restart_barrier;
 }
 
 static void status_pre_select(struct sched *s, struct task *t)
@@ -1626,7 +1639,8 @@ static void status_pre_select(struct sched *s, struct task *t)
        t->ret = 1;
        if (st->fd >= 0 && audiod_status == AUDIOD_OFF)
                close_stat_pipe();
-       if (st->fd < 0 && audiod_status != AUDIOD_OFF) {
+       if (st->fd < 0 && audiod_status != AUDIOD_OFF
+               && tv_diff(now, &st->restart_barrier, NULL) > 0) {
                st->fd = open_stat_pipe();
                st->loaded = 0;
                st->buf[0] = '\0';
@@ -1655,14 +1669,12 @@ static void status_post_select(struct sched *s, struct task *t)
 
 static void init_status_task(struct status_task *st)
 {
+       memset(st, 0, sizeof(struct status_task));
        st->task.pre_select = status_pre_select;
        st->task.post_select = status_post_select;
        st->task.event_handler = status_event_handler;
        st->task.private_data = st;
-       st->task.flags = 0;
-       st->loaded = 0;
        st->fd = -1;
-       st->buf[0] = '\0';
        sprintf(st->task.status, "status task");
 }
 
@@ -1732,7 +1744,7 @@ int main(int argc, char *argv[])
        register_task(&cmd_task->task);
        register_task(&stat_task->task);
        register_task(audiod_task);
-       s.default_timeout.tv_sec = 0;
+       s.default_timeout.tv_sec = 3;
        s.default_timeout.tv_usec = 99 * 1000;
        ret = sched(&s);