[master] 2811421 Move much closer to FreeBSD current sbuf implementation.

Poul-Henning Kamp phk at varnish-cache.org
Mon Apr 4 16:05:25 CEST 2011


commit 2811421b19c5fbbdf8f7c3b4fa9cd1263962df6e
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Mon Apr 4 13:52:25 2011 +0000

    Move much closer to FreeBSD current sbuf implementation.

diff --git a/include/vsb.h b/include/vsb.h
index db65eae..0ab0ee1 100644
--- a/include/vsb.h
+++ b/include/vsb.h
@@ -37,14 +37,14 @@
 struct vsb {
 	unsigned	s_magic;
 	char		*s_buf;		/* storage buffer */
-	size_t		 s_size;	/* size of storage buffer */
-	size_t		 s_len;		/* current length of string */
+	ssize_t		 s_size;	/* size of storage buffer */
+	ssize_t		 s_len;		/* current length of string */
+	int		 s_error;	/* current error code */
 #define	VSB_FIXEDLEN	0x00000000	/* fixed length buffer (default) */
 #define	VSB_AUTOEXTEND	0x00000001	/* automatically extend buffer */
 #define	VSB_USRFLAGMSK 0x0000ffff	/* mask of flags the user may specify */
 #define	VSB_DYNAMIC	0x00010000	/* s_buf must be freed */
 #define	VSB_FINISHED	0x00020000	/* set by vsb_finish() */
-#define	VSB_OVERFLOWED	0x00040000	/* vsb overflowed */
 #define	VSB_DYNSTRUCT	0x00080000	/* vsb must be freed */
 	int		 s_flags;	/* flags */
 };
diff --git a/lib/libvarnish/vsb.c b/lib/libvarnish/vsb.c
index 28333eb..bfe9735 100644
--- a/lib/libvarnish/vsb.c
+++ b/lib/libvarnish/vsb.c
@@ -46,6 +46,9 @@ SVNID("$Id$")
 #define	SBFREE(buf)		free(buf)
 #define	min(x,y)		(x < y ? x : y)
 
+// #define bzero(x,y)		memset(x,0,y)
+#define	roundup2(x, y)	(((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
+
 #define VSB_MAGIC		0x4a82dd8a
 /*
  * Predicates
@@ -53,7 +56,6 @@ SVNID("$Id$")
 #define	VSB_ISDYNAMIC(s)	((s)->s_flags & VSB_DYNAMIC)
 #define	VSB_ISDYNSTRUCT(s)	((s)->s_flags & VSB_DYNSTRUCT)
 #define	VSB_ISFINISHED(s)	((s)->s_flags & VSB_FINISHED)
-#define	VSB_HASOVERFLOWED(s)	((s)->s_flags & VSB_OVERFLOWED)
 #define	VSB_HASROOM(s)		((s)->s_len < (s)->s_size - 1)
 #define	VSB_FREESPACE(s)	((s)->s_size - ((s)->s_len + 1))
 #define	VSB_CANEXTEND(s)	((s)->s_flags & VSB_AUTOEXTEND)
@@ -111,13 +113,14 @@ vsb_extendsize(int size)
 {
 	int newsize;
 
-	newsize = VSB_MINEXTENDSIZE;
-	while (newsize < size) {
-		if (newsize < (int)VSB_MAXEXTENDSIZE)
+	if (size < (int)VSB_MAXEXTENDSIZE) {
+		newsize = VSB_MINEXTENDSIZE;
+		while (newsize < size)
 			newsize *= 2;
-		else
-			newsize += VSB_MAXEXTENDINCR;
+	} else {
+		newsize = roundup2(size, VSB_MAXEXTENDINCR);
 	}
+	KASSERT(newsize >= size, ("%s: %d < %d\n", __func__, newsize, size));
 	return (newsize);
 }
 
@@ -166,17 +169,21 @@ vsb_new(struct vsb *s, char *buf, int length, int flags)
 		s = SBMALLOC(sizeof(*s));
 		if (s == NULL)
 			return (NULL);
-		flags |= VSB_DYNSTRUCT;
+		bzero(s, sizeof(*s));
+		s->s_flags = flags;
+		VSB_SETFLAG(s, VSB_DYNSTRUCT);
+	} else {
+		bzero(s, sizeof(*s));
+		s->s_flags = flags;
 	}
-	memset(s, 0, sizeof *s);
-	s->s_flags = flags;
+		
 	s->s_magic = VSB_MAGIC;
 	s->s_size = length;
-	if (buf) {
+	if (buf != NULL) {
 		s->s_buf = buf;
 		return (s);
 	}
-	if (flags & VSB_AUTOEXTEND)
+	if ((flags & VSB_AUTOEXTEND) != 0)
 		s->s_size = vsb_extendsize(s->s_size);
 	s->s_buf = SBMALLOC(s->s_size);
 	if (s->s_buf == NULL) {
@@ -199,7 +206,7 @@ vsb_clear(struct vsb *s)
 	/* don't care if it's finished or not */
 
 	VSB_CLEARFLAG(s, VSB_FINISHED);
-	VSB_CLEARFLAG(s, VSB_OVERFLOWED);
+	s->s_error = 0;
 	s->s_len = 0;
 }
 
@@ -226,26 +233,47 @@ vsb_setpos(struct vsb *s, int pos)
 }
 
 /*
+ * Append a byte to an vsb.  This is the core function for appending
+ * to an vsb and is the main place that deals with extending the
+ * buffer and marking overflow.
+ */
+static void
+vsb_put_byte(int c, struct vsb *s)
+{
+
+	assert_vsb_integrity(s);
+	assert_vsb_state(s, 0);
+
+	if (s->s_error != 0)
+		return;
+	if (VSB_FREESPACE(s) <= 0) {
+		if (vsb_extend(s, 1) < 0)
+			s->s_error = ENOMEM;
+		if (s->s_error != 0)
+			return;
+	}
+	s->s_buf[s->s_len++] = c;
+}
+
+
+/*
  * Append a byte string to an vsb.
  */
 int
 vsb_bcat(struct vsb *s, const void *buf, size_t len)
 {
 	const char *str = buf;
+	const char *end = str + len;
 
 	assert_vsb_integrity(s);
 	assert_vsb_state(s, 0);
 
-	if (VSB_HASOVERFLOWED(s))
-		return (-1);
-	for (; len; len--) {
-		if (!VSB_HASROOM(s) && vsb_extend(s, len) < 0)
-			break;
-		s->s_buf[s->s_len++] = *str++;
-	}
-	if (len) {
-		VSB_SETFLAG(s, VSB_OVERFLOWED);
+	if (s->s_error != 0)
 		return (-1);
+	for (; str < end; str++) {
+		vsb_put_byte(*str, s);
+		if (s->s_error != 0)
+			return (-1);
 	}
 	return (0);
 }
@@ -274,17 +302,13 @@ vsb_cat(struct vsb *s, const char *str)
 	assert_vsb_integrity(s);
 	assert_vsb_state(s, 0);
 
-	if (VSB_HASOVERFLOWED(s))
+	if (s->s_error != 0)
 		return (-1);
 
-	while (*str) {
-		if (!VSB_HASROOM(s) && vsb_extend(s, strlen(str)) < 0)
-			break;
-		s->s_buf[s->s_len++] = *str++;
-	}
-	if (*str) {
-		VSB_SETFLAG(s, VSB_OVERFLOWED);
-		return (-1);
+	while (*str != '\0') {
+		vsb_put_byte(*str++, s);
+		if (s->s_error != 0)
+			return (-1);
 	}
 	return (0);
 }
@@ -318,7 +342,7 @@ vsb_vprintf(struct vsb *s, const char *fmt, va_list ap)
 	KASSERT(fmt != NULL,
 	    ("%s called with a NULL format string", __func__));
 
-	if (VSB_HASOVERFLOWED(s))
+	if (s->s_error != 0)
 		return (-1);
 
 	do {
@@ -336,16 +360,18 @@ vsb_vprintf(struct vsb *s, const char *fmt, va_list ap)
 	 * terminating nul.
 	 *
 	 * vsnprintf() returns the amount that would have been copied,
-	 * given sufficient space, hence the min() calculation below.
+	 * given sufficient space, so don't over-increment s_len.
 	 */
-	s->s_len += min(len, VSB_FREESPACE(s));
+	if (VSB_FREESPACE(s) < len)
+		len = VSB_FREESPACE(s);
+	s->s_len += len;
 	if (!VSB_HASROOM(s) && !VSB_CANEXTEND(s))
-		VSB_SETFLAG(s, VSB_OVERFLOWED);
+		s->s_error = ENOMEM;
 
 	KASSERT(s->s_len < s->s_size,
 	    ("wrote past end of vsb (%d >= %d)", s->s_len, s->s_size));
 
-	if (VSB_HASOVERFLOWED(s))
+	if (s->s_error != 0)
 		return (-1);
 	return (0);
 }
@@ -362,7 +388,7 @@ vsb_printf(struct vsb *s, const char *fmt, ...)
 	va_start(ap, fmt);
 	result = vsb_vprintf(s, fmt, ap);
 	va_end(ap);
-	return(result);
+	return (result);
 }
 
 /*
@@ -372,17 +398,9 @@ int
 vsb_putc(struct vsb *s, int c)
 {
 
-	assert_vsb_integrity(s);
-	assert_vsb_state(s, 0);
-
-	if (VSB_HASOVERFLOWED(s))
+	vsb_put_byte(c, s);
+	if (s->s_error != 0)
 		return (-1);
-	if (!VSB_HASROOM(s) && vsb_extend(s, 1) < 0) {
-		VSB_SETFLAG(s, VSB_OVERFLOWED);
-		return (-1);
-	}
-	if (c != '\0')
-		s->s_buf[s->s_len++] = (char)c;
 	return (0);
 }
 
@@ -396,23 +414,23 @@ vsb_trim(struct vsb *s)
 	assert_vsb_integrity(s);
 	assert_vsb_state(s, 0);
 
-	if (VSB_HASOVERFLOWED(s))
+	if (s->s_error != 0)
 		return (-1);
 
-	while (s->s_len && isspace(s->s_buf[s->s_len-1]))
+	while (s->s_len > 0 && isspace(s->s_buf[s->s_len-1]))
 		--s->s_len;
 
 	return (0);
 }
 
 /*
- * Check if an vsb overflowed
+ * Check if an vsb has an error.
  */
 int
 vsb_error(const struct vsb *s)
 {
 
-	return (VSB_HASOVERFLOWED(s));
+	return (s->s_error);
 }
 
 /*
@@ -426,8 +444,10 @@ vsb_finish(struct vsb *s)
 	assert_vsb_state(s, 0);
 
 	s->s_buf[s->s_len] = '\0';
-	VSB_CLEARFLAG(s, VSB_OVERFLOWED);
 	VSB_SETFLAG(s, VSB_FINISHED);
+	errno = s->s_error;
+	if (s->s_error)
+		return (-1);
 	return (0);
 }
 
@@ -454,7 +474,7 @@ vsb_len(struct vsb *s)
 	assert_vsb_integrity(s);
 	/* don't care if it's finished or not */
 
-	if (VSB_HASOVERFLOWED(s))
+	if (s->s_error != 0)
 		return (-1);
 	return (s->s_len);
 }
@@ -473,7 +493,7 @@ vsb_delete(struct vsb *s)
 	if (VSB_ISDYNAMIC(s))
 		SBFREE(s->s_buf);
 	isdyn = VSB_ISDYNSTRUCT(s);
-	memset(s, 0, sizeof *s);
+	bzero(s, sizeof(*s));
 	if (isdyn)
 		SBFREE(s);
 }



More information about the varnish-commit mailing list