audiod: Fix status item parsing for long status items.
authorAndre Noll <maan@systemlinux.org>
Mon, 19 Apr 2010 21:50:51 +0000 (23:50 +0200)
committerAndre Noll <maan@systemlinux.org>
Mon, 19 Apr 2010 21:50:51 +0000 (23:50 +0200)
This was broken since audiod started to use the buffer tree API. Actually there are
two bugs which are both fixed by this patch:

- for_each_stat_item() copies the remaining part of the buffer containing
the incomplete part of the last status item to the beginning of the buffer.
This is necessary if the buffer tree API is not used but messes up the buffer
contents if it _is_ used. Move this memmove()  call from for_each_status_item(),
which is called from audiod.c and gui.c,  to gui.c, as only gui.c needs it.

- Secondly, audiod.c called btr_node_status() with an minimum input queue
size of zero, which is does not work if a status item crosses a buffer
boundary. In this case for_each_status_item() will only ever see the first buffer
containing the incomplete status item, hence it can never make progress.
Fix this by introducing  the min_iqs field of struct status_task. Set  this field
to non-zero if the full buffer size was returned by for_each_status_item(),
indicating that the next status item is spread out over two or more buffers.

audiod.c
gui.c
stat.c

index 136557a..32047a1 100644 (file)
--- a/audiod.c
+++ b/audiod.c
@@ -92,6 +92,7 @@ struct status_task {
        struct timeval restart_barrier;
        /** Last time we received status data from para_server. */
        struct timeval last_status_read;
+       size_t min_iqs;
        /** The offset value announced by para_server. */
        int offset_seconds;
        /** The length of the current audio file as announced by para_server. */
@@ -1187,25 +1188,28 @@ static void status_post_select(__a_unused struct sched *s, struct task *t)
                }
                if (st->ct->status != CL_RECEIVING)
                        goto out;
-               ret = btr_node_status(st->btrn, 0, BTR_NT_LEAF);
-               if (ret <= 0)
+               ret = btr_node_status(st->btrn, st->min_iqs, BTR_NT_LEAF);
+               if (ret <= 0) {
+                       struct timeval diff;
+                       tv_diff(now, &st->last_status_read, &diff);
+                       if (diff.tv_sec > 61)
+                               kill_btrn(st->ct->btrn, &st->ct->task,
+                                       -E_STATUS_TIMEOUT);
                        goto out;
+               }
+               btr_merge(st->btrn, st->min_iqs);
                sz = btr_next_buffer(st->btrn, &buf);
                ret = for_each_stat_item(buf, sz, update_item);
                if (ret < 0) {
                        kill_btrn(st->ct->btrn, &st->ct->task, ret);
                        goto out;
                }
-               if (sz != ret)
+               if (sz != ret) {
+                       btr_consume(st->btrn, sz - ret);
                        st->last_status_read = *now;
-               else {
-                       struct timeval diff;
-                       tv_diff(now, &st->last_status_read, &diff);
-                       if (diff.tv_sec > 61)
-                               kill_btrn(st->ct->btrn, &st->ct->task,
-                                       -E_STATUS_TIMEOUT);
-               }
-               btr_consume(st->btrn, sz - ret);
+                       st->min_iqs = 0;
+               } else /* current status item crosses buffers */
+                       st->min_iqs = sz + 1;
                goto out;
        }
        if (tv_diff(now, &st->restart_barrier, NULL) < 0)
diff --git a/gui.c b/gui.c
index 45b477f..5f2dba0 100644 (file)
--- a/gui.c
+++ b/gui.c
@@ -730,6 +730,8 @@ static int read_audiod_pipe(int fd)
        ret = for_each_stat_item(buf, loaded, update_item);
        if (ret < 0)
                return ret;
+       if (ret > 0 && ret < loaded)
+               memmove(buf, buf + loaded - ret, ret);
        loaded = ret;
        return 1;
 }
diff --git a/stat.c b/stat.c
index 58e289f..b9d8e3b 100644 (file)
--- a/stat.c
+++ b/stat.c
@@ -77,7 +77,5 @@ int for_each_stat_item(char *item_buf, size_t num_bytes,
                assert(len >= 0 && buf <= item_buf + num_bytes);
        }
        assert(len >= 0);
-       if (len && len != num_bytes)
-               memmove(item_buf, item_buf + num_bytes - len, len);
        return len;
 }