Commit 4037d758 authored by Dridi Boukelmoune's avatar Dridi Boukelmoune

Introduce barriers in varnishtest

They work like semaphores, except that they need explicit initialization
and can optionally be shared between processes.
parent d6ed2444
......@@ -27,6 +27,7 @@ varnishtest_SOURCES = \
vtc.h \
vmods.h \
programs.h \
vtc_barrier.c \
vtc_client.c \
vtc_http.c \
vtc_main.c \
......
......@@ -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
......
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
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
......@@ -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 */
......
......@@ -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);
......
/*-
* Copyright (c) 2005 Varnish Software AS
* All rights reserved.
*
* Author: Dridi Boukelmoune <dridi@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));
}
......@@ -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 },
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment