From 5fd5216cf802889b6d621dd7f844495db867a224 Mon Sep 17 00:00:00 2001 From: ozaki-r Date: Thu, 28 May 2015 10:19:17 +0000 Subject: [PATCH] Make the test stable under load or when running on a slow machine Let sender and receiver synchronize explicitly via a socketpair and don't rely on sleep. --- tests/net/mcast/mcast.c | 85 +++++++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 12 deletions(-) diff --git a/tests/net/mcast/mcast.c b/tests/net/mcast/mcast.c index 36d5050b5e34..ad2c9b39b9a7 100644 --- a/tests/net/mcast/mcast.c +++ b/tests/net/mcast/mcast.c @@ -1,4 +1,4 @@ -/* $NetBSD: mcast.c,v 1.2 2015/05/28 08:32:53 ozaki-r Exp $ */ +/* $NetBSD: mcast.c,v 1.3 2015/05/28 10:19:17 ozaki-r Exp $ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. @@ -30,7 +30,7 @@ */ #include #ifdef __RCSID -__RCSID("$NetBSD: mcast.c,v 1.2 2015/05/28 08:32:53 ozaki-r Exp $"); +__RCSID("$NetBSD: mcast.c,v 1.3 2015/05/28 10:19:17 ozaki-r Exp $"); #else extern const char *__progname; #define getprogname() __progname @@ -59,6 +59,7 @@ extern const char *__progname; #include #define ERRX(ev, msg, ...) ATF_REQUIRE_MSG(0, msg, __VA_ARGS__) +#define ERRX0(ev, msg) ATF_REQUIRE_MSG(0, msg) #define SKIPX(ev, msg, ...) do { \ atf_tc_skip(msg, __VA_ARGS__); \ @@ -67,6 +68,7 @@ extern const char *__progname; #else #define ERRX(ev, msg, ...) errx(ev, msg, __VA_ARGS__) +#define ERRX0(ev, msg) errx(ev, msg) #define SKIPX(ev, msg, ...) errx(ev, msg, __VA_ARGS__) #endif @@ -232,8 +234,38 @@ out: return s; } -static void -sender(const char *host, const char *port, size_t n, bool conn, bool bug) +static int +synchronize(const int fd, bool waiter) +{ + int syncmsg = 0; + int r; + struct pollfd pfd; + + if (waiter) { + pfd.fd = fd; + pfd.events = POLLIN; + + /* We use poll to avoid lock up when the peer died unexpectedly */ + r = poll(&pfd, 1, 10000); + if (r == -1) + ERRX(EXIT_FAILURE, "poll (%s)", strerror(errno)); + if (r == 0) + /* Timed out */ + return -1; + + if (read(fd, &syncmsg, sizeof(syncmsg)) == -1) + ERRX(EXIT_FAILURE, "read (%s)", strerror(errno)); + } else { + if (write(fd, &syncmsg, sizeof(syncmsg)) == -1) + ERRX(EXIT_FAILURE, "write (%s)", strerror(errno)); + } + + return 0; +} + +static int +sender(const int fd, const char *host, const char *port, size_t n, bool conn, + bool bug) { int s; ssize_t l; @@ -242,6 +274,11 @@ sender(const char *host, const char *port, size_t n, bool conn, bool bug) socklen_t slen; s = getsocket(host, port, conn ? connect : connector, &slen, bug); + + /* Wait until receiver gets ready. */ + if (synchronize(fd, true) == -1) + return -1; + for (msg.seq = 0; msg.seq < n; msg.seq++) { #ifdef CLOCK_MONOTONIC if (clock_gettime(CLOCK_MONOTONIC, &msg.ts) == -1) @@ -261,10 +298,17 @@ sender(const char *host, const char *port, size_t n, bool conn, bool bug) ERRX(EXIT_FAILURE, "send (%s)", strerror(errno)); usleep(100); } + + /* Wait until receiver finishes its work. */ + if (synchronize(fd, true) == -1) + return -1; + + return 0; } static void -receiver(const char *host, const char *port, size_t n, bool conn, bool bug) +receiver(const int fd, const char *host, const char *port, size_t n, bool conn, + bool bug) { int s; ssize_t l; @@ -276,6 +320,10 @@ receiver(const char *host, const char *port, size_t n, bool conn, bool bug) s = getsocket(host, port, bind, &slen, bug); pfd.fd = s; pfd.events = POLLIN; + + /* Tell I'm ready */ + synchronize(fd, false); + for (seq = 0; seq < n; seq++) { if (poll(&pfd, 1, 10000) == -1) ERRX(EXIT_FAILURE, "poll (%s)", strerror(errno)); @@ -289,6 +337,9 @@ receiver(const char *host, const char *port, size_t n, bool conn, bool bug) ERRX(EXIT_FAILURE, "seq: expect=%zu actual=%zu", seq, msg.seq); } + + /* Tell I'm finished */ + synchronize(fd, false); } static void @@ -296,22 +347,32 @@ run(const char *host, const char *port, size_t n, bool conn, bool bug) { pid_t pid; int status; + int syncfds[2]; + int error; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, syncfds) == -1) + ERRX(EXIT_FAILURE, "socketpair (%s)", strerror(errno)); switch ((pid = fork())) { case 0: - receiver(host, port, n, conn, bug); + receiver(syncfds[0], host, port, n, conn, bug); return; case -1: ERRX(EXIT_FAILURE, "fork (%s)", strerror(errno)); default: - usleep(1000); - sender(host, port, n, conn, bug); - usleep(100); + error = sender(syncfds[1], host, port, n, conn, bug); again: switch (waitpid(pid, &status, WNOHANG)) { case -1: ERRX(EXIT_FAILURE, "wait (%s)", strerror(errno)); case 0: + if (error == 0) + /* + * Receiver is still alive, but we know + * it will exit soon. + */ + goto again; + if (kill(pid, SIGTERM) == -1) ERRX(EXIT_FAILURE, "kill (%s)", strerror(errno)); @@ -319,9 +380,9 @@ run(const char *host, const char *port, size_t n, bool conn, bool bug) default: if (WIFSIGNALED(status)) { if (WTERMSIG(status) == SIGTERM) - ERRX(EXIT_FAILURE, - "receiver got terminated due to " \ - "deadline (%d usec)", 100); + ERRX0(EXIT_FAILURE, + "receiver failed and was killed" \ + "by sender"); else ERRX(EXIT_FAILURE, "receiver got signaled (%s)",