[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