[MEDIUM] buffer: make buffer_feed* support writing non-contiguous chunks
The buffer_feed* functions that are used to send data to buffers did only
support sending contiguous chunks while they're relying on memcpy(). This
patch improves on this by making them able to write in two chunks if needed.
Thus, the buffer_almost_full() function has been improved to really consider
the remaining space and not just what can be written at once.
diff --git a/include/proto/buffers.h b/include/proto/buffers.h
index 870dadb..dca3c88 100644
--- a/include/proto/buffers.h
+++ b/include/proto/buffers.h
@@ -290,6 +290,15 @@
}
/*
+ * Return the maximum amount of bytes that can be written into the buffer in
+ * one call to buffer_feed*().
+ */
+static inline int buffer_free_space(struct buffer *buf)
+{
+ return buffer_max_len(buf) - buf->l;
+}
+
+/*
* Return the max amount of bytes that can be stuffed into the buffer at once.
* Note that this may be lower than the actual buffer size when the free space
* wraps after the end, so it's preferable to call this function again after
@@ -314,10 +323,33 @@
return ret;
}
+/*
+ * Same as above but the caller may pass the value of buffer_max_len(buf) if it
+ * knows it, thus avoiding some calculations.
+ */
+static inline int buffer_contig_space_with_len(struct buffer *buf, int maxlen)
+{
+ int ret;
+
+ if (buf->l == 0) {
+ buf->r = buf->w = buf->lr = buf->data;
+ ret = maxlen;
+ }
+ else if (buf->r > buf->w) {
+ ret = buf->data + maxlen - buf->r;
+ }
+ else {
+ ret = buf->w - buf->r;
+ if (ret > maxlen)
+ ret = maxlen;
+ }
+ return ret;
+}
+
/* Return 1 if the buffer has less than 1/4 of its capacity free, otherwise 0 */
static inline int buffer_almost_full(struct buffer *buf)
{
- if (buffer_contig_space(buf) < buf->size / 4)
+ if (buffer_free_space(buf) < buf->size / 4)
return 1;
return 0;
}
diff --git a/src/buffers.c b/src/buffers.c
index 2557fe4..c128bb9 100644
--- a/src/buffers.c
+++ b/src/buffers.c
@@ -86,19 +86,24 @@
if (len == 0)
return -1;
- if (len > buffer_max_len(buf)) {
- /* we can't write this chunk and will never be able to, because
- * it is larger than the buffer's current max size.
+ max = buffer_max_len(buf);
+ if (len > max - buf->l) {
+ /* we can't write this chunk right now because the buffer is
+ * almost full or because the block is too large. Return the
+ * available space or -2 if impossible.
*/
- return -2;
- }
+ if (len > max)
+ return -2;
- max = buffer_contig_space(buf);
+ return max - buf->l;
+ }
+ /* OK so the data fits in the buffer in one or two blocks */
+ max = buffer_contig_space_with_len(buf, max);
+ memcpy(buf->r, str, MIN(len, max));
if (len > max)
- return max;
+ memcpy(buf->data, str + max, len - max);
- memcpy(buf->r, str, len);
buf->l += len;
buf->r += len;
buf->total += len;
@@ -113,8 +118,8 @@
buf->flags &= ~BF_OUT_EMPTY;
}
- if (buf->r == buf->data + buf->size)
- buf->r = buf->data;
+ if (buf->r >= buf->data + buf->size)
+ buf->r -= buf->size;
buf->flags &= ~BF_FULL;
if (buf->l >= buffer_max_len(buf))