Hi,

As discussed in Rotterdam, and in Dag's thread on IPC semaphores,
we need to sync varnishtest with varnishd. This patch set retires
varnishtest semaphores and introduce barriers instead. The main
difference is that barriers are not cyclic by default, and separate
the initialization from actual syncing. I kept Dag's test case, it was
more interesting than mine.

The syntax looks like this:

> # initialization
> barrier b1 cond 2
> barrier b2 sock 2
>
> # usage in varnishtest, you don't "sync N" anymore
> barrier b1 sync
>
> # usage in VCL
> debug.barrier_sync("${b2_sock}");

I see two choices I made that could be controversial:
- a sock barrier doesn't keep track of incoming connections
- debug.barrier_sync won't work in vcl_(init|fini) {}

Thoughts?

Happy syncing,
Dridi
From 259da2df042e2704365d92d86c184cb0c0747ad5 Mon Sep 17 00:00:00 2001
From: Dridi Boukelmoune <[email protected]>
Date: Tue, 22 Dec 2015 18:16:08 +0100
Subject: [PATCH 1/6] Introduce barriers in varnishtest

They work like semaphores, except that they need explicit initialization
and can optionally be shared between processes.
---
 bin/varnishtest/Makefile.am      |   1 +
 bin/varnishtest/Makefile.phk     |   1 +
 bin/varnishtest/tests/a00008.vtc |  21 ++--
 bin/varnishtest/vtc.c            |   2 +
 bin/varnishtest/vtc.h            |   2 +
 bin/varnishtest/vtc_barrier.c    | 239 +++++++++++++++++++++++++++++++++++++++
 bin/varnishtest/vtc_http.c       |   1 +
 7 files changed, 258 insertions(+), 9 deletions(-)
 create mode 100644 bin/varnishtest/vtc_barrier.c

diff --git a/bin/varnishtest/Makefile.am b/bin/varnishtest/Makefile.am
index 2506a8a..a748fee 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/vtc.c b/bin/varnishtest/vtc.c
index 3c6c884..136f0ee 100644
--- a/bin/varnishtest/vtc.c
+++ b/bin/varnishtest/vtc.c
@@ -627,6 +627,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 },
@@ -650,6 +651,7 @@ exec_file(const char *fn, const char *script, const char *tmpdir,
 
 	init_macro();
 	init_sema();
+	init_barrier();
 	init_server();
 
 	/* Apply extmacro definitions */
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 <[email protected]>
+ *
+ * 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 0440542..0214b0d 100644
--- a/bin/varnishtest/vtc_http.c
+++ b/bin/varnishtest/vtc_http.c
@@ -1353,6 +1353,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 },
-- 
2.4.3

From 305aeb00f0b59419356f31627c6acae279626442 Mon Sep 17 00:00:00 2001
From: Dridi Boukelmoune <[email protected]>
Date: Wed, 23 Dec 2015 08:27:14 +0100
Subject: [PATCH 2/6] Barriers can be cyclic but not like semaphores

This is useful in HTTP loops where it's impossible to predict and use an
array of barriers. All cycles expect the same number of waiters, unlike
semaphores.
---
 bin/varnishtest/tests/a00008.vtc | 30 ++++++++++++++++++++----------
 bin/varnishtest/vtc_barrier.c    | 30 +++++++++++++++++++++++++++++-
 2 files changed, 49 insertions(+), 11 deletions(-)

diff --git a/bin/varnishtest/tests/a00008.vtc b/bin/varnishtest/tests/a00008.vtc
index 6fe35c9..dfa84d3 100644
--- a/bin/varnishtest/tests/a00008.vtc
+++ b/bin/varnishtest/tests/a00008.vtc
@@ -1,25 +1,30 @@
 varnishtest "Barrier operations"
 
-barrier b1 cond 4
-barrier b2 cond 4
+# bs -> server, bc -> client, bb -> both
+barrier bs cond 4
+barrier bc cond 4
+barrier bb cond 4 -cyclic
 
 server s1 {
 	rxreq
-	barrier b1 sync
+	barrier bs sync
+	barrier bb sync
 	delay .9
 	txresp
 } -start
 
 server s2 {
 	rxreq
-	barrier b1 sync
+	barrier bs sync
+	barrier bb sync
 	delay .6
 	txresp
 } -start
 
 server s3 {
 	rxreq
-	barrier b1 sync
+	barrier bs sync
+	barrier bb sync
 	delay .2
 	txresp
 } -start
@@ -28,25 +33,30 @@ client c1 -connect ${s1_sock} {
 	delay .2
 	txreq
 	rxresp
-	barrier b2 sync
+	barrier bc sync
+	barrier bb sync
 } -start
 
 client c2 -connect ${s2_sock} {
 	delay .6
 	txreq
 	rxresp
-	barrier b2 sync
+	barrier bc sync
+	barrier bb sync
 } -start
 
 client c3 -connect ${s3_sock} {
 	delay .9
 	txreq
 	rxresp
-	barrier b2 sync
+	barrier bc sync
+	barrier bb sync
 } -start
 
 # Wait for all servers to have received requests
-barrier b1 sync
+barrier bs sync
+barrier bb sync
 
 # Wait for all clients to have received responses
-barrier b2 sync
+barrier bc sync
+barrier bb sync
diff --git a/bin/varnishtest/vtc_barrier.c b/bin/varnishtest/vtc_barrier.c
index 448eb0d..b170c56 100644
--- a/bin/varnishtest/vtc_barrier.c
+++ b/bin/varnishtest/vtc_barrier.c
@@ -52,6 +52,7 @@ struct barrier {
 
 	unsigned		waiters;
 	unsigned		expected;
+	unsigned		cyclic;
 
 	enum barrier_e		type;
 };
@@ -122,6 +123,23 @@ barrier_sock(struct barrier *b, const char *av, struct vtclog *vl)
 	INCOMPL();
 }
 
+static void
+barrier_cyclic(struct barrier *b, struct vtclog *vl)
+{
+
+	CHECK_OBJ_NOTNULL(b, BARRIER_MAGIC);
+
+	if (b->type == BARRIER_NONE)
+		vtc_log(vl, 0,
+		    "Barrier(%s) use error: not initialized", b->name);
+
+	if (b->waiters != 0)
+		vtc_log(vl, 0,
+		    "Barrier(%s) use error: already in use", b->name);
+
+	b->cyclic = 1;
+}
+
 /**********************************************************************
  * Sync a barrier
  */
@@ -148,6 +166,9 @@ barrier_cond_sync(struct barrier *b, struct vtclog *vl)
 		    b->name, b->waiters, b->expected);
 		AZ(pthread_cond_wait(&b->cond, &b->mtx));
 	}
+
+	if (b->cyclic)
+		b->waiters = 0;
 }
 
 static void
@@ -189,7 +210,10 @@ cmd_barrier(CMD_ARGS)
 		VTAILQ_FOREACH_SAFE(b, &barriers, list, b2) {
 			AZ(pthread_mutex_lock(&b->mtx));
 			assert(b->type != BARRIER_NONE);
-			assert(b->waiters == b->expected);
+			if (b->cyclic)
+				AZ(b->waiters);
+			else
+				assert(b->waiters == b->expected);
 			AZ(pthread_mutex_unlock(&b->mtx));
 		}
 		AZ(pthread_mutex_unlock(&barrier_mtx));
@@ -226,6 +250,10 @@ cmd_barrier(CMD_ARGS)
 			barrier_sync(b, vl);
 			continue;
 		}
+		if (!strcmp(*av, "-cyclic")) {
+			barrier_cyclic(b, vl);
+			continue;
+		}
 		vtc_log(vl, 0, "Unknown barrier argument: %s", *av);
 	}
 	AZ(pthread_mutex_unlock(&b->mtx));
-- 
2.4.3

From ccedd0856094c3011d83d51b79f1c3f39ffa4ea4 Mon Sep 17 00:00:00 2001
From: Dridi Boukelmoune <[email protected]>
Date: Wed, 23 Dec 2015 11:52:52 +0100
Subject: [PATCH 3/6] Retire varnishtest semaphores and use barriers

All usage of cyclic semaphores has been replaced by non-cylic barriers,
except in the disabled test r01252 that absolutely needs one. It still
passes when run with the proper requirements.
---
 bin/varnishtest/Makefile.am               |   1 -
 bin/varnishtest/Makefile.phk              |   1 -
 bin/varnishtest/tests.disabled/r01252.vtc |   6 +-
 bin/varnishtest/tests.disabled/r01506.vtc |  12 ++-
 bin/varnishtest/tests.disabled/r01732.vtc |  11 +-
 bin/varnishtest/tests.disabled/t00000.vtc |  21 ++--
 bin/varnishtest/tests/c00013.vtc          |  11 +-
 bin/varnishtest/tests/c00014.vtc          |   6 +-
 bin/varnishtest/tests/c00017.vtc          |   6 +-
 bin/varnishtest/tests/c00038.vtc          |   6 +-
 bin/varnishtest/tests/c00043.vtc          |  10 +-
 bin/varnishtest/tests/c00058.vtc          |   6 +-
 bin/varnishtest/tests/c00062.vtc          |  11 +-
 bin/varnishtest/tests/d00009.vtc          |  11 +-
 bin/varnishtest/tests/d00010.vtc          |  11 +-
 bin/varnishtest/tests/d00011.vtc          |   6 +-
 bin/varnishtest/tests/d00012.vtc          |   6 +-
 bin/varnishtest/tests/d00013.vtc          |   6 +-
 bin/varnishtest/tests/p00007.vtc          |  11 +-
 bin/varnishtest/tests/r00345.vtc          |   6 +-
 bin/varnishtest/tests/r00427.vtc          |  11 +-
 bin/varnishtest/tests/r00667.vtc          |  11 +-
 bin/varnishtest/tests/r00963.vtc          |  12 ++-
 bin/varnishtest/tests/r01073.vtc          |  11 +-
 bin/varnishtest/tests/r01391.vtc          |   5 +-
 bin/varnishtest/tests/r01399.vtc          |   6 +-
 bin/varnishtest/tests/r01419.vtc          |  11 +-
 bin/varnishtest/tests/r01468.vtc          |  11 +-
 bin/varnishtest/tests/r01478.vtc          |  21 ++--
 bin/varnishtest/tests/r01646.vtc          |  13 ++-
 bin/varnishtest/tests/r01648.vtc          |   8 +-
 bin/varnishtest/tests/r01737.vtc          |   6 +-
 bin/varnishtest/tests/r01818.vtc          |  11 +-
 bin/varnishtest/tests/s00001.vtc          |   6 +-
 bin/varnishtest/tests/s00002.vtc          |  11 +-
 bin/varnishtest/tests/v00010.vtc          |  11 +-
 bin/varnishtest/tests/v00012.vtc          |  11 +-
 bin/varnishtest/tests/v00014.vtc          |  21 ++--
 bin/varnishtest/vtc.c                     |   2 -
 bin/varnishtest/vtc.h                     |   2 -
 bin/varnishtest/vtc_http.c                |   1 -
 bin/varnishtest/vtc_sema.c                | 162 ------------------------------
 42 files changed, 228 insertions(+), 301 deletions(-)
 delete mode 100644 bin/varnishtest/vtc_sema.c

diff --git a/bin/varnishtest/Makefile.am b/bin/varnishtest/Makefile.am
index a748fee..a65d621 100644
--- a/bin/varnishtest/Makefile.am
+++ b/bin/varnishtest/Makefile.am
@@ -32,7 +32,6 @@ varnishtest_SOURCES = \
 		vtc_http.c \
 		vtc_main.c \
 		vtc_log.c \
-		vtc_sema.c \
 		vtc_server.c \
 		vtc_varnish.c \
 		vtc_logexp.c \
diff --git a/bin/varnishtest/Makefile.phk b/bin/varnishtest/Makefile.phk
index 5c80efd..b50535d 100644
--- a/bin/varnishtest/Makefile.phk
+++ b/bin/varnishtest/Makefile.phk
@@ -4,7 +4,6 @@ PROG_SRC += vtc_http.c
 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
diff --git a/bin/varnishtest/tests.disabled/r01252.vtc b/bin/varnishtest/tests.disabled/r01252.vtc
index fd820e9..21a2995 100644
--- a/bin/varnishtest/tests.disabled/r01252.vtc
+++ b/bin/varnishtest/tests.disabled/r01252.vtc
@@ -5,10 +5,12 @@ varnishtest "#1252 - Drop remote closed connections returning from waitinglists"
 # because it requires "-t 80" argument to varnishtest (remote closed
 # state will only be detected after FIN timeout has passed (60s))
 
+barrier b1 cond 2
+
 server s1 {
 	rxreq
 	expect req.http.X-Client == "1"
-	sema r1 sync 2
+	barrier b1 sync
 	delay 75
 	close
 } -start
@@ -50,7 +52,7 @@ client c1 {
 } -start
 
 client c2 {
-	sema r1 sync 2
+	barrier b1 sync
 	txreq -hdr "X-Client: 2"
 	delay 1
 } -start
diff --git a/bin/varnishtest/tests.disabled/r01506.vtc b/bin/varnishtest/tests.disabled/r01506.vtc
index f2bb5b2..1d0f0bb 100644
--- a/bin/varnishtest/tests.disabled/r01506.vtc
+++ b/bin/varnishtest/tests.disabled/r01506.vtc
@@ -1,5 +1,7 @@
 varnishtest "range requests on streamed response"
 
+barrier b1 cond 2 -cyclic
+
 server s1 -repeat 4 {
 	rxreq
 	txresp -nolen \
@@ -9,7 +11,7 @@ server s1 -repeat 4 {
 	send "11\r\n1_23456789abcdef\n"
 	send "11\r\n2_23456789abcdef\n"
 	send "11\r\n3_23456789abcdef\n"
-	sema r1 sync 2
+	barrier b1 sync
 	send "11\r\n4_23456789abcdef\n"
 	send "11\r\n5_23456789abcdef\n"
 	send "11\r\n6_23456789abcdef\n"
@@ -32,7 +34,7 @@ client c1 {
 	rxresphdrs
 	expect resp.status == 206
 	expect resp.http.content-length == 85
-	sema r1 sync 2
+	barrier b1 sync
 	rxrespbody
 	expect resp.bodylen == 85
 	delay .1
@@ -42,7 +44,7 @@ client c1 {
 	rxresphdrs
 	expect resp.status == 200
 	expect resp.http.Transfer-Encoding == chunked
-	sema r1 sync 2
+	barrier b1 sync
 	rxrespbody
 	expect resp.bodylen == 136
 	delay .1
@@ -52,7 +54,7 @@ client c1 {
 	rxresphdrs
 	expect resp.status == 200
 	expect resp.http.Transfer-Encoding == chunked
-	sema r1 sync 2
+	barrier b1 sync
 	rxrespbody
 	expect resp.bodylen == 136
 	delay .1
@@ -62,7 +64,7 @@ client c1 {
 	rxresphdrs
 	expect resp.status == 206
 	expect resp.http.content-length == 99
-	sema r1 sync 2
+	barrier b1 sync
 	recv 34
 	delay .3
 	expect_close
diff --git a/bin/varnishtest/tests.disabled/r01732.vtc b/bin/varnishtest/tests.disabled/r01732.vtc
index f738dec..052ae09 100644
--- a/bin/varnishtest/tests.disabled/r01732.vtc
+++ b/bin/varnishtest/tests.disabled/r01732.vtc
@@ -1,17 +1,20 @@
 varnishtest "range related panic"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	txresp -nolen -hdr "Transfer-Encoding: chunked"
 	chunkedlen 10
 	chunkedlen 10
-	sema r1 sync 2
+	barrier b1 sync
 	chunkedlen 10
 	chunkedlen 10
 	chunkedlen 10
 	chunkedlen 0
 	delay .1
-	sema r2 sync 2
+	barrier b2 sync
 } -start
 
 varnish v1 -vcl+backend {
@@ -25,8 +28,8 @@ client c1 {
 } -run
 
 delay .1
-sema r1 sync 2
-sema r2 sync 2
+barrier b1 sync
+barrier b2 sync
 delay .4
 
 client c1 {
diff --git a/bin/varnishtest/tests.disabled/t00000.vtc b/bin/varnishtest/tests.disabled/t00000.vtc
index 7dd5818..c84100a 100644
--- a/bin/varnishtest/tests.disabled/t00000.vtc
+++ b/bin/varnishtest/tests.disabled/t00000.vtc
@@ -1,16 +1,21 @@
 varnishtest "Ticket #873"
 
+barrier b1 cond 2
+barrier b2 cond 2
+barrier b3 cond 2
+barrier b4 cond 2
+
 server s1 {
 	rxreq
 	txresp -nolen -hdr "Transfer-encoding: chunked"
 	chunked "<1>------------------------<1>\n"
-	sema r1 sync 2
+	barrier b1 sync
 	chunked "<2>------------------------<2>\n"
-	sema r2 sync 2
+	barrier b2 sync
 	chunked "<3>------------------------<3>\n"
-	sema r1 sync 2
+	barrier b3 sync
 	chunked "<4>------------------------<4>\n"
-	sema r2 sync 2
+	barrier b4 sync
 	chunkedlen 0
 } -start
 
@@ -28,19 +33,19 @@ client c1 {
 
 	rxchunk
 	expect resp.chunklen == 31
-	sema r1 sync 2
+	barrier b1 sync
 
 	rxchunk
 	expect resp.chunklen == 31
-	sema r2 sync 2
+	barrier b2 sync
 
 	rxchunk
 	expect resp.chunklen == 31
-	sema r1 sync 2
+	barrier b3 sync
 
 	rxchunk
 	expect resp.chunklen == 31
-	sema r2 sync 2
+	barrier b4 sync
 
 	rxchunk
 	expect resp.chunklen == 0
diff --git a/bin/varnishtest/tests/c00013.vtc b/bin/varnishtest/tests/c00013.vtc
index 689e118..ed027d3 100644
--- a/bin/varnishtest/tests/c00013.vtc
+++ b/bin/varnishtest/tests/c00013.vtc
@@ -1,15 +1,18 @@
 varnishtest "Test parking second request on backend delay"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	expect req.url == "/foo"
 	send "HTTP/1.0 200 OK\r\nConnection: close\r\n\r\n"
 	delay .2
-	sema r1 sync 2
+	barrier b1 sync
 	delay .2
 	send "line1\n"
 	delay .2
-	sema r1 sync 2
+	barrier b2 sync
 	send "line2\n"
 } -start
 
@@ -29,12 +32,12 @@ client c1 {
 	expect resp.http.x-varnish == "1001"
 } -start
 
-sema r1 sync 2
+barrier b1 sync
 
 client c2 {
 	txreq -url "/foo" -hdr "client: c2"
 	delay .2
-	sema r1 sync 2
+	barrier b2 sync
 	rxresp
 	expect resp.status == 200
 	expect resp.bodylen == 12
diff --git a/bin/varnishtest/tests/c00014.vtc b/bin/varnishtest/tests/c00014.vtc
index ec8c9d8..41eb00b 100644
--- a/bin/varnishtest/tests/c00014.vtc
+++ b/bin/varnishtest/tests/c00014.vtc
@@ -1,9 +1,11 @@
 varnishtest "Test parking second request on backend delay, then pass"
 
+barrier b1 cond 2
+
 server s1 {
 	rxreq
 	expect req.url == "/foo"
-	sema r1 sync 2
+	barrier b1 sync
 	send "HTTP/1.1 200 OK\r\nContent-Length: 12\r\n\r\n"
 	send "line1\n"
 	send "line2\n"
@@ -28,7 +30,7 @@ client c1 {
 	expect resp.http.x-varnish == "1001"
 } -start
 
-sema r1 sync 2
+barrier b1 sync
 delay .2
 
 client c2 {
diff --git a/bin/varnishtest/tests/c00017.vtc b/bin/varnishtest/tests/c00017.vtc
index 9342c53..b062980 100644
--- a/bin/varnishtest/tests/c00017.vtc
+++ b/bin/varnishtest/tests/c00017.vtc
@@ -1,5 +1,7 @@
 varnishtest "Test Backend Polling"
 
+barrier b1 cond 2
+
 server s1 {
 	# Probes
 	loop 8 {
@@ -22,7 +24,7 @@ server s1 {
 		accept
 	}
 
-	sema r1 sync 2
+	barrier b1 sync
 } -start
 
 varnish v1 -vcl {
@@ -38,6 +40,6 @@ varnish v1 -vcl {
 
 } -start
 
-sema r1 sync 2
+barrier b1 sync
 
 varnish v1 -cli "backend.list -p"
diff --git a/bin/varnishtest/tests/c00038.vtc b/bin/varnishtest/tests/c00038.vtc
index e9402b6..1e81f26 100644
--- a/bin/varnishtest/tests/c00038.vtc
+++ b/bin/varnishtest/tests/c00038.vtc
@@ -1,8 +1,10 @@
 varnishtest "Test req.hash_ignore_busy in vcl_recv"
 
+barrier b1 cond 2
+
 server s1 {
 	rxreq
-	sema r1 sync 2
+	barrier b1 sync
 	delay 1
 	txresp -hdr "Server: 1"
 } -start
@@ -36,7 +38,7 @@ client c1 {
 } -start
 
 client c2 {
-    sema r1 sync 2
+	barrier b1 sync
 	txreq -url "/" -hdr "x-client: 2" -hdr "x-ignorebusy: 1"
 	txreq -url "/" -hdr "x-client: 2"
 	rxresp
diff --git a/bin/varnishtest/tests/c00043.vtc b/bin/varnishtest/tests/c00043.vtc
index 0960621..15d87c7 100644
--- a/bin/varnishtest/tests/c00043.vtc
+++ b/bin/varnishtest/tests/c00043.vtc
@@ -1,12 +1,14 @@
 varnishtest "predictive vary"
 
+barrier b1 cond 2
+barrier b2 cond 2
 
 server s1 {
 	rxreq
 	txresp -hdr "Vary: foo" -bodylen 1
 	rxreq
-	sema r2 sync 2
-	sema r1 sync 2
+	barrier b2 sync
+	barrier b1 sync
 	txresp -hdr "Vary: foo" -bodylen 2
 } -start
 
@@ -33,10 +35,10 @@ client c1 {
 } -start
 
 client c2 {
-	sema r2 sync 2
+	barrier b2 sync
 	txreq -hdr "Foo: vary3" -hdr "bar: yes"
 	rxresp
-	sema r1 sync 2
+	barrier b1 sync
 	expect resp.bodylen == 3
 } -start
 
diff --git a/bin/varnishtest/tests/c00058.vtc b/bin/varnishtest/tests/c00058.vtc
index b898034..6a2d733 100644
--- a/bin/varnishtest/tests/c00058.vtc
+++ b/bin/varnishtest/tests/c00058.vtc
@@ -1,11 +1,13 @@
 varnishtest "Test v4 grace"
 
+barrier b1 cond 2
+
 server s1 {
 	rxreq
 	txresp -hdr "Last-Modified: Mon, 09 Feb 2015 09:32:47 GMT" -bodylen 3
 	rxreq
 	txresp -bodylen 6
-	sema r2 sync 2
+	barrier b1 sync
 } -start
 
 varnish v1 -vcl+backend {
@@ -33,7 +35,7 @@ client c1 {
 	expect resp.bodylen == 3
 
 	# But bg fetch was kicked off
-	sema r2 sync 2
+	barrier b1 sync
 	delay .2
 
 	# And now we get the new object
diff --git a/bin/varnishtest/tests/c00062.vtc b/bin/varnishtest/tests/c00062.vtc
index 643a2f6..54e0318 100644
--- a/bin/varnishtest/tests/c00062.vtc
+++ b/bin/varnishtest/tests/c00062.vtc
@@ -1,12 +1,15 @@
 varnishtest "Check that aborted backend body aborts client in streaming mode"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	txresp -nolen -hdr "Transfer-encoding: chunked"
 	chunked {<HTML>}
-	sema r1 sync 2
+	barrier b1 sync
 	chunked {<HTML>}
-	sema r1 sync 2
+	barrier b2 sync
 } -start
 
 varnish v1 -cliok "param.set debug +syncvsl" -vcl+backend {
@@ -19,9 +22,9 @@ client c1 {
 	rxresphdrs
 	expect resp.status == 200
 	rxchunk
-	sema r1 sync 2
+	barrier b1 sync
 	rxchunk
-	sema r1 sync 2
+	barrier b2 sync
 	expect_close
 } -run
 
diff --git a/bin/varnishtest/tests/d00009.vtc b/bin/varnishtest/tests/d00009.vtc
index 46d05c4..bb23412 100644
--- a/bin/varnishtest/tests/d00009.vtc
+++ b/bin/varnishtest/tests/d00009.vtc
@@ -1,17 +1,20 @@
 varnishtest "Test dynamic backends hot swap while being used"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	expect req.url == "/foo"
-	sema r1 sync 2
-	sema r2 sync 2
+	barrier b1 sync
+	barrier b2 sync
 	txresp
 } -start
 
 server s2 {
 	rxreq
 	expect req.url == "/bar"
-	sema r2 sync 2
+	barrier b2 sync
 	txresp
 } -start
 
@@ -42,7 +45,7 @@ client c1 {
 } -start
 
 client c2 {
-	sema r1 sync 2
+	barrier b1 sync
 	txreq -req "SWAP" -hdr "X-Addr: ${s2_addr}" -hdr "X-Port: ${s2_port}"
 	rxresp
 	expect resp.status == 200
diff --git a/bin/varnishtest/tests/d00010.vtc b/bin/varnishtest/tests/d00010.vtc
index 145112a..dbfac37 100644
--- a/bin/varnishtest/tests/d00010.vtc
+++ b/bin/varnishtest/tests/d00010.vtc
@@ -1,17 +1,20 @@
 varnishtest "Test dynamic backends hot swap during a pipe"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	expect req.url == "/foo"
-	sema r1 sync 2
-	sema r2 sync 2
+	barrier b1 sync
+	barrier b2 sync
 	txresp
 } -start
 
 server s2 {
 	rxreq
 	expect req.url == "/bar"
-	sema r2 sync 2
+	barrier b2 sync
 	txresp
 } -start
 
@@ -43,7 +46,7 @@ client c1 {
 } -start
 
 client c2 {
-	sema r1 sync 2
+	barrier b1 sync
 	txreq -req "SWAP" -hdr "X-Addr: ${s2_addr}" -hdr "X-Port: ${s2_port}"
 	rxresp
 	expect resp.status == 200
diff --git a/bin/varnishtest/tests/d00011.vtc b/bin/varnishtest/tests/d00011.vtc
index 639161e..96b70e6 100644
--- a/bin/varnishtest/tests/d00011.vtc
+++ b/bin/varnishtest/tests/d00011.vtc
@@ -1,5 +1,7 @@
 varnishtest "Test a dynamic backend hot swap after it was picked by a bereq"
 
+barrier b1 cond 2
+
 server s1 {
 } -start
 
@@ -41,13 +43,13 @@ varnish v1 -expect MAIN.n_backend == 2
 
 client c1 {
 	txreq
-	sema r2 sync 2
+	barrier b1 sync
 	rxresp
 	expect resp.status == 200
 }
 
 client c2 {
-	sema r2 sync 2
+	barrier b1 sync
 	delay 0.1
 	txreq -req "SWAP" -hdr "X-Addr: ${s2_addr}" -hdr "X-Port: ${s2_port}"
 	rxresp
diff --git a/bin/varnishtest/tests/d00012.vtc b/bin/varnishtest/tests/d00012.vtc
index edc028b..4c1693f 100644
--- a/bin/varnishtest/tests/d00012.vtc
+++ b/bin/varnishtest/tests/d00012.vtc
@@ -2,10 +2,12 @@ varnishtest "Test a dynamic backend discard during a request"
 
 # vcl.discard testing inspired by v00006.vtc from commit e1f7207
 
+barrier b1 cond 2
+
 server s1 {
 	rxreq
 	expect req.url == "/foo"
-	sema r1 sync 2
+	barrier b1 sync
 	txresp
 } -start
 
@@ -53,7 +55,7 @@ varnish v1 -vcl {
 }
 
 varnish v1 -cli "vcl.discard vcl1"
-sema r1 sync 2
+barrier b1 sync
 
 client c1 -wait
 delay 2
diff --git a/bin/varnishtest/tests/d00013.vtc b/bin/varnishtest/tests/d00013.vtc
index 6762f41..766df26 100644
--- a/bin/varnishtest/tests/d00013.vtc
+++ b/bin/varnishtest/tests/d00013.vtc
@@ -1,5 +1,7 @@
 varnishtest "Test a dynamic backend hot swap after it was hinted to a req"
 
+barrier b1 cond 2
+
 server s1 {
 } -start
 
@@ -38,13 +40,13 @@ varnish v1 -expect MAIN.n_backend == 2
 
 client c1 {
 	txreq
-	sema r2 sync 2
+	barrier b1 sync
 	rxresp
 	expect resp.status == 200
 }
 
 client c2 {
-	sema r2 sync 2
+	barrier b1 sync
 	delay 0.1
 	txreq -req "SWAP" -hdr "X-Addr: ${s2_addr}" -hdr "X-Port: ${s2_port}"
 	rxresp
diff --git a/bin/varnishtest/tests/p00007.vtc b/bin/varnishtest/tests/p00007.vtc
index 1daf4e5..a7c232a 100644
--- a/bin/varnishtest/tests/p00007.vtc
+++ b/bin/varnishtest/tests/p00007.vtc
@@ -1,5 +1,8 @@
 varnishtest "test reload of object spanning incomplete segment"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	expect req.url == "/1"
@@ -8,9 +11,9 @@ server s1 {
 	send "\n"
 	chunkedlen 32
 	# Tell top-level that it can sync the stevedore
-	sema r1 sync 2
+	barrier b1 sync
 	# Top-level tells us it has synched the stevedore
-	sema r1 sync 2
+	barrier b2 sync
 	chunkedlen 32
 	chunkedlen 0
 	accept
@@ -36,14 +39,14 @@ client c1 {
 } -start
 
 # Wait for first chunk to have been sent
-sema r1 sync 2
+barrier b1 sync
 delay .2
 
 # Sync the stevedore, so the next chunk ends up i segment 2
 varnish v1 -cliok "debug.persistent s0 sync"
 
 # Tell server to continue
-sema r1 sync 2
+barrier b2 sync
 
 # Get the result
 client c1 -wait
diff --git a/bin/varnishtest/tests/r00345.vtc b/bin/varnishtest/tests/r00345.vtc
index 8ce2d53..9041acd 100644
--- a/bin/varnishtest/tests/r00345.vtc
+++ b/bin/varnishtest/tests/r00345.vtc
@@ -1,10 +1,12 @@
 varnishtest "#345, ESI waitinglist trouble"
 
+barrier b1 cond 2
+
 server s1 {
 	rxreq
 	txresp -body {<esi:include src="someurl">}
 	rxreq
-	sema r1 sync 2
+	barrier b1 sync
 	delay 1
 	txresp -body {DATA}
 } -start
@@ -25,7 +27,7 @@ client c1 {
 
 client c2 {
 	txreq
-	sema r1 sync 2
+	barrier b1 sync
 	rxresp
 	expect resp.bodylen == 4
 } -run
diff --git a/bin/varnishtest/tests/r00427.vtc b/bin/varnishtest/tests/r00427.vtc
index a75247b..00c085b 100644
--- a/bin/varnishtest/tests/r00427.vtc
+++ b/bin/varnishtest/tests/r00427.vtc
@@ -1,5 +1,8 @@
 varnishtest "client close in ESI delivery"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	txresp -body {
@@ -10,8 +13,8 @@ server s1 {
 
 	rxreq
 	expect req.url == "/foo"
-	sema r1 sync 2
-	sema r1 sync 2
+	barrier b1 sync
+	barrier b2 sync
 	txresp -body "[foo]"
 
 	rxreq
@@ -31,11 +34,11 @@ varnish v1 -vcl+backend {
 
 client c1 {
 	txreq
-	sema r1 sync 2
+	barrier b1 sync
 } -run
 
 client c1 {
-	sema r1 sync 2
+	barrier b2 sync
 	txreq
 	rxresp
 } -run
diff --git a/bin/varnishtest/tests/r00667.vtc b/bin/varnishtest/tests/r00667.vtc
index 1c1da1f..2782e63 100644
--- a/bin/varnishtest/tests/r00667.vtc
+++ b/bin/varnishtest/tests/r00667.vtc
@@ -1,9 +1,12 @@
 varnishtest "things stuck on busy object"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
-	sema r1 sync 2
-	sema r1 sync 2
+	barrier b1 sync
+	barrier b2 sync
 	# There is a race in varnish between the first request releasing
 	# the backend connection, and the second request trying to get it
 	# which makes reuse of backend connection sometimes work and
@@ -29,9 +32,9 @@ client c1 {
 } -start
 
 client c2 {
-	sema r1 sync 2
+	barrier b1 sync
 	txreq
-	sema r1 sync 2
+	barrier b2 sync
 	rxresp
 	expect resp.bodylen == 5
 } -start
diff --git a/bin/varnishtest/tests/r00963.vtc b/bin/varnishtest/tests/r00963.vtc
index 6e8fc1d..f4599f5 100644
--- a/bin/varnishtest/tests/r00963.vtc
+++ b/bin/varnishtest/tests/r00963.vtc
@@ -1,8 +1,10 @@
 varnishtest "Test hsh_rush"
 
+barrier b1 cond 5
+
 server s1 {
 	rxreq
-	sema r1 sync 5
+	barrier b1 sync
 	txresp -bodylen 10
 } -start
 
@@ -13,28 +15,28 @@ varnish v1 -cliok "param.set rush_exponent 2"
 
 client c1 {
 	txreq
-	sema r1 sync 5
+	barrier b1 sync
 	rxresp
 	expect resp.bodylen == 10
 } -start
 
 client c2 {
 	txreq
-	sema r1 sync 5
+	barrier b1 sync
 	rxresp
 	expect resp.bodylen == 10
 } -start
 
 client c3 {
 	txreq
-	sema r1 sync 5
+	barrier b1 sync
 	rxresp
 	expect resp.bodylen == 10
 } -start
 
 client c4 {
 	txreq
-	sema r1 sync 5
+	barrier b1 sync
 	rxresp
 	expect resp.bodylen == 10
 } -start
diff --git a/bin/varnishtest/tests/r01073.vtc b/bin/varnishtest/tests/r01073.vtc
index 3e0c44e..c75563f 100644
--- a/bin/varnishtest/tests/r01073.vtc
+++ b/bin/varnishtest/tests/r01073.vtc
@@ -1,16 +1,19 @@
 varnishtest "Test that hash_always_miss also implies hash_ignore_busy. Ticket #1073."
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
-	sema r1 sync 2
-	sema r2 sync 2
+	barrier b1 sync
+	barrier b2 sync
 	delay 1
 	txresp -hdr "Server: 1"
 } -start
 
 server s2 {
 	rxreq
-	sema r2 sync 2
+	barrier b2 sync
 	txresp -hdr "Server: 2"
 } -start
 
@@ -38,7 +41,7 @@ client c1 {
 } -start
 
 client c2 {
-    sema r1 sync 2
+	barrier b1 sync
 	txreq -url "/" -hdr "x-client: 2" -hdr "x-hash-always-miss: 1"
 	txreq -url "/" -hdr "x-client: 2"
 	rxresp
diff --git a/bin/varnishtest/tests/r01391.vtc b/bin/varnishtest/tests/r01391.vtc
index 3858558..cfab166 100644
--- a/bin/varnishtest/tests/r01391.vtc
+++ b/bin/varnishtest/tests/r01391.vtc
@@ -1,12 +1,13 @@
 varnishtest "client abandoning hit-for-pass"
 
+barrier b1 cond 2
 
 server s1 {
 	non-fatal
 	rxreq
 	txresp -nolen -hdr "Transfer-Encoding: chunked" -hdr "Set-Cookie: foo=bar"
 	chunked "foo"
-	sema r1 sync 2
+	barrier b1 sync
 	chunked "bar"
 	delay .1
 	chunkedlen 64
@@ -23,7 +24,7 @@ client c1 {
 	txreq
 	rxresphdrs
 	rxchunk
-	sema r1 sync 2
+	barrier b1 sync
 } -run
 
 delay 2
diff --git a/bin/varnishtest/tests/r01399.vtc b/bin/varnishtest/tests/r01399.vtc
index 5d7171a..c7adffa 100644
--- a/bin/varnishtest/tests/r01399.vtc
+++ b/bin/varnishtest/tests/r01399.vtc
@@ -1,10 +1,12 @@
 varnishtest "1399 race issue with bg-fetches"
 
+barrier b1 cond 2
+
 server s1 {
 	rxreq
 	txresp -bodylen 1
 
-	sema r1 sync 2
+	barrier b1 sync
 
 	# Delay here, to stall the bgfetch for a while, to give the req time to finish
 	# delivery and cleanup up struct req
@@ -43,7 +45,7 @@ client c1 {
 	txreq
 	rxresp
 	expect resp.http.content-length == 1
-	sema r1 sync 2
+	barrier b1 sync
 } -run
 
 # Wait for the server to not explode
diff --git a/bin/varnishtest/tests/r01419.vtc b/bin/varnishtest/tests/r01419.vtc
index a47d424..84130b9 100644
--- a/bin/varnishtest/tests/r01419.vtc
+++ b/bin/varnishtest/tests/r01419.vtc
@@ -1,14 +1,17 @@
 varnishtest "Make sure banlurker skips busy objects"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	send "HTTP/1.0 200 OK\r\n"
-	sema r1 sync 2
+	barrier b1 sync
 	send "Foobar: blaf\r\n"
 	send "Content-Length: 10\r\n"
 	send "\r\n\r\n"
 	send "abcde"
-	sema r2 sync 2
+	barrier b2 sync
 	send "abcdefghij"
 } -start
 
@@ -29,7 +32,7 @@ client c1 {
 	expect resp.http.foobar == blaf
 } -start
 
-sema r1 sync 2
+barrier b1 sync
 varnish v1 -cliok {ban.list}
 
 varnish v1 -cliok {ban obj.http.goo == bar}
@@ -38,6 +41,6 @@ delay 2
 varnish v1 -cliok {ban.list}
 
 
-sema r2 sync 2
+barrier b2 sync
 
 client c1 -wait
diff --git a/bin/varnishtest/tests/r01468.vtc b/bin/varnishtest/tests/r01468.vtc
index 119c1da..10b97cf 100644
--- a/bin/varnishtest/tests/r01468.vtc
+++ b/bin/varnishtest/tests/r01468.vtc
@@ -1,11 +1,14 @@
 varnishtest "#1468 - freeing failed obj"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	expect req.url == "/1"
 	txresp -nolen -hdr "Transfer-Encoding: chunked"
 	chunked {<HTML>}
-	sema r1 sync 2
+	barrier b1 sync
 	close
 
 	accept
@@ -13,7 +16,7 @@ server s1 {
 	expect req.url == "/2"
 	txresp -nolen -hdr "Transfer-Encoding: chunked"
 	chunked {<HTML>}
-	sema r1 sync 2
+	barrier b2 sync
 } -start
 
 varnish v1 -vcl+backend {
@@ -33,7 +36,7 @@ client c1 {
 	rxresphdrs
 	expect resp.status == 200
 	rxchunk
-	sema r1 sync 2
+	barrier b1 sync
 	expect_close
 } -run
 
@@ -43,7 +46,7 @@ client c1 {
 	rxresphdrs
 	expect resp.status == 200
 	rxchunk
-	sema r1 sync 2
+	barrier b2 sync
 	expect_close
 } -run
 
diff --git a/bin/varnishtest/tests/r01478.vtc b/bin/varnishtest/tests/r01478.vtc
index 1df49a6..a6844c4 100644
--- a/bin/varnishtest/tests/r01478.vtc
+++ b/bin/varnishtest/tests/r01478.vtc
@@ -1,23 +1,28 @@
 varnishtest "panic due to hash_ignore_busy"
 
+barrier b1 cond 2
+barrier b2 cond 2
+barrier b3 cond 2
+barrier b4 cond 2
+
 server s1 {
 	rxreq
 	txresp -nolen -hdr "Transfer-Encoding: chunked"
 	chunkedlen 10
 	delay .5
-	sema r1 sync 2
+	barrier b1 sync
 	delay .5
 	chunkedlen 10
 	delay .5
-	sema r2 sync 2
+	barrier b2 sync
 	delay .5
 	chunkedlen 10
 	delay .5
-	sema r3 sync 2
+	barrier b3 sync
 	delay .5
 	chunkedlen 10
 	delay .5
-	sema r4 sync 2
+	barrier b4 sync
 	delay .5
 	chunkedlen 10
 	delay .5
@@ -41,17 +46,17 @@ client c1 {
 	rxresp
 } -start
 
-sema r1 sync 2
+barrier b1 sync
 client c2 {
 	txreq -hdr "client: c2"
-	sema r2 sync 2
+	barrier b2 sync
 	rxresp
 } -start
 
-sema r3 sync 2
+barrier b3 sync
 client c3 {
 	txreq -hdr "client: c3"
-	sema r4 sync 2
+	barrier b4 sync
 	rxresp
 } -start
 
diff --git a/bin/varnishtest/tests/r01646.vtc b/bin/varnishtest/tests/r01646.vtc
index 951350e..10b640e 100644
--- a/bin/varnishtest/tests/r01646.vtc
+++ b/bin/varnishtest/tests/r01646.vtc
@@ -1,12 +1,15 @@
 varnishtest "cond/stream race ?"
 
+barrier b1 cond 3
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	txresp -nolen -hdr "Transfer-Encoding: chunked" -hdr "Etag: foo"
 	chunkedlen 32
-	sema r1 sync 3
+	barrier b1 sync
 	chunkedlen 32
-	sema r2 sync 2
+	barrier b2 sync
 	chunkedlen 32
 	chunkedlen 0
 } -start
@@ -35,17 +38,17 @@ varnish v1 -cliok "param.set debug +syncvsl"
 client c1 {
 	txreq
 	rxresphdrs
-	sema r1 sync 3
+	barrier b1 sync
 	rxrespbody
 	expect resp.bodylen == 96
 } -start
 
 client c2 {
-	sema r1 sync 3
+	barrier b1 sync
 	delay 2
 	txreq -hdr "foo: s2"
 	rxresphdrs
-	sema r2 sync 2
+	barrier b2 sync
 	rxrespbody
 	expect resp.bodylen == 96
 } -start
diff --git a/bin/varnishtest/tests/r01648.vtc b/bin/varnishtest/tests/r01648.vtc
index de0c364..1a8cef9 100644
--- a/bin/varnishtest/tests/r01648.vtc
+++ b/bin/varnishtest/tests/r01648.vtc
@@ -1,10 +1,12 @@
 varnishtest "#1648 - corrupt object in cache through IMS update"
 
+barrier b1 cond 3
+
 # This server sends a broken response body
 server s1 {
 	rxreq
 	txresp -nolen -hdr "Transfer-Encoding: chunked" -hdr "Etag: \"foo\"" -hdr "Server: s1"
-	sema r1 sync 3
+	barrier b1 sync
 	delay 1
 	chunked "abc"
 } -start
@@ -13,7 +15,7 @@ server s1 {
 server s2 {
 	rxreq
 	expect req.http.If-None-Match == "\"foo\""
-	sema r1 sync 3
+	barrier b1 sync
 	txresp -status 304 -nolen -hdr "Server: s2"
 } -start
 
@@ -58,7 +60,7 @@ delay 1
 # IMS update by s2
 client c2 {
 	txreq -hdr "Client: c2"
-	sema r1 sync 3
+	barrier b1 sync
 	rxresphdrs
 	expect resp.status == 200
 	expect resp.http.transfer-encoding == "chunked"
diff --git a/bin/varnishtest/tests/r01737.vtc b/bin/varnishtest/tests/r01737.vtc
index 66c5aee..182d1f0 100644
--- a/bin/varnishtest/tests/r01737.vtc
+++ b/bin/varnishtest/tests/r01737.vtc
@@ -1,5 +1,7 @@
 varnishtest "#1737 - ESI sublevel session close"
 
+barrier b1 cond 2
+
 # Build a esi request tree that fails on flush before include at two different
 # levels. Synchronize a client close after the response headers have been
 # received by the client. This produces write erros for the body parts in all
@@ -7,7 +9,7 @@ varnishtest "#1737 - ESI sublevel session close"
 server s1 {
 	rxreq
 	txresp -body {<esi:include src="/bar"/><esi:include src="/bar"/>}
-	sema r1 sync 2
+	barrier b1 sync
 
 	rxreq
 	delay 1
@@ -31,7 +33,7 @@ varnish v1 -vcl+backend {
 client c1 {
 	txreq
 	rxresp -no_obj
-	sema r1 sync 2
+	barrier b1 sync
 } -run
 
 delay 3
diff --git a/bin/varnishtest/tests/r01818.vtc b/bin/varnishtest/tests/r01818.vtc
index ee887a8..2fe8ae3 100644
--- a/bin/varnishtest/tests/r01818.vtc
+++ b/bin/varnishtest/tests/r01818.vtc
@@ -1,5 +1,8 @@
 varnishtest "#1818: verify that grace works for hit_for_pass objects"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	expect req.http.a == "1"
@@ -7,15 +10,15 @@ server s1 {
 
 	rxreq
 	expect req.http.b == "1"
-	sema r2 sync 2
-	sema r1 sync 2
+	barrier b2 sync
+	barrier b1 sync
 	txresp
 } -start
 
 server s2 {
 	rxreq
 	expect req.http.c == "1"
-	sema r1 sync 2
+	barrier b1 sync
 	txresp
 } -start
 
@@ -68,7 +71,7 @@ client c1 {
 } -start
 
 client c2 {
-	sema r2 sync 2
+	barrier b2 sync
 	txreq -hdr "c: 1"
 	rxresp
 	expect resp.http.pass == "1"
diff --git a/bin/varnishtest/tests/s00001.vtc b/bin/varnishtest/tests/s00001.vtc
index 0223916..77fe6fe 100644
--- a/bin/varnishtest/tests/s00001.vtc
+++ b/bin/varnishtest/tests/s00001.vtc
@@ -1,10 +1,12 @@
 varnishtest "Simple expiry test (fully reaped object)"
 
+barrier b1 cond 2
+
 server s1 {
 	rxreq
 	expect req.url == "/"
 	txresp -hdr "Cache-control: max-age = 1" -body "1111\n"
-	sema r1 sync 2
+	barrier b1 sync
 	rxreq
 	expect req.url == "/"
 	txresp -hdr "Cache-control: max-age = 1" -body "22222\n"
@@ -23,7 +25,7 @@ client c1 {
 	expect resp.status == 200
 } -run
 
-sema r1 sync 2
+barrier b1 sync
 delay 1.1
 
 client c2 {
diff --git a/bin/varnishtest/tests/s00002.vtc b/bin/varnishtest/tests/s00002.vtc
index 10049c0..3d8442e 100644
--- a/bin/varnishtest/tests/s00002.vtc
+++ b/bin/varnishtest/tests/s00002.vtc
@@ -1,5 +1,8 @@
 varnishtest "Check grace with sick backends"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	expect req.url == "/"
@@ -11,7 +14,7 @@ server s1 {
 	expect req.url == "/"
 	txresp -proto HTTP/1.0 -hdr "nbr: 2" -body "hi"
 
-	sema r1 sync 2
+	barrier b1 sync
 	accept
 
 	rxreq
@@ -30,7 +33,7 @@ server s1 {
 	txresp -proto HTTP/1.0 -status 400 -hdr "nbr: 5" -body "hi"
 	accept
 
-	sema r1 sync 2
+	barrier b2 sync
 
 } -start
 
@@ -53,7 +56,7 @@ varnish v1 -vcl {
 	}
 } -start
 
-sema r1 sync 2
+barrier b1 sync
 
 client c1 {
 	txreq -url "/"
@@ -62,7 +65,7 @@ client c1 {
 	expect resp.status == 200
 } -run
 
-sema r1 sync 2
+barrier b2 sync
 
 client c2 {
 	txreq -url "/"
diff --git a/bin/varnishtest/tests/v00010.vtc b/bin/varnishtest/tests/v00010.vtc
index 7b0d57e..9d2253e 100644
--- a/bin/varnishtest/tests/v00010.vtc
+++ b/bin/varnishtest/tests/v00010.vtc
@@ -1,5 +1,8 @@
 varnishtest "VCL: check panic and restart"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
 	txresp -hdr "Foo: bar" -body "abcdef\n"
@@ -7,7 +10,7 @@ server s1 {
 	txresp -hdr "Panic: fetch" -body "012345\n"
 	close
 
-	sema r1 sync 2
+	barrier b1 sync
 	accept
 	rxreq
 	txresp -hdr "Foo: bar" -body "abcdef\n"
@@ -15,7 +18,7 @@ server s1 {
 	txresp -hdr "Panic: deliver" -body "012345\n"
 	close
 
-	sema r1 sync 2
+	barrier b2 sync
 	accept
 	rxreq
 	txresp -hdr "Foo: foo" -body "abcdef\n"
@@ -53,7 +56,7 @@ varnish v1 -expect MGT.child_panic == 1
 varnish v1 -clierr 300 "panic.clear"
 varnish v1 -cliok "start"
 varnish v1 -wait-running
-sema r1 sync 2
+barrier b1 sync
 
 delay 0.5
 
@@ -71,7 +74,7 @@ varnish v1 -expect MGT.child_panic == 0
 varnish v1 -clierr 300 "panic.clear"
 varnish v1 -cliok "start"
 varnish v1 -wait-running
-sema r1 sync 2
+barrier b2 sync
 
 delay 0.5
 
diff --git a/bin/varnishtest/tests/v00012.vtc b/bin/varnishtest/tests/v00012.vtc
index e7c8d44..f68e26a 100644
--- a/bin/varnishtest/tests/v00012.vtc
+++ b/bin/varnishtest/tests/v00012.vtc
@@ -1,9 +1,12 @@
 varnishtest "Check backend connection limit"
 
+barrier b1 cond 2
+barrier b2 cond 2
+
 server s1 {
 	rxreq
-	sema r1 sync 2
-	sema r2 sync 2
+	barrier b1 sync
+	barrier b2 sync
 	txresp
 } -start
 
@@ -27,13 +30,13 @@ client c1 {
 
 
 client c2 {
-	sema r1 sync 2
+	barrier b1 sync
 	txreq
 	rxresp
 	expect resp.status == 503
 } -run
 
-sema r2 sync 2
+barrier b2 sync
 client c1 -wait
 
 varnish v1 -expect backend_busy == 1
diff --git a/bin/varnishtest/tests/v00014.vtc b/bin/varnishtest/tests/v00014.vtc
index 4a290b0..d24f1a4 100644
--- a/bin/varnishtest/tests/v00014.vtc
+++ b/bin/varnishtest/tests/v00014.vtc
@@ -1,18 +1,23 @@
 varnishtest "Check req.backend.healthy"
 
+barrier b1 cond 2
+barrier b2 cond 2
+barrier b3 cond 2
+barrier b4 cond 2
+
 server s1 {
 	rxreq
-	sema r1 sync 2
+	barrier b1 sync
 	expect req.url == "/"
 	txresp -body "slash"
 	accept
 	rxreq
-	sema r2 sync 2
-	sema r3 sync 2
+	barrier b2 sync
+	barrier b3 sync
 	expect req.url == "/"
 	txresp -body "slash"
 	accept
-	sema r4 sync 2
+	barrier b4 sync
 } -start
 
 varnish v1 -vcl {
@@ -51,15 +56,15 @@ client c1 {
 	rxresp
 	expect resp.status == 500
 
-	sema r1 sync 2
+	barrier b1 sync
 
-	sema r2 sync 2
+	barrier b2 sync
 	txreq
 	rxresp
 	expect resp.status == 500
 
-	sema r3 sync 2
-	sema r4 sync 2
+	barrier b3 sync
+	barrier b4 sync
 	txreq
 	rxresp
 	expect resp.status == 200
diff --git a/bin/varnishtest/vtc.c b/bin/varnishtest/vtc.c
index 136f0ee..1a944cc 100644
--- a/bin/varnishtest/vtc.c
+++ b/bin/varnishtest/vtc.c
@@ -626,7 +626,6 @@ static const struct cmds cmds[] = {
 	{ "varnishtest",cmd_varnishtest },
 	{ "shell",	cmd_shell },
 	{ "err_shell",	cmd_err_shell },
-	{ "sema",	cmd_sema },
 	{ "barrier",	cmd_barrier },
 	{ "random",	cmd_random },
 	{ "feature",	cmd_feature },
@@ -650,7 +649,6 @@ exec_file(const char *fn, const char *script, const char *tmpdir,
 	AN(vltop);
 
 	init_macro();
-	init_sema();
 	init_barrier();
 	init_server();
 
diff --git a/bin/varnishtest/vtc.h b/bin/varnishtest/vtc.h
index 584b1ba..23095d4 100644
--- a/bin/varnishtest/vtc.h
+++ b/bin/varnishtest/vtc.h
@@ -61,7 +61,6 @@ cmd_f cmd_delay;
 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,7 +73,6 @@ extern unsigned vtc_maxdur;
 extern int vtc_witness;
 extern int feature_dns;
 
-void init_sema(void);
 void init_barrier(void);
 void init_server(void);
 
diff --git a/bin/varnishtest/vtc_http.c b/bin/varnishtest/vtc_http.c
index 0214b0d..2ebab8a 100644
--- a/bin/varnishtest/vtc_http.c
+++ b/bin/varnishtest/vtc_http.c
@@ -1354,7 +1354,6 @@ static const struct cmds http_cmds[] = {
 	{ "chunkedlen",		cmd_http_chunkedlen },
 	{ "delay",		cmd_delay },
 	{ "barrier",		cmd_barrier },
-	{ "sema",		cmd_sema },
 	{ "expect_close",	cmd_http_expect_close },
 	{ "close",		cmd_http_close },
 	{ "accept",		cmd_http_accept },
diff --git a/bin/varnishtest/vtc_sema.c b/bin/varnishtest/vtc_sema.c
deleted file mode 100644
index 1cab9d1..0000000
--- a/bin/varnishtest/vtc_sema.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*-
- * Copyright (c) 2008-2010 Varnish Software AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <[email protected]>
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "vtc.h"
-
-struct sema {
-	unsigned		magic;
-#define SEMA_MAGIC		0x29b64317
-	char			*name;
-	VTAILQ_ENTRY(sema)	list;
-	pthread_mutex_t		mtx;
-	pthread_cond_t		cond;
-
-	unsigned		waiters;
-	unsigned		expected;
-};
-
-static pthread_mutex_t		sema_mtx;
-static VTAILQ_HEAD(, sema)	semas = VTAILQ_HEAD_INITIALIZER(semas);
-
-/**********************************************************************
- * Allocate and initialize a sema
- */
-
-static struct sema *
-sema_new(char *name, struct vtclog *vl)
-{
-	struct sema *r;
-
-	ALLOC_OBJ(r, SEMA_MAGIC);
-	AN(r);
-	AN(name);
-	if (*name != 'r')
-		vtc_log(vl, 0, "Sema name must start with 'r' (%s)", name);
-	r->name = name;
-
-	AZ(pthread_mutex_init(&r->mtx, NULL));
-	AZ(pthread_cond_init(&r->cond, NULL));
-	r->waiters = 0;
-	r->expected = 0;
-	VTAILQ_INSERT_TAIL(&semas, r, list);
-	return (r);
-}
-
-/**********************************************************************
- * Sync a sema
- */
-
-static void
-sema_sync(struct sema *r, const char *av, struct vtclog *vl)
-{
-	unsigned u;
-
-	CHECK_OBJ_NOTNULL(r, SEMA_MAGIC);
-	u = strtoul(av, NULL, 0);
-
-	if (r->expected == 0)
-		r->expected = u;
-	if (r->expected != u)
-		vtc_log(vl, 0,
-		    "Sema(%s) use error: different expectations (%u vs %u)",
-		    r->name, r->expected, u);
-
-	if (++r->waiters == r->expected) {
-		vtc_log(vl, 4, "Sema(%s) wake %u", r->name, r->expected);
-		AZ(pthread_cond_broadcast(&r->cond));
-		r->waiters = 0;
-		r->expected = 0;
-	} else {
-		vtc_log(vl, 4, "Sema(%s) wait %u of %u",
-		    r->name, r->waiters, r->expected);
-		AZ(pthread_cond_wait(&r->cond, &r->mtx));
-	}
-}
-
-/**********************************************************************
- * Semaphore command dispatch
- */
-
-void
-cmd_sema(CMD_ARGS)
-{
-	struct sema *r, *r2;
-
-	(void)priv;
-	(void)cmd;
-
-	if (av == NULL) {
-		AZ(pthread_mutex_lock(&sema_mtx));
-		/* Reset and free */
-		VTAILQ_FOREACH_SAFE(r, &semas, list, r2) {
-			AZ(pthread_mutex_lock(&r->mtx));
-			AZ(r->waiters);
-			AZ(r->expected);
-			AZ(pthread_mutex_unlock(&r->mtx));
-		}
-		AZ(pthread_mutex_unlock(&sema_mtx));
-		return;
-	}
-
-	AZ(strcmp(av[0], "sema"));
-	av++;
-
-	AZ(pthread_mutex_lock(&sema_mtx));
-	VTAILQ_FOREACH(r, &semas, list)
-		if (!strcmp(r->name, av[0]))
-			break;
-	if (r == NULL)
-		r = sema_new(av[0], vl);
-	av++;
-	AZ(pthread_mutex_lock(&r->mtx));
-	AZ(pthread_mutex_unlock(&sema_mtx));
-
-	for (; *av != NULL; av++) {
-		if (!strcmp(*av, "sync")) {
-			av++;
-			AN(*av);
-			sema_sync(r, *av, vl);
-			continue;
-		}
-		vtc_log(vl, 0, "Unknown sema argument: %s", *av);
-	}
-	AZ(pthread_mutex_unlock(&r->mtx));
-}
-
-void
-init_sema(void)
-{
-	AZ(pthread_mutex_init(&sema_mtx, NULL));
-}
-- 
2.4.3

From aa04d6f30ff6091218386e3659eb1c4bcbcf3022 Mon Sep 17 00:00:00 2001
From: Dridi Boukelmoune <[email protected]>
Date: Wed, 23 Dec 2015 16:24:02 +0100
Subject: [PATCH 4/6] Barriers can only be created on the top thread

This is similar ASSERT_CLI, in order to make socket barriers creation
thread-safe.
---
 bin/varnishtest/vtc_barrier.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/bin/varnishtest/vtc_barrier.c b/bin/varnishtest/vtc_barrier.c
index b170c56..ba80cfb 100644
--- a/bin/varnishtest/vtc_barrier.c
+++ b/bin/varnishtest/vtc_barrier.c
@@ -70,6 +70,9 @@ barrier_new(char *name, struct vtclog *vl)
 	AN(name);
 	if (*name != 'b')
 		vtc_log(vl, 0, "Barrier name must start with 'b' (%s)", name);
+	if (pthread_self() != vtc_thread)
+		vtc_log(vl, 0,
+		    "Barrier %s can only be created on the top thread", name);
 	REPLACE(b->name, name);
 
 	AZ(pthread_mutex_init(&b->mtx, NULL));
-- 
2.4.3

From 6d080f4ddc8b282a439ec712a28cf9973038459c Mon Sep 17 00:00:00 2001
From: Dridi Boukelmoune <[email protected]>
Date: Wed, 23 Dec 2015 17:29:24 +0100
Subject: [PATCH 5/6] Implement socket barriers (shared between processes)

When varnishtest creates a socket barrier, it will bind a socket and
listen to incoming connections. Once the number of expected connections
is open, connections are closed.

Barrier users only need to connect to the socket, read "nothing" and
block until the connection is closed. It allows virtually any process
to sync with varnishtest. The barrier will provide macros with its
socket information.
---
 bin/varnishtest/tests/a00013.vtc |  64 ++++++++++++++
 bin/varnishtest/vtc_barrier.c    | 180 +++++++++++++++++++++++++++++++++++++--
 2 files changed, 237 insertions(+), 7 deletions(-)
 create mode 100644 bin/varnishtest/tests/a00013.vtc

diff --git a/bin/varnishtest/tests/a00013.vtc b/bin/varnishtest/tests/a00013.vtc
new file mode 100644
index 0000000..91bfce0
--- /dev/null
+++ b/bin/varnishtest/tests/a00013.vtc
@@ -0,0 +1,64 @@
+varnishtest "Barrier operations"
+
+# same as a00008.vtc, with socket barriers instead
+
+# bs -> server, bc -> client, bb -> both
+barrier bs sock 4
+barrier bc sock 4
+barrier bb sock 4 -cyclic
+
+server s1 {
+	rxreq
+	barrier bs sync
+	barrier bb sync
+	delay .9
+	txresp
+} -start
+
+server s2 {
+	rxreq
+	barrier bs sync
+	barrier bb sync
+	delay .6
+	txresp
+} -start
+
+server s3 {
+	rxreq
+	barrier bs sync
+	barrier bb sync
+	delay .2
+	txresp
+} -start
+
+client c1 -connect ${s1_sock} {
+	delay .2
+	txreq
+	rxresp
+	barrier bc sync
+	barrier bb sync
+} -start
+
+client c2 -connect ${s2_sock} {
+	delay .6
+	txreq
+	rxresp
+	barrier bc sync
+	barrier bb sync
+} -start
+
+client c3 -connect ${s3_sock} {
+	delay .9
+	txreq
+	rxresp
+	barrier bc sync
+	barrier bb sync
+} -start
+
+# Wait for all servers to have received requests
+barrier bs sync
+barrier bb sync
+
+# Wait for all clients to have received responses
+barrier bc sync
+barrier bb sync
diff --git a/bin/varnishtest/vtc_barrier.c b/bin/varnishtest/vtc_barrier.c
index ba80cfb..47ac4dc 100644
--- a/bin/varnishtest/vtc_barrier.c
+++ b/bin/varnishtest/vtc_barrier.c
@@ -28,13 +28,19 @@
 
 #include "config.h"
 
+#include <errno.h>
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
+#include <sys/select.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
 #include "vtc.h"
+#include "vtcp.h"
 
 enum barrier_e {
 	BARRIER_NONE = 0,
@@ -55,6 +61,9 @@ struct barrier {
 	unsigned		cyclic;
 
 	enum barrier_e		type;
+	/* fields below are only for BARRIER_SOCK */
+	pthread_t		thread;
+	volatile unsigned	active;
 };
 
 static pthread_mutex_t		barrier_mtx;
@@ -116,6 +125,108 @@ barrier_cond(struct barrier *b, const char *av, struct vtclog *vl)
 	b->type = BARRIER_COND;
 }
 
+static void *
+barrier_sock_thread(void *priv)
+{
+	struct barrier *b;
+	struct vtclog *vl;
+	struct timeval tmo;
+	const char *err;
+	char abuf[16], pbuf[6];
+	int i, sock, *conns;
+	fd_set rfds;
+
+	CAST_OBJ_NOTNULL(b, priv, BARRIER_MAGIC);
+	assert(b->type == BARRIER_SOCK);
+
+	AZ(pthread_mutex_lock(&b->mtx));
+
+	vl = vtc_logopen(b->name);
+	AN(vl);
+
+	sock = VTCP_listen_on("127.0.0.1:0", NULL, b->expected, &err);
+	if (sock < 0) {
+		pthread_cond_signal(&b->cond);
+		AZ(pthread_mutex_unlock(&b->mtx));
+		vtc_log(vl, 0, "Barrier(%s) %s fails: %s (errno=%d)",
+		    b->name, err, strerror(errno), errno);
+	}
+	assert(sock > 0);
+	(void)VTCP_nonblocking(sock);
+	VTCP_myname(sock, abuf, sizeof abuf, pbuf, sizeof pbuf);
+
+	macro_def(vl, b->name, "addr", "%s", abuf);
+	macro_def(vl, b->name, "port", "%s", pbuf);
+	macro_def(vl, b->name, "sock", "%s:%s", abuf, pbuf);
+
+	pthread_cond_signal(&b->cond);
+	AZ(pthread_mutex_unlock(&b->mtx));
+
+	conns = calloc(b->expected, sizeof *conns);
+	AN(conns);
+
+	while (b->active) {
+		FD_ZERO(&rfds);
+		FD_SET(sock, &rfds);
+
+		tmo.tv_sec = 1;
+		tmo.tv_usec = 0;
+		i = select(sock + 1, &rfds, NULL, NULL, &tmo);
+		if (i == 0)
+			continue;
+		if (i < 0) {
+			if (errno == EINTR)
+				continue;
+			AZ(close(sock));
+			vtc_log(vl, 0,
+			    "Barrier(%s) select fails: %s (errno=%d)",
+			    b->name, strerror(errno), errno);
+		}
+		assert(i == 1);
+		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);
+
+		i = accept(sock, NULL, NULL);
+		if (i < 0) {
+			AZ(close(sock));
+			vtc_log(vl, 0,
+			    "Barrier(%s) accept fails: %s (errno=%d)",
+			    b->name, strerror(errno), errno);
+		}
+
+		/* NB. We don't keep track of the established connections, only
+		 *     that connections were made to the barrier's socket.
+		 */
+		conns[b->waiters] = i;
+
+		if (++b->waiters < b->expected) {
+			vtc_log(vl, 4, "Barrier(%s) wait %u of %u",
+			    b->name, b->waiters, b->expected);
+			continue;
+		}
+
+		vtc_log(vl, 4, "Barrier(%s) wake %u", b->name, b->expected);
+		for (i = 0; i < b->expected; i++)
+			AZ(close(conns[i]));
+
+		if (b->cyclic)
+			b->waiters = 0;
+		else
+			b->active = 0;
+	}
+
+	macro_undef(vl, b->name, "addr");
+	macro_undef(vl, b->name, "port");
+	macro_undef(vl, b->name, "sock");
+	AZ(close(sock));
+
+	return (NULL);
+}
+
 static void
 barrier_sock(struct barrier *b, const char *av, struct vtclog *vl)
 {
@@ -123,7 +234,13 @@ 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();
+	b->active = 1;
+
+	/* NB. We can use the BARRIER_COND's pthread_cond_t to wait until the
+	 *     socket is ready for convenience.
+	 */
+	AZ(pthread_create(&b->thread, NULL, barrier_sock_thread, b));
+	AZ(pthread_cond_wait(&b->cond, &b->mtx));
 }
 
 static void
@@ -175,6 +292,46 @@ barrier_cond_sync(struct barrier *b, struct vtclog *vl)
 }
 
 static void
+barrier_sock_sync(struct barrier *b, struct vtclog *vl)
+{
+	struct vsb *vsb;
+	const char *err;
+	char buf[32];
+	int i, sock;
+	ssize_t sz;
+
+	CHECK_OBJ_NOTNULL(b, BARRIER_MAGIC);
+	assert(b->type == BARRIER_SOCK);
+
+	i = snprintf(buf, sizeof buf, "${%s_sock}", b->name);
+	assert(i > 0 && i < sizeof buf);
+	vsb = macro_expand(vl, buf);
+	vtc_log(vl, 4, "Barrier(%s) sync with socket", b->name);
+
+	sock = VTCP_open(VSB_data(vsb), NULL, 0., &err);
+	if (sock < 0)
+		vtc_log(vl, 0, "Barrier(%s) connection failed: %s",
+		    b->name, err);
+
+	VSB_delete(vsb);
+
+	/* emulate pthread_cond_wait's behavior */
+	AZ(pthread_mutex_unlock(&b->mtx));
+	sz = read(sock, buf, sizeof buf); /* XXX loop with timeout? */
+	AZ(pthread_mutex_lock(&b->mtx));
+
+	i = errno;
+	AZ(close(sock));
+
+	if (sz < 0)
+		vtc_log(vl, 0, "Barrier(%s) connection failed: %s (errno=%d)",
+		    b->name, strerror(i), i);
+	if (sz > 0)
+		vtc_log(vl, 0, "Barrier(%s) unexpected data (%ldB)",
+		    b->name, sz);
+}
+
+static void
 barrier_sync(struct barrier *b, struct vtclog *vl)
 {
 
@@ -188,7 +345,7 @@ barrier_sync(struct barrier *b, struct vtclog *vl)
 		barrier_cond_sync(b, vl);
 		break;
 	case BARRIER_SOCK:
-		INCOMPL();
+		barrier_sock_sync(b, vl);
 		break;
 	default:
 		WRONG("Wrong barrier type");
@@ -212,11 +369,20 @@ cmd_barrier(CMD_ARGS)
 		/* Reset and free */
 		VTAILQ_FOREACH_SAFE(b, &barriers, list, b2) {
 			AZ(pthread_mutex_lock(&b->mtx));
-			assert(b->type != BARRIER_NONE);
-			if (b->cyclic)
-				AZ(b->waiters);
-			else
-				assert(b->waiters == b->expected);
+			switch (b->type) {
+			case BARRIER_COND:
+				if (b->cyclic)
+					AZ(b->waiters);
+				else
+					assert(b->waiters == b->expected);
+				break;
+			case BARRIER_SOCK:
+				b->active = 0;
+				AZ(pthread_join(b->thread, NULL));
+				break;
+			default:
+				WRONG("Wrong barrier type");
+			}
 			AZ(pthread_mutex_unlock(&b->mtx));
 		}
 		AZ(pthread_mutex_unlock(&barrier_mtx));
-- 
2.4.3

From 537055095b8224cc56deb14b9126c369b1abdc41 Mon Sep 17 00:00:00 2001
From: Dridi Boukelmoune <[email protected]>
Date: Thu, 24 Dec 2015 10:28:46 +0100
Subject: [PATCH 6/6] Teach vmod-debug how to sync with varnishtest

---
 bin/varnishtest/tests/m00023.vtc | 39 +++++++++++++++++++++++++++++++++++++++
 lib/libvmod_debug/vmod.vcc       |  4 ++++
 lib/libvmod_debug/vmod_debug.c   | 33 +++++++++++++++++++++++++++++++++
 3 files changed, 76 insertions(+)
 create mode 100644 bin/varnishtest/tests/m00023.vtc

diff --git a/bin/varnishtest/tests/m00023.vtc b/bin/varnishtest/tests/m00023.vtc
new file mode 100644
index 0000000..93c56ee
--- /dev/null
+++ b/bin/varnishtest/tests/m00023.vtc
@@ -0,0 +1,39 @@
+varnishtest "Test debug.barrier_sync"
+
+barrier b1 sock 2
+barrier b2 sock 2
+
+server s1 {
+	rxreq
+	txresp
+} -start
+
+varnish v1 -vcl+backend {
+	import ${vmod_debug};
+
+	sub vcl_recv {
+		if (!debug.barrier_sync("${b1_sock}")) {
+			return (synth(400));
+		}
+	}
+
+	sub vcl_backend_response {
+		if (!debug.barrier_sync("${b2_sock}")) {
+			return (abandon);
+		}
+	}
+} -start
+
+varnish v1 -cliok "param.set debug +syncvsl"
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+} -start
+
+barrier b1 sync
+delay 0.5
+barrier b2 sync
+
+client c1 -wait
diff --git a/lib/libvmod_debug/vmod.vcc b/lib/libvmod_debug/vmod.vcc
index 74c8c12..e68798d 100644
--- a/lib/libvmod_debug/vmod.vcc
+++ b/lib/libvmod_debug/vmod.vcc
@@ -142,3 +142,7 @@ Find how much unallocated space there is left in a workspace.
 $Function VOID vcl_release_delay(DURATION)
 
 Hold a reference to the VCL when it goes cold for the given delay.
+
+$Function BOOL barrier_sync(STRING)
+
+Synchronize with a varnishtest shared barrier.
diff --git a/lib/libvmod_debug/vmod_debug.c b/lib/libvmod_debug/vmod_debug.c
index a9e2cde..39043ab 100644
--- a/lib/libvmod_debug/vmod_debug.c
+++ b/lib/libvmod_debug/vmod_debug.c
@@ -28,6 +28,7 @@
 
 #include "config.h"
 
+#include <errno.h>
 #include <pthread.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -37,6 +38,7 @@
 #include "vcl.h"
 #include "vrt.h"
 #include "vsb.h"
+#include "vtcp.h"
 #include "vtim.h"
 #include "vcc_if.h"
 
@@ -415,3 +417,34 @@ vmod_vcl_release_delay(VRT_CTX, VCL_DURATION delay)
 	assert(delay > 0.0);
 	vcl_release_delay = delay;
 }
+
+VCL_BOOL
+vmod_barrier_sync(VRT_CTX, VCL_STRING addr)
+{
+	const char *err;
+	char buf[32];
+	int sock;
+	ssize_t sz;
+
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	AN(addr);
+	AN(*addr);
+
+	VSLb(ctx->vsl, SLT_VCL_call, "barrier_sync(\"%s\")", addr);
+	sock = VTCP_open(addr, NULL, 0., &err);
+	if (sock < 0) {
+		VSLb(ctx->vsl, SLT_Error, "Barrier connection failed: %s", err);
+		return (0);
+	}
+
+	sz = read(sock, buf, sizeof buf);
+	if (sz == 0)
+		return (1);
+	if (sz < 0)
+		VSLb(ctx->vsl, SLT_Error,
+		    "Barrier connection failed: %s (errno=%d)",
+		    strerror(errno), errno);
+	if (sz > 0)
+		VSLb(ctx->vsl, SLT_Error, "Barrier unexpected data (%ldB)", sz);
+	return (0);
+}
-- 
2.4.3

_______________________________________________
varnish-dev mailing list
[email protected]
https://www.varnish-cache.org/lists/mailman/listinfo/varnish-dev

Reply via email to