At present the membuf implementation wastes a slot in the fifo so it can
detect the difference between a full and an empty buffer.

Add the option of supporting a boolean flag, if desired. For now it is
off.

The code-size penalty is non-zero, but the space penalty is small and
could be reduced on 64-bit machines by using a u32 offset for head and
tail.

Signed-off-by: Simon Glass <s...@chromium.org>
---

 include/membuf.h  |  6 +++++
 lib/membuf.c      | 63 ++++++++++++++++++++++++++++++++++++++---------
 test/lib/membuf.c | 11 ++++++---
 3 files changed, 65 insertions(+), 15 deletions(-)

diff --git a/include/membuf.h b/include/membuf.h
index 46764690f53..b495a72652b 100644
--- a/include/membuf.h
+++ b/include/membuf.h
@@ -11,6 +11,9 @@
 
 #include <stdbool.h>
 
+/* Set this to 1 to support a 'full' flag */
+#define MEMBUF_FULL    0
+
 /**
  * @struct membuf: holds the state of a membuff - it is used for input and
  * output buffers. The buffer extends from @start to (@start + @size - 1).
@@ -36,6 +39,9 @@ struct membuf {
        char *end;              /** the end of the buffer (start + length) */
        char *head;             /** current buffer head */
        char *tail;             /** current buffer tail */
+#if MEMBUF_FULL
+       bool full;              /** true if full (for when head == tail) */
+#endif
 };
 
 /**
diff --git a/lib/membuf.c b/lib/membuf.c
index f38ff36cb0b..016430ae988 100644
--- a/lib/membuf.c
+++ b/lib/membuf.c
@@ -11,11 +11,28 @@
 #include <malloc.h>
 #include "membuf.h"
 
+static inline bool is_full(const struct membuf *mb)
+{
+#if MEMBUF_FULL
+       return mb->full;
+#else
+       return false;
+#endif
+}
+
+static inline void set_full(struct membuf *mb, bool full)
+{
+#if MEMBUF_FULL
+       mb->full = full;
+#endif
+}
+
 void membuf_purge(struct membuf *mb)
 {
        /* set mb->head and mb->tail so the buffers look empty */
        mb->head = mb->start;
        mb->tail = mb->start;
+       set_full(mb, false);
 }
 
 static int membuf_putrawflex(struct membuf *mb, int maxlen, bool update,
@@ -36,21 +53,29 @@ static int membuf_putrawflex(struct membuf *mb, int maxlen, 
bool update,
         * if head is ahead of tail, we can write from head until the end of
         * the buffer
         */
-       if (mb->head >= mb->tail) {
+       if (mb->head >= mb->tail && !is_full(mb)) {
                /* work out how many bytes can fit here */
-               len = mb->end - mb->head - 1;
+               len = mb->end - mb->head;
+               if (!MEMBUF_FULL)
+                       len--;
                if (maxlen >= 0 && len > maxlen)
                        len = maxlen;
 
                /* update the head pointer to mark these bytes as written */
-               if (update)
+               if (update) {
                        mb->head += len;
+                       if (mb->head == mb->end)
+                               mb->head = mb->start;
+                       if (len && mb->head == mb->tail)
+                               set_full(mb, true);
+               }
 
                /*
                 * if the tail isn't at start of the buffer, then we can
                 * write one more byte right at the end
                 */
-               if ((maxlen < 0 || len < maxlen) && mb->tail != mb->start) {
+               if (!MEMBUF_FULL && (maxlen < 0 || len < maxlen) &&
+                   mb->tail != mb->start) {
                        len++;
                        if (update)
                                mb->head = mb->start;
@@ -59,13 +84,18 @@ static int membuf_putrawflex(struct membuf *mb, int maxlen, 
bool update,
        /* otherwise now we can write until head almost reaches tail */
        } else {
                /* work out how many bytes can fit here */
-               len = mb->tail - mb->head - 1;
+               len = mb->tail - mb->head;
+               if (!MEMBUF_FULL)
+                       len--;
                if (maxlen >= 0 && len > maxlen)
                        len = maxlen;
 
                /* update the head pointer to mark these bytes as written */
-               if (update)
+               if (update) {
                        mb->head += len;
+                       if (MEMBUF_FULL && len && mb->head == mb->tail)
+                               set_full(mb, true);
+               }
        }
 
        /* return the number of bytes which can be/must be written */
@@ -125,7 +155,7 @@ int membuf_getraw(struct membuf *mb, int maxlen, bool 
update, char **data)
         * and some more data between 'start' and 'head'(which we can't
         * return this time
         */
-       else if (mb->head < mb->tail) {
+       else if (is_full(mb) || mb->head < mb->tail) {
                /* work out the amount of data */
                *data = mb->tail;
                len = mb->end - mb->tail;
@@ -135,6 +165,8 @@ int membuf_getraw(struct membuf *mb, int maxlen, bool 
update, char **data)
                        mb->tail += len;
                        if (mb->tail == mb->end)
                                mb->tail = mb->start;
+                       if (len)
+                               set_full(mb, false);
                }
        }
 
@@ -205,7 +237,7 @@ int membuf_put(struct membuf *mb, const char *buff, int 
length)
 
 bool membuf_isempty(struct membuf *mb)
 {
-       return mb->head == mb->tail;
+       return !is_full(mb) && mb->head == mb->tail;
 }
 
 int membuf_avail(struct membuf *mb)
@@ -230,6 +262,9 @@ int membuf_size(struct membuf *mb)
        return mb->end - mb->start;
 }
 
+#if MEMBUF_FULL == 0
+/* This has not been updated for MEMBUF_FULL */
+
 bool membuf_makecontig(struct membuf *mb)
 {
        int topsize, botsize;
@@ -280,11 +315,12 @@ bool membuf_makecontig(struct membuf *mb)
        /* all ok */
        return true;
 }
+#endif
 
 int membuf_free(struct membuf *mb)
 {
        return mb->end == mb->start ? 0 :
-                       (mb->end - mb->start) - 1 - membuf_avail(mb);
+               (mb->end - mb->start) - MEMBUF_FULL - membuf_avail(mb);
 }
 
 int membuf_readline(struct membuf *mb, char *str, int maxlen, int minch,
@@ -295,7 +331,7 @@ int membuf_readline(struct membuf *mb, char *str, int 
maxlen, int minch,
        bool ok = false;
        char *orig = str;
 
-       end = mb->head >= mb->tail ? mb->head : mb->end;
+       end = mb->head < mb->tail || is_full(mb) ? mb->end : mb->head;
        for (len = 0, s = mb->tail; s < end && len < maxlen - 1; str++) {
                *str = *s++;
                len++;
@@ -303,7 +339,7 @@ int membuf_readline(struct membuf *mb, char *str, int 
maxlen, int minch,
                        ok = true;
                        break;
                }
-               if (s == end && mb->tail > mb->head) {
+               if (s == end && (is_full(mb) || mb->tail > mb->head)) {
                        s = mb->start;
                        end = mb->head;
                }
@@ -319,6 +355,8 @@ int membuf_readline(struct membuf *mb, char *str, int 
maxlen, int minch,
        /* terminate the string, update the membuff and return success */
        *str = '\0';
        mb->tail = s == mb->end ? mb->start : s;
+       if (len)
+               set_full(mb, false);
 
        return len;
 }
@@ -350,9 +388,10 @@ int membuf_extend_by(struct membuf *mb, int by, int max)
        mb->head = mb->start + oldhead;
        mb->tail = mb->start + oldtail;
 
-       if (mb->head < mb->tail) {
+       if (is_full(mb) || mb->head < mb->tail) {
                memmove(mb->tail + by, mb->tail, orig - oldtail);
                mb->tail += by;
+               set_full(mb, false);
        }
        mb->end = mb->start + size;
 
diff --git a/test/lib/membuf.c b/test/lib/membuf.c
index 3f268a422d5..f36332ff7b6 100644
--- a/test/lib/membuf.c
+++ b/test/lib/membuf.c
@@ -23,6 +23,11 @@ static void membuf_zero(struct membuf *mb)
 static int membuf_check(struct unit_test_state *uts, struct membuf *mb,
                        int value)
 {
+       /* says it is full, but can't be */
+#if MEMBUF_FULL
+       ut_assert(!(mb->full && mb->head != mb->tail));
+#endif
+
        /* head is out of range */
        ut_assert(!(mb->head < mb->start || mb->head >= mb->end));
 
@@ -47,7 +52,7 @@ static int lib_test_membuf_one(struct unit_test_state *uts)
                in[i + TEST_SIZE] = in[i];
        }
 
-       test_size = TEST_SIZE;
+       test_size = TEST_SIZE + MEMBUF_FULL;
 
        for (i = 1; i < TEST_COUNT; i++) {
                membuf_zero(&mb);
@@ -92,7 +97,7 @@ static int lib_test_membuf_random(struct unit_test_state *uts)
                in[i + TEST_SIZE] = in[i];
        }
 
-       test_size = TEST_SIZE;
+       test_size = TEST_SIZE + MEMBUF_FULL;
 
        inptr = in;
        outptr = in;
@@ -145,7 +150,7 @@ static int lib_test_membuf_extend(struct unit_test_state 
*uts)
                in[i + TEST_SIZE] = in[i];
        }
 
-       test_size = TEST_SIZE - 1;
+       test_size = TEST_SIZE - 1 + MEMBUF_FULL;
 
        for (cur = 0; cur <= test_size; cur++) {
                ut_assertok(membuf_new(&mb, TEST_SIZE));
-- 
2.34.1

Reply via email to