Rework bufchain code to allow for variable-sized granules.
authorben <ben@cda61777-01e9-0310-a592-d414129be87e>
Sat, 11 Aug 2012 09:10:31 +0000 (09:10 +0000)
committerben <ben@cda61777-01e9-0310-a592-d414129be87e>
Sat, 11 Aug 2012 09:10:31 +0000 (09:10 +0000)
bufchain_add() now allocates at most one new granule.  Granules still
have a minimum size, so small adds still get coalesced.

The main practical consequence of this is that PSCP and PSFTP now
generate 4K SSH packets rather than 512-byte ones.  Also, the compiled
code (on my Ubuntu box) is fractionally smaller.

git-svn-id: svn://svn.tartarus.org/sgt/putty@9602 cda61777-01e9-0310-a592-d414129be87e

misc.c

diff --git a/misc.c b/misc.c
index 76e5fab..054b793 100644 (file)
--- a/misc.c
+++ b/misc.c
@@ -364,12 +364,11 @@ void base64_encode_atom(unsigned char *data, int n, char *out)
  *  - return the current size of the buffer chain in bytes
  */
 
-#define BUFFER_GRANULE  512
+#define BUFFER_MIN_GRANULE  512
 
 struct bufchain_granule {
     struct bufchain_granule *next;
-    int buflen, bufpos;
-    char buf[BUFFER_GRANULE];
+    char *bufpos, *bufend, *bufmax;
 };
 
 void bufchain_init(bufchain *ch)
@@ -403,28 +402,29 @@ void bufchain_add(bufchain *ch, const void *data, int len)
 
     ch->buffersize += len;
 
-    if (ch->tail && ch->tail->buflen < BUFFER_GRANULE) {
-       int copylen = min(len, BUFFER_GRANULE - ch->tail->buflen);
-       memcpy(ch->tail->buf + ch->tail->buflen, buf, copylen);
-       buf += copylen;
-       len -= copylen;
-       ch->tail->buflen += copylen;
-    }
     while (len > 0) {
-       int grainlen = min(len, BUFFER_GRANULE);
-       struct bufchain_granule *newbuf;
-       newbuf = snew(struct bufchain_granule);
-       newbuf->bufpos = 0;
-       newbuf->buflen = grainlen;
-       memcpy(newbuf->buf, buf, grainlen);
-       buf += grainlen;
-       len -= grainlen;
-       if (ch->tail)
-           ch->tail->next = newbuf;
-       else
-           ch->head = ch->tail = newbuf;
-       newbuf->next = NULL;
-       ch->tail = newbuf;
+       if (ch->tail && ch->tail->bufend < ch->tail->bufmax) {
+           int copylen = min(len, ch->tail->bufmax - ch->tail->bufend);
+           memcpy(ch->tail->bufend, buf, copylen);
+           buf += copylen;
+           len -= copylen;
+           ch->tail->bufend += copylen;
+       }
+       if (len > 0) {
+           int grainlen =
+               max(sizeof(struct bufchain_granule) + len, BUFFER_MIN_GRANULE);
+           struct bufchain_granule *newbuf;
+           newbuf = smalloc(grainlen);
+           newbuf->bufpos = newbuf->bufend =
+               (char *)newbuf + sizeof(struct bufchain_granule);
+           newbuf->bufmax = (char *)newbuf + grainlen;
+           newbuf->next = NULL;
+           if (ch->tail)
+               ch->tail->next = newbuf;
+           else
+               ch->head = newbuf;
+           ch->tail = newbuf;
+       }
     }
 }
 
@@ -436,13 +436,13 @@ void bufchain_consume(bufchain *ch, int len)
     while (len > 0) {
        int remlen = len;
        assert(ch->head != NULL);
-       if (remlen >= ch->head->buflen - ch->head->bufpos) {
-           remlen = ch->head->buflen - ch->head->bufpos;
+       if (remlen >= ch->head->bufend - ch->head->bufpos) {
+           remlen = ch->head->bufend - ch->head->bufpos;
            tmp = ch->head;
            ch->head = tmp->next;
-           sfree(tmp);
            if (!ch->head)
                ch->tail = NULL;
+           sfree(tmp);
        } else
            ch->head->bufpos += remlen;
        ch->buffersize -= remlen;
@@ -452,8 +452,8 @@ void bufchain_consume(bufchain *ch, int len)
 
 void bufchain_prefix(bufchain *ch, void **data, int *len)
 {
-    *len = ch->head->buflen - ch->head->bufpos;
-    *data = ch->head->buf + ch->head->bufpos;
+    *len = ch->head->bufend - ch->head->bufpos;
+    *data = ch->head->bufpos;
 }
 
 void bufchain_fetch(bufchain *ch, void *data, int len)
@@ -468,9 +468,9 @@ void bufchain_fetch(bufchain *ch, void *data, int len)
        int remlen = len;
 
        assert(tmp != NULL);
-       if (remlen >= tmp->buflen - tmp->bufpos)
-           remlen = tmp->buflen - tmp->bufpos;
-       memcpy(data_c, tmp->buf + tmp->bufpos, remlen);
+       if (remlen >= tmp->bufend - tmp->bufpos)
+           remlen = tmp->bufend - tmp->bufpos;
+       memcpy(data_c, tmp->bufpos, remlen);
 
        tmp = tmp->next;
        len -= remlen;