[master] 4037d75 Introduce barriers in varnishtest

Dridi Boukelmoune dridi.boukelmoune at gmail.com
Tue Mar 29 14:20:05 CEST 2016


commit 4037d75855826aa6b86dec2266858334cb23fca5
Author: Dridi Boukelmoune <dridi.boukelmoune at gmail.com>
Date:   Tue Dec 22 18:16:08 2015 +0100

    Introduce barriers in varnishtest
    
    They work like semaphores, except that they need explicit initialization
    and can optionally be shared between processes.

diff --git a/bin/varnishtest/Makefile.am b/bin/varnishtest/Makefile.am
index 924f21c..5732534 100644
--- a/bin/varnishtest/Makefile.am
+++ b/bin/varnishtest/Makefile.am
@@ -27,6 +27,7 @@ varnishtest_SOURCES = \
 		vtc.h \
 		vmods.h \
 		programs.h \
+		vtc_barrier.c \
 		vtc_client.c \
 		vtc_http.c \
 		vtc_main.c \
diff --git a/bin/varnishtest/Makefile.phk b/bin/varnishtest/Makefile.phk
index 438bfed..5c80efd 100644
--- a/bin/varnishtest/Makefile.phk
+++ b/bin/varnishtest/Makefile.phk
@@ -5,6 +5,7 @@ PROG_SRC += vtc_log.c
 PROG_SRC += vtc_logexp.c
 PROG_SRC += vtc_main.c
 PROG_SRC += vtc_sema.c
+PROG_SRC += vtc_barrier.c
 PROG_SRC += vtc_server.c
 PROG_SRC += vtc_varnish.c
 PROG_SRC += vtc_process.c
diff --git a/bin/varnishtest/tests/a00008.vtc b/bin/varnishtest/tests/a00008.vtc
index 3a581c8..6fe35c9 100644
--- a/bin/varnishtest/tests/a00008.vtc
+++ b/bin/varnishtest/tests/a00008.vtc
@@ -1,22 +1,25 @@
-varnishtest "Sema operations"
+varnishtest "Barrier operations"
+
+barrier b1 cond 4
+barrier b2 cond 4
 
 server s1 {
 	rxreq
-	sema r1 sync 4
+	barrier b1 sync
 	delay .9
 	txresp
 } -start
 
 server s2 {
 	rxreq
-	sema r1 sync 4
+	barrier b1 sync
 	delay .6
 	txresp
 } -start
 
 server s3 {
 	rxreq
-	sema r1 sync 4
+	barrier b1 sync
 	delay .2
 	txresp
 } -start
@@ -25,25 +28,25 @@ client c1 -connect ${s1_sock} {
 	delay .2
 	txreq
 	rxresp
-	sema r1 sync 4
+	barrier b2 sync
 } -start
 
 client c2 -connect ${s2_sock} {
 	delay .6
 	txreq
 	rxresp
-	sema r1 sync 4
+	barrier b2 sync
 } -start
 
 client c3 -connect ${s3_sock} {
 	delay .9
 	txreq
 	rxresp
-	sema r1 sync 4
+	barrier b2 sync
 } -start
 
 # Wait for all servers to have received requests
-sema r1 sync 4
+barrier b1 sync
 
 # Wait for all clients to have received responses
-sema r1 sync 4
+barrier b2 sync
diff --git a/bin/varnishtest/tests/c00073.vtc b/bin/varnishtest/tests/c00073.vtc
index f638e20..de94671 100644
--- a/bin/varnishtest/tests/c00073.vtc
+++ b/bin/varnishtest/tests/c00073.vtc
@@ -1,12 +1,15 @@
 varnishtest "Test object trimming"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	txresp -nolen -hdr "Transfer-encoding: chunked"
 	delay .2
 	chunkedlen 4096
-	sema r1 sync 2
-	sema r2 sync 2
+	barrier b1 sync
+	barrier b2 sync
 	chunkedlen 0
 } -start
 
@@ -18,10 +21,10 @@ client c1 {
 	rxresp
 } -start
 
-sema r1 sync 2
+barrier b1 sync
 varnish v1 -expect SMA.s0.g_bytes > 10000
 
-sema r2 sync 2
+barrier b2 sync
 
 client c1 -wait
 varnish v1 -expect SMA.s0.g_bytes < 6000
diff --git a/bin/varnishtest/vtc.c b/bin/varnishtest/vtc.c
index 5e6770a..fc42c72 100644
--- a/bin/varnishtest/vtc.c
+++ b/bin/varnishtest/vtc.c
@@ -619,6 +619,7 @@ static const struct cmds cmds[] = {
 	{ "shell",	cmd_shell },
 	{ "err_shell",	cmd_err_shell },
 	{ "sema",	cmd_sema },
+	{ "barrier",	cmd_barrier },
 	{ "random",	cmd_random },
 	{ "feature",	cmd_feature },
 	{ "logexpect",	cmd_logexp },
@@ -641,6 +642,7 @@ exec_file(const char *fn, const char *script, const char *tmpdir,
 
 	init_macro();
 	init_sema();
+	init_barrier();
 	init_server();
 
 	/* Move into our tmpdir */
diff --git a/bin/varnishtest/vtc.h b/bin/varnishtest/vtc.h
index 518494c..584b1ba 100644
--- a/bin/varnishtest/vtc.h
+++ b/bin/varnishtest/vtc.h
@@ -62,6 +62,7 @@ cmd_f cmd_server;
 cmd_f cmd_client;
 cmd_f cmd_varnish;
 cmd_f cmd_sema;
+cmd_f cmd_barrier;
 cmd_f cmd_logexp;
 cmd_f cmd_process;
 
@@ -74,6 +75,7 @@ extern int vtc_witness;
 extern int feature_dns;
 
 void init_sema(void);
+void init_barrier(void);
 void init_server(void);
 
 int http_process(struct vtclog *vl, const char *spec, int sock, int *sfd);
diff --git a/bin/varnishtest/vtc_barrier.c b/bin/varnishtest/vtc_barrier.c
new file mode 100644
index 0000000..448eb0d
--- /dev/null
+++ b/bin/varnishtest/vtc_barrier.c
@@ -0,0 +1,239 @@
+/*-
+ * Copyright (c) 2005 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Dridi Boukelmoune <dridi at varnish-software.com>
+ *
+ * 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.
+ */
+
+#include "config.h"
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "vtc.h"
+
+enum barrier_e {
+	BARRIER_NONE = 0,
+	BARRIER_COND,
+	BARRIER_SOCK,
+};
+
+struct barrier {
+	unsigned		magic;
+#define BARRIER_MAGIC		0x7b54c275
+	char			*name;
+	VTAILQ_ENTRY(barrier)	list;
+	pthread_mutex_t		mtx;
+	pthread_cond_t		cond;
+
+	unsigned		waiters;
+	unsigned		expected;
+
+	enum barrier_e		type;
+};
+
+static pthread_mutex_t		barrier_mtx;
+static VTAILQ_HEAD(, barrier)	barriers = VTAILQ_HEAD_INITIALIZER(barriers);
+
+static struct barrier *
+barrier_new(char *name, struct vtclog *vl)
+{
+	struct barrier *b;
+
+	ALLOC_OBJ(b, BARRIER_MAGIC);
+	AN(b);
+	AN(name);
+	if (*name != 'b')
+		vtc_log(vl, 0, "Barrier name must start with 'b' (%s)", name);
+	REPLACE(b->name, name);
+
+	AZ(pthread_mutex_init(&b->mtx, NULL));
+	AZ(pthread_cond_init(&b->cond, NULL));
+	b->waiters = 0;
+	b->expected = 0;
+	VTAILQ_INSERT_TAIL(&barriers, b, list);
+	return (b);
+}
+
+/**********************************************************************
+ * Init a barrier
+ */
+
+static void
+barrier_expect(struct barrier *b, const char *av, struct vtclog *vl)
+{
+	unsigned expected;
+
+	if (b->type != BARRIER_NONE)
+		vtc_log(vl, 0,
+		    "Barrier(%s) use error: already initialized", b->name);
+
+	AZ(b->expected);
+	AZ(b->waiters);
+	expected = strtoul(av, NULL, 0);
+	if (expected < 2)
+		vtc_log(vl, 0,
+		    "Barrier(%s) use error: wrong expectation (%u)",
+		    b->name, expected);
+
+	b->expected = expected;
+}
+
+static void
+barrier_cond(struct barrier *b, const char *av, struct vtclog *vl)
+{
+
+	CHECK_OBJ_NOTNULL(b, BARRIER_MAGIC);
+	barrier_expect(b, av, vl);
+	b->type = BARRIER_COND;
+}
+
+static void
+barrier_sock(struct barrier *b, const char *av, struct vtclog *vl)
+{
+
+	CHECK_OBJ_NOTNULL(b, BARRIER_MAGIC);
+	barrier_expect(b, av, vl);
+	b->type = BARRIER_SOCK;
+	INCOMPL();
+}
+
+/**********************************************************************
+ * Sync a barrier
+ */
+
+static void
+barrier_cond_sync(struct barrier *b, struct vtclog *vl)
+{
+
+	CHECK_OBJ_NOTNULL(b, BARRIER_MAGIC);
+	assert(b->type == BARRIER_COND);
+
+	assert(b->waiters <= b->expected);
+	if (b->waiters == b->expected)
+		vtc_log(vl, 0,
+		    "Barrier(%s) use error: more waiters than the %u expected",
+		    b->name, b->expected);
+
+	if (++b->waiters == b->expected) {
+		vtc_log(vl, 4, "Barrier(%s) wake %u", b->name, b->expected);
+		AZ(pthread_cond_broadcast(&b->cond));
+	}
+	else {
+		vtc_log(vl, 4, "Barrier(%s) wait %u of %u",
+		    b->name, b->waiters, b->expected);
+		AZ(pthread_cond_wait(&b->cond, &b->mtx));
+	}
+}
+
+static void
+barrier_sync(struct barrier *b, struct vtclog *vl)
+{
+
+	CHECK_OBJ_NOTNULL(b, BARRIER_MAGIC);
+
+	switch (b->type) {
+	case BARRIER_NONE:
+		vtc_log(vl, 0,
+		    "Barrier(%s) use error: not initialized", b->name);
+	case BARRIER_COND:
+		barrier_cond_sync(b, vl);
+		break;
+	case BARRIER_SOCK:
+		INCOMPL();
+		break;
+	default:
+		WRONG("Wrong barrier type");
+	}
+}
+
+/**********************************************************************
+ * Barrier command dispatch
+ */
+
+void
+cmd_barrier(CMD_ARGS)
+{
+	struct barrier *b, *b2;
+
+	(void)priv;
+	(void)cmd;
+
+	if (av == NULL) {
+		AZ(pthread_mutex_lock(&barrier_mtx));
+		/* Reset and free */
+		VTAILQ_FOREACH_SAFE(b, &barriers, list, b2) {
+			AZ(pthread_mutex_lock(&b->mtx));
+			assert(b->type != BARRIER_NONE);
+			assert(b->waiters == b->expected);
+			AZ(pthread_mutex_unlock(&b->mtx));
+		}
+		AZ(pthread_mutex_unlock(&barrier_mtx));
+		return;
+	}
+
+	AZ(strcmp(av[0], "barrier"));
+	av++;
+
+	AZ(pthread_mutex_lock(&barrier_mtx));
+	VTAILQ_FOREACH(b, &barriers, list)
+		if (!strcmp(b->name, av[0]))
+			break;
+	if (b == NULL)
+		b = barrier_new(av[0], vl);
+	av++;
+	AZ(pthread_mutex_lock(&b->mtx));
+	AZ(pthread_mutex_unlock(&barrier_mtx));
+
+	for (; *av != NULL; av++) {
+		if (!strcmp(*av, "cond")) {
+			av++;
+			AN(*av);
+			barrier_cond(b, *av, vl);
+			continue;
+		}
+		if (!strcmp(*av, "sock")) {
+			av++;
+			AN(*av);
+			barrier_sock(b, *av, vl);
+			continue;
+		}
+		if (!strcmp(*av, "sync")) {
+			barrier_sync(b, vl);
+			continue;
+		}
+		vtc_log(vl, 0, "Unknown barrier argument: %s", *av);
+	}
+	AZ(pthread_mutex_unlock(&b->mtx));
+}
+
+void
+init_barrier(void)
+{
+
+	AZ(pthread_mutex_init(&barrier_mtx, NULL));
+}
diff --git a/bin/varnishtest/vtc_http.c b/bin/varnishtest/vtc_http.c
index 9d1fe34..b2846f4 100644
--- a/bin/varnishtest/vtc_http.c
+++ b/bin/varnishtest/vtc_http.c
@@ -1380,6 +1380,7 @@ static const struct cmds http_cmds[] = {
 	{ "chunked",		cmd_http_chunked },
 	{ "chunkedlen",		cmd_http_chunkedlen },
 	{ "delay",		cmd_delay },
+	{ "barrier",		cmd_barrier },
 	{ "sema",		cmd_sema },
 	{ "expect_close",	cmd_http_expect_close },
 	{ "close",		cmd_http_close },



More information about the varnish-commit mailing list