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 136557adca486f65bdb38c592254461284148459..32047a1f9aae8d8c69adefe82e12a82e7bfcf00f 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 45b477fb19b8bddaa43918b2d86676584c12b864..5f2dba0230cf409e0f80820c8314d5d6cc1d6e84 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 58e289f7346fae8afe0d6acce9460e5801c7a239..b9d8e3b9e3afc763beca585683e147effaaf334f 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;
 }