From 45b4e8b0ba410fd929a341a9bf84b1ac3995d734 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Mon, 19 Apr 2010 23:50:51 +0200 Subject: [PATCH] audiod: Fix status item parsing for long status items. 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 | 26 +++++++++++++++----------- gui.c | 2 ++ stat.c | 2 -- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/audiod.c b/audiod.c index 136557ad..32047a1f 100644 --- 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 45b477fb..5f2dba02 100644 --- 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 58e289f7..b9d8e3b9 100644 --- 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; } -- 2.39.2