summaryrefslogtreecommitdiffstats
path: root/tools/regression
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2009-08-25 20:33:37 +0000
committerjilles <jilles@FreeBSD.org>2009-08-25 20:33:37 +0000
commit7570cc2d3276876d8e3ee4358f50c8c29ef684c8 (patch)
tree16c029b213c69885bd547dee7ea49283f5b8088d /tools/regression
parent8184e58b3aca79bbb4865b22468b7a7b74040fe2 (diff)
downloadFreeBSD-src-7570cc2d3276876d8e3ee4358f50c8c29ef684c8.zip
FreeBSD-src-7570cc2d3276876d8e3ee4358f50c8c29ef684c8.tar.gz
Add some tests for poll(2)/shutdown(2) interaction.
Diffstat (limited to 'tools/regression')
-rw-r--r--tools/regression/poll/Makefile5
-rw-r--r--tools/regression/poll/sockpoll.c202
2 files changed, 205 insertions, 2 deletions
diff --git a/tools/regression/poll/Makefile b/tools/regression/poll/Makefile
index 71192a9..45f743f 100644
--- a/tools/regression/poll/Makefile
+++ b/tools/regression/poll/Makefile
@@ -3,14 +3,15 @@
# Nothing yet works with gmake for the path to the sources.
.PATH: ..
-PROG= pipepoll pipeselect
+PROG= pipepoll pipeselect sockpoll
CFLAGS+= -Werror -Wall
all: ${PROG}
pipepoll: pipepoll.c
pipeselect: pipeselect.c
+sockpoll: sockpoll.c
-pipepoll pipeselect:
+pipepoll pipeselect sockpoll:
${CC} ${CFLAGS} ${LDFLAGS} -o $@ $@.c
test: all
diff --git a/tools/regression/poll/sockpoll.c b/tools/regression/poll/sockpoll.c
new file mode 100644
index 0000000..4bffd29
--- /dev/null
+++ b/tools/regression/poll/sockpoll.c
@@ -0,0 +1,202 @@
+/* $FreeBSD$ */
+
+#include <sys/poll.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static const char *
+decode_events(int events)
+{
+ char *ncresult;
+ const char *result;
+
+ switch (events) {
+ case POLLIN:
+ result = "POLLIN";
+ break;
+ case POLLOUT:
+ result = "POLLOUT";
+ break;
+ case POLLIN | POLLOUT:
+ result = "POLLIN | POLLOUT";
+ break;
+ case POLLHUP:
+ result = "POLLHUP";
+ break;
+ case POLLIN | POLLHUP:
+ result = "POLLIN | POLLHUP";
+ break;
+ case POLLOUT | POLLHUP:
+ result = "POLLOUT | POLLHUP";
+ break;
+ case POLLIN | POLLOUT | POLLHUP:
+ result = "POLLIN | POLLOUT | POLLHUP";
+ break;
+ default:
+ asprintf(&ncresult, "%#x", events);
+ result = ncresult;
+ break;
+ }
+ return (result);
+}
+
+static void
+report(int num, const char *state, int expected, int got)
+{
+ if (expected == got)
+ printf("ok %-2d ", num);
+ else
+ printf("not ok %-2d", num);
+ printf(" state %s: expected %s; got %s\n",
+ state, decode_events(expected), decode_events(got));
+ fflush(stdout);
+}
+
+static int
+set_nonblocking(int sck)
+{
+ int flags;
+
+ flags = fcntl(sck, F_GETFL, 0);
+ flags |= O_NONBLOCK;
+
+ if (fcntl(sck, F_SETFL, flags))
+ return -1;
+
+ return 0;
+}
+
+static char largeblock[1048576]; /* should be more than AF_UNIX sockbuf size */
+static int fd[2];
+static struct pollfd pfd0;
+static struct pollfd pfd1;
+
+void
+setup(void)
+{
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0)
+ err(1, "socketpair");
+ if (set_nonblocking(fd[0]) == -1)
+ err(1, "fcntl");
+ if (set_nonblocking(fd[1]) == -1)
+ err(1, "fcntl");
+ pfd0.fd = fd[0];
+ pfd0.events = POLLIN | POLLOUT;
+ pfd1.fd = fd[1];
+ pfd1.events = POLLIN | POLLOUT;
+}
+
+int
+main(void)
+{
+ int num;
+
+ num = 1;
+ printf("1..18\n");
+ fflush(stdout);
+
+ /* Large write with close */
+ setup();
+ if (poll(&pfd0, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "initial 0", POLLOUT, pfd0.revents);
+ if (poll(&pfd1, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "initial 1", POLLOUT, pfd1.revents);
+ if (write(fd[0], largeblock, sizeof(largeblock)) == -1)
+ err(1, "write");
+ if (poll(&pfd0, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "after large write", 0, pfd0.revents);
+ if (poll(&pfd1, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "other side after large write", POLLIN | POLLOUT, pfd1.revents);
+ close(fd[0]);
+ if (poll(&pfd1, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "other side after close", POLLIN | POLLHUP, pfd1.revents);
+ if (read(fd[1], largeblock, sizeof(largeblock)) == -1)
+ err(1, "read");
+ if (poll(&pfd1, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "other side after reading input", POLLHUP, pfd1.revents);
+ close(fd[1]);
+
+ /* With shutdown(SHUT_WR) */
+ setup();
+ if (shutdown(fd[0], SHUT_WR) == -1)
+ err(1, "shutdown");
+ if (poll(&pfd0, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "after shutdown(SHUT_WR)", POLLOUT, pfd0.revents);
+ if (poll(&pfd1, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "other side after shutdown(SHUT_WR)", POLLIN | POLLOUT, pfd1.revents);
+ switch (read(fd[1], largeblock, sizeof(largeblock))) {
+ case 0:
+ break;
+ case -1:
+ err(1, "read after other side shutdown");
+ break;
+ default:
+ errx(1, "kernel made up data that was never written");
+ }
+ if (poll(&pfd1, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "other side after reading EOF", POLLIN | POLLOUT, pfd1.revents);
+ if (write(fd[1], largeblock, sizeof(largeblock)) == -1)
+ err(1, "write");
+ if (poll(&pfd0, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "after data from other side", POLLIN | POLLOUT, pfd0.revents);
+ if (poll(&pfd1, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "after writing", POLLIN, pfd1.revents);
+ if (shutdown(fd[1], SHUT_WR) == -1)
+ err(1, "shutdown second");
+ if (poll(&pfd0, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "after second shutdown", POLLIN | POLLHUP, pfd0.revents);
+ if (poll(&pfd1, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "after second shutdown", POLLHUP, pfd1.revents);
+ close(fd[0]);
+ if (poll(&pfd1, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "after close", POLLHUP, pfd1.revents);
+ close(fd[1]);
+
+ /*
+ * With shutdown(SHUT_RD)
+ * Note that shutdown(SHUT_WR) is passed to the peer, but
+ * shutdown(SHUT_RD) is not.
+ */
+ setup();
+ if (shutdown(fd[0], SHUT_RD) == -1)
+ err(1, "shutdown");
+ if (poll(&pfd0, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "after shutdown(SHUT_RD)", POLLIN | POLLOUT, pfd0.revents);
+ if (poll(&pfd1, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "other side after shutdown(SHUT_RD)", POLLOUT, pfd1.revents);
+ if (shutdown(fd[0], SHUT_WR) == -1)
+ err(1, "shutdown");
+ if (poll(&pfd0, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "after shutdown(SHUT_WR)", POLLHUP, pfd0.revents);
+ if (poll(&pfd1, 1, 0) == -1)
+ err(1, "poll");
+ report(num++, "other side after shutdown(SHUT_WR)", POLLIN | POLLOUT, pfd1.revents);
+ close(fd[0]);
+ close(fd[1]);
+
+ return (0);
+}
OpenPOWER on IntegriCloud