[master] 39e2405 improve the vbm facility, rename former vbit_init to vbit_new

Nils Goroll nils.goroll at uplex.de
Thu Mar 3 14:46:00 CET 2016


commit 39e2405bb04317c893726f38d43676570a1bdf1a
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Thu Mar 3 14:35:28 2016 +0100

    improve the vbm facility, rename former vbit_init to vbit_new
    
    vbit_init now initializes a vbitmap from an arbitrary memory extent.
    If more bits are used than the extent provided, auto-sizing falls
    back to malloc, so vbit_destroy() should still be used.
    
    adding a test program

diff --git a/.gitignore b/.gitignore
index 0cfaa04..fb9cde6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -57,6 +57,9 @@ cscope.*out
 /include/tbl/vrt_stv_var.h
 /include/tbl/vcc_types.h
 /include/vcs_version.h
+/include/vbm_test
+/include/vbm_test.log
+/include/test-suite.log
 /lib/libvcc/vcc_fixed_token.c
 /lib/libvcc/vcc_obj.c
 /lib/libvcc/vcc_token_defs.h
diff --git a/bin/varnishd/mgt/mgt_child.c b/bin/varnishd/mgt/mgt_child.c
index 1673169..3aee527 100644
--- a/bin/varnishd/mgt/mgt_child.c
+++ b/bin/varnishd/mgt/mgt_child.c
@@ -206,7 +206,7 @@ mgt_child_inherit(int fd, const char *what)
 
 	assert(fd >= 0);
 	if (fd_map == NULL)
-		fd_map = vbit_init(128);
+		fd_map = vbit_new(128);
 	AN(fd_map);
 	if (what != NULL)
 		vbit_set(fd_map, fd);
diff --git a/include/Makefile.am b/include/Makefile.am
index ced33c8..816e416 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -152,3 +152,12 @@ CLEANFILES = \
 	vcl.h \
 	vrt_obj.h \
 	vmod_abi.h
+
+TESTS = vbm_test
+
+noinst_PROGRAMS = ${TESTS}
+
+vbm_test_SOURCES = vbm_test.c vbm.h
+
+test: ${TESTS}
+	@for test in ${TESTS} ; do ./$${test} ; done
diff --git a/include/vbm.h b/include/vbm.h
index 984a3ea..94497ab 100644
--- a/include/vbm.h
+++ b/include/vbm.h
@@ -29,17 +29,33 @@
  * Self-sizeing bitmap operations
  */
 
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
 /**********************************************************************
- * Generic bitmap functions, may be generalized at some point.
+ * Generic bitmap functions
  */
 
 #define VBITMAP_TYPE	unsigned	/* Our preferred wordsize */
 #define VBITMAP_LUMP	(1024)		/* How many bits we alloc at a time */
 #define VBITMAP_WORD	(sizeof(VBITMAP_TYPE) * 8)
-#define VBITMAP_IDX(n)	(n / VBITMAP_WORD)
-#define VBITMAP_BIT(n)	(1U << (n % VBITMAP_WORD))
+#define VBITMAP_IDX(n)	((n) / VBITMAP_WORD)
+#define VBITMAP_BIT(n)	(1U << ((n) % VBITMAP_WORD))
+
+static inline unsigned
+vbit_rndup(unsigned bit, unsigned to) {
+	bit += to - 1;
+	bit -= (bit % to);
+
+	return (bit);
+}
 
 struct vbitmap {
+	unsigned	flags;
+#define VBITMAP_FL_MALLOC	 1	/* struct vbitmap is malloced */
+#define VBITMAP_FL_MALLOC_BITS	(1<<1)	/* bits space is malloced */
+
 	VBITMAP_TYPE	*bits;
 	unsigned	nbits;
 };
@@ -49,22 +65,64 @@ vbit_expand(struct vbitmap *vb, unsigned bit)
 {
 	unsigned char *p;
 
-	bit += VBITMAP_LUMP - 1;
-	bit -= (bit % VBITMAP_LUMP);
-	p = realloc(vb->bits, bit / 8);
-	assert(p != NULL);
+	bit = vbit_rndup(bit, VBITMAP_LUMP);
+	assert(bit > vb->nbits);
+
+	if (vb->flags & VBITMAP_FL_MALLOC_BITS) {
+		p = realloc(vb->bits, bit / 8);
+		assert(p != NULL);
+	} else {
+		p = malloc(bit / 8);
+		assert(p != NULL);
+		if (vb->nbits > 0)
+			memcpy(p, vb->bits, vb->nbits / 8);
+	}
 	memset(p + vb->nbits / 8, 0, (bit - vb->nbits) / 8);
+	vb->flags |= VBITMAP_FL_MALLOC_BITS;
 	vb->bits = (void*)p;
 	vb->nbits = bit;
 }
 
+#define VBITMAP_SZ(b) (sizeof(struct vbitmap) + \
+	vbit_rndup(b, VBITMAP_WORD))
+
+/*
+ * init from some extent of memory (e.g. workspace) which the caller must
+ * manage. Returns a vbitmap with as many bits as fit into sz in VBITMAP_WORD
+ * chunks.
+ *
+ * use VBITMAP_SZ to calculate sz
+ */
+static inline struct vbitmap *
+vbit_init(void *p, size_t sz)
+{
+	struct vbitmap *vb;
+
+	if (sz < sizeof(*vb))
+		return NULL;
+
+	memset(p, 0, sz);
+	vb = p;
+
+	p = (char *)p + sizeof(*vb);
+	sz -= sizeof(*vb);
+
+	vb->nbits = (sz / VBITMAP_WORD) * VBITMAP_WORD;
+	if (vb->nbits)
+		vb->bits = p;
+
+	return (vb);
+}
+
+/* init using malloc */
 static inline struct vbitmap *
-vbit_init(unsigned initial)
+vbit_new(unsigned initial)
 {
 	struct vbitmap *vb;
 
 	vb = calloc(sizeof *vb, 1);
 	assert(vb != NULL);
+	vb->flags |= VBITMAP_FL_MALLOC;
 	if (initial == 0)
 		initial = VBITMAP_LUMP;
 	vbit_expand(vb, initial);
@@ -77,8 +135,13 @@ vbit_destroy(struct vbitmap *vb)
 
 	if (vb == NULL)
 		return;
-	free(vb->bits);
-	free(vb);
+	if (vb->flags & VBITMAP_FL_MALLOC_BITS) {
+		free(vb->bits);
+		vb->bits = NULL;
+		vb->nbits = 0;
+	}
+	if (vb->flags & VBITMAP_FL_MALLOC)
+		free(vb);
 }
 
 static inline void
diff --git a/include/vbm_test.c b/include/vbm_test.c
new file mode 100644
index 0000000..f680597
--- /dev/null
+++ b/include/vbm_test.c
@@ -0,0 +1,92 @@
+/*-
+ * Copyright 2016 UPLEX - Nils Goroll Systemoptimierung
+ * All rights reserved.
+ *
+ * Author: Nils Goroll <nils.goroll at uplex.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Test Self-sizeing bitmap operations static initialization with dynamic growth
+ */
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "vbm.h"
+
+int
+main(void)
+{
+
+	const unsigned sz = VBITMAP_SZ(1);
+	char spc[sz];
+	struct vbitmap *vb = vbit_init(spc, sz);
+
+	VBITMAP_TYPE	*obits;
+	unsigned	nbits;
+
+	assert(vb);
+	obits = vb->bits;
+	nbits = vb->nbits;
+	assert(nbits == VBITMAP_WORD);
+
+	vbit_set(vb, nbits - 1);
+	assert(vbit_test(vb, nbits - 1));
+
+	assert(vb->bits);
+	/* nothing malloc'ed - null ops */
+	vbit_destroy(vb);
+	assert(vb->bits);
+	assert(vb->bits == obits);
+
+	/* re-alloc */
+	vbit_set(vb, nbits);
+	assert(vbit_test(vb, nbits - 1));
+	assert(vbit_test(vb, nbits));
+	assert(vb->nbits == VBITMAP_LUMP);
+	assert(vb->bits != obits);
+	assert(vb->flags & VBITMAP_FL_MALLOC_BITS);
+
+	assert(vb->bits);
+	/* free the bits */
+	vbit_destroy(vb);
+	assert(vb->bits == NULL);
+	assert(vb->nbits == 0);
+
+	/* use again */
+	assert(20 < VBITMAP_LUMP);
+	vbit_set(vb, 20);
+	assert(vbit_test(vb, 20));
+	assert(vb->nbits == VBITMAP_LUMP);
+	assert(vb->flags & VBITMAP_FL_MALLOC_BITS);
+
+	/* grow */
+	vbit_set(vb, VBITMAP_LUMP);
+	assert(vbit_test(vb, 20));
+	assert(vbit_test(vb, VBITMAP_LUMP));
+	assert(vb->nbits == 2 * VBITMAP_LUMP);
+	assert(vb->flags & VBITMAP_FL_MALLOC_BITS);
+
+	vbit_destroy(vb);
+
+	return (0);
+}
diff --git a/lib/libvarnishapi/vsl.c b/lib/libvarnishapi/vsl.c
index 2bd801c..1efc453 100644
--- a/lib/libvarnishapi/vsl.c
+++ b/lib/libvarnishapi/vsl.c
@@ -101,8 +101,8 @@ VSL_New(void)
 
 	vsl->L_opt = 1000;
 	vsl->T_opt = 120.;
-	vsl->vbm_select = vbit_init(SLT__MAX);
-	vsl->vbm_supress = vbit_init(SLT__MAX);
+	vsl->vbm_select = vbit_new(SLT__MAX);
+	vsl->vbm_supress = vbit_new(SLT__MAX);
 	VTAILQ_INIT(&vsl->vslf_select);
 	VTAILQ_INIT(&vsl->vslf_suppress);
 
diff --git a/lib/libvarnishapi/vsl_arg.c b/lib/libvarnishapi/vsl_arg.c
index cc14e94..89ab29d 100644
--- a/lib/libvarnishapi/vsl_arg.c
+++ b/lib/libvarnishapi/vsl_arg.c
@@ -270,7 +270,7 @@ vsl_IX_arg(struct VSL_data *vsl, int opt, const char *arg)
 	b = arg;
 	e = strchr(b, ':');
 	if (e) {
-		tags = vbit_init(SLT__MAX);
+		tags = vbit_new(SLT__MAX);
 		AN(tags);
 		l = e - b;
 		i = VSL_List2Tags(b, l, vsl_vbm_bitset, tags);
diff --git a/lib/libvarnishapi/vxp_parse.c b/lib/libvarnishapi/vxp_parse.c
index 7ec8865..7ec0d4f 100644
--- a/lib/libvarnishapi/vxp_parse.c
+++ b/lib/libvarnishapi/vxp_parse.c
@@ -75,7 +75,7 @@ vxp_expr_lhs(struct vxp *vxp, struct vex_lhs **plhs)
 	AZ(*plhs);
 	ALLOC_OBJ(*plhs, VEX_LHS_MAGIC);
 	AN(*plhs);
-	(*plhs)->tags = vbit_init(SLT__MAX);
+	(*plhs)->tags = vbit_new(SLT__MAX);
 	(*plhs)->level = -1;
 
 	if (vxp->t->tok == '{') {
diff --git a/lib/libvmod_directors/vdir.c b/lib/libvmod_directors/vdir.c
index 22dfee3..15dd56a 100644
--- a/lib/libvmod_directors/vdir.c
+++ b/lib/libvmod_directors/vdir.c
@@ -72,7 +72,7 @@ vdir_new(struct vdir **vdp, const char *name, const char *vcl_name,
 	vd->dir->priv = priv;
 	vd->dir->healthy = healthy;
 	vd->dir->resolve = resolve;
-	vd->vbm = vbit_init(8);
+	vd->vbm = vbit_new(8);
 	AN(vd->vbm);
 }
 



More information about the varnish-commit mailing list