From owner-svn-src-all@FreeBSD.ORG Sun Jul 12 12:50:44 2009 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 6A33E106566B; Sun, 12 Jul 2009 12:50:44 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 570BF8FC0A; Sun, 12 Jul 2009 12:50:44 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n6CCoixw084751; Sun, 12 Jul 2009 12:50:44 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n6CCoiHP084736; Sun, 12 Jul 2009 12:50:44 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <200907121250.n6CCoiHP084736@svn.freebsd.org> From: Konstantin Belousov Date: Sun, 12 Jul 2009 12:50:44 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r195636 - in head/tools/regression/poll: . 4 7 l m n X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 12 Jul 2009 12:50:44 -0000 Author: kib Date: Sun Jul 12 12:50:43 2009 New Revision: 195636 URL: http://svn.freebsd.org/changeset/base/195636 Log: Test suite for the poll(2)/select(2) on fifos, pipes and sockets, and recorded results for several operating systems. Submitted by: bde Approved by: re (kensmith) Added: head/tools/regression/poll/ head/tools/regression/poll/4/ head/tools/regression/poll/4/pipepoll.out (contents, props changed) head/tools/regression/poll/4/pipeselect.out (contents, props changed) head/tools/regression/poll/7/ head/tools/regression/poll/7/pipepoll.out (contents, props changed) head/tools/regression/poll/7/pipeselect.out (contents, props changed) head/tools/regression/poll/Makefile (contents, props changed) head/tools/regression/poll/Readme (contents, props changed) head/tools/regression/poll/l/ head/tools/regression/poll/l/pipepoll.out (contents, props changed) head/tools/regression/poll/l/pipeselect.out (contents, props changed) head/tools/regression/poll/m/ head/tools/regression/poll/m/pipepoll.out (contents, props changed) head/tools/regression/poll/m/pipeselect.out (contents, props changed) head/tools/regression/poll/n/ head/tools/regression/poll/n/pipepoll.out (contents, props changed) head/tools/regression/poll/n/pipeselect.out (contents, props changed) head/tools/regression/poll/pipepoll.c (contents, props changed) head/tools/regression/poll/pipeselect.c (contents, props changed) Added: head/tools/regression/poll/4/pipepoll.out ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/4/pipepoll.out Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,21 @@ +1..20 +ok 1 Pipe state 4: expected 0; got 0 +ok 2 Pipe state 5: expected POLLIN; got POLLIN +ok 3 Pipe state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP +not ok 4 Pipe state 6a: expected POLLHUP; got POLLIN | POLLHUP +ok 5 Sock state 4: expected 0; got 0 +ok 6 Sock state 5: expected POLLIN; got POLLIN +not ok 7 Sock state 6: expected POLLIN | POLLHUP; got POLLIN +not ok 8 Sock state 6a: expected POLLHUP; got POLLIN +not ok 9 FIFO state 0: expected 0; got POLLIN +ok 10 FIFO state 1: expected 0; got 0 +ok 11 FIFO state 2: expected POLLIN; got POLLIN +ok 12 FIFO state 2a: expected 0; got 0 +not ok 13 FIFO state 3: expected POLLHUP; got POLLIN +ok 14 FIFO state 4: expected 0; got 0 +ok 15 FIFO state 5: expected POLLIN; got POLLIN +not ok 16 FIFO state 6: expected POLLIN | POLLHUP; got POLLIN +not ok 17 FIFO state 6a: expected POLLHUP; got POLLIN +not ok 18 FIFO state 6b: expected 0; got POLLIN +not ok 19 FIFO state 6c: expected POLLHUP; got POLLIN +not ok 20 FIFO state 6d: expected POLLHUP; got POLLIN Added: head/tools/regression/poll/4/pipeselect.out ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/4/pipeselect.out Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,21 @@ +1..20 +ok 1 Pipe state 4: expected clear; got clear +ok 2 Pipe state 5: expected set; got set +ok 3 Pipe state 6: expected set; got set +ok 4 Pipe state 6a: expected set; got set +ok 5 Sock state 4: expected clear; got clear +ok 6 Sock state 5: expected set; got set +ok 7 Sock state 6: expected set; got set +ok 8 Sock state 6a: expected set; got set +not ok 9 FIFO state 0: expected clear; got set +ok 10 FIFO state 1: expected clear; got clear +ok 11 FIFO state 2: expected set; got set +ok 12 FIFO state 2a: expected clear; got clear +ok 13 FIFO state 3: expected set; got set +ok 14 FIFO state 4: expected clear; got clear +ok 15 FIFO state 5: expected set; got set +ok 16 FIFO state 6: expected set; got set +ok 17 FIFO state 6a: expected set; got set +not ok 18 FIFO state 6b: expected clear; got set +ok 19 FIFO state 6c: expected set; got set +ok 20 FIFO state 6d: expected set; got set Added: head/tools/regression/poll/7/pipepoll.out ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/7/pipepoll.out Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,21 @@ +1..20 +ok 1 Pipe state 4: expected 0; got 0 +ok 2 Pipe state 5: expected POLLIN; got POLLIN +ok 3 Pipe state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP +not ok 4 Pipe state 6a: expected POLLHUP; got POLLIN | POLLHUP +ok 5 Sock state 4: expected 0; got 0 +ok 6 Sock state 5: expected POLLIN; got POLLIN +not ok 7 Sock state 6: expected POLLIN | POLLHUP; got POLLIN +not ok 8 Sock state 6a: expected POLLHUP; got POLLIN +ok 9 FIFO state 0: expected 0; got 0 +ok 10 FIFO state 1: expected 0; got 0 +ok 11 FIFO state 2: expected POLLIN; got POLLIN +ok 12 FIFO state 2a: expected 0; got 0 +not ok 13 FIFO state 3: expected POLLHUP; got 0 +ok 14 FIFO state 4: expected 0; got 0 +ok 15 FIFO state 5: expected POLLIN; got POLLIN +not ok 16 FIFO state 6: expected POLLIN | POLLHUP; got POLLIN +not ok 17 FIFO state 6a: expected POLLHUP; got 0 +ok 18 FIFO state 6b: expected 0; got 0 +not ok 19 FIFO state 6c: expected POLLHUP; got 0 +not ok 20 FIFO state 6d: expected POLLHUP; got 0 Added: head/tools/regression/poll/7/pipeselect.out ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/7/pipeselect.out Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,21 @@ +1..20 +ok 1 Pipe state 4: expected clear; got clear +ok 2 Pipe state 5: expected set; got set +ok 3 Pipe state 6: expected set; got set +ok 4 Pipe state 6a: expected set; got set +ok 5 Sock state 4: expected clear; got clear +ok 6 Sock state 5: expected set; got set +ok 7 Sock state 6: expected set; got set +ok 8 Sock state 6a: expected set; got set +ok 9 FIFO state 0: expected clear; got clear +ok 10 FIFO state 1: expected clear; got clear +ok 11 FIFO state 2: expected set; got set +ok 12 FIFO state 2a: expected clear; got clear +not ok 13 FIFO state 3: expected set; got clear +ok 14 FIFO state 4: expected clear; got clear +ok 15 FIFO state 5: expected set; got set +ok 16 FIFO state 6: expected set; got set +not ok 17 FIFO state 6a: expected set; got clear +ok 18 FIFO state 6b: expected clear; got clear +not ok 19 FIFO state 6c: expected set; got clear +not ok 20 FIFO state 6d: expected set; got clear Added: head/tools/regression/poll/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/Makefile Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,35 @@ +$ $FreeBSD$ +# This makefile has been uglified for portability. +# Nothing yet works with gmake for the path to the sources. +.PATH: .. + +PROG= pipepoll pipeselect +CFLAGS+= -Werror -Wall + +all: ${PROG} +pipepoll: pipepoll.c +pipeselect: pipeselect.c + +pipepoll pipeselect: + ${CC} ${CFLAGS} ${LDFLAGS} -o $@ $@.c + +test: all + -for prog in ${PROG}; do \ + ./$${prog} > $${prog}.out.new; \ + diff -u1 $${prog}.out $${prog}.out.new; \ + done + +clean: + for prog in ${PROG}; do \ + rm -f $${prog} $${prog}.out.new; \ + done + +rename: + for prog in ${PROG}; do \ + mv $${prog}.out.new $${prog}.out; \ + done + +veryclean: clean + for prog in ${PROG}; do \ + rm -f $${prog}.out; \ + done Added: head/tools/regression/poll/Readme ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/Readme Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,18 @@ +$FreeBSD$ + +The directory contains poll(2) and select(2) compliance (and more) tests +from Bruce Evans, together with canned test results from several systems +for reference. + +Citing Bruce Evans: +The subdirectories contain results of old runs: + +{4,7}: FreeBSD-{4,7} with old tests (only state 0 and 6b have different +expectations; state 0 fails in FreeBSD-4 so the above is wrong +about at least when it was broken. I thought that I fixed it +completely for select() in FreeBSD-1. One or both of these states +were very broken in Net/2 and maybe in 4.4BSD-Lite*). + +l: Linux-2.6.10 with old tests (only state 0 has different expectations) +m: my current version of FreeBSD with old tests (0 and 6b) +n: my previous version of FreeBSD with old tests (0 and 6b) Added: head/tools/regression/poll/l/pipepoll.out ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/l/pipepoll.out Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,21 @@ +1..20 +ok 1 Pipe state 4: expected 0; got 0 +ok 2 Pipe state 5: expected POLLIN; got POLLIN +ok 3 Pipe state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP +ok 4 Pipe state 6a: expected POLLHUP; got POLLHUP +ok 5 Sock state 4: expected 0; got 0 +ok 6 Sock state 5: expected POLLIN; got POLLIN +ok 7 Sock state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP +not ok 8 Sock state 6a: expected POLLHUP; got POLLIN | POLLHUP +ok 9 FIFO state 0: expected 0; got 0 +ok 10 FIFO state 1: expected 0; got 0 +ok 11 FIFO state 2: expected POLLIN; got POLLIN +ok 12 FIFO state 2a: expected 0; got 0 +ok 13 FIFO state 3: expected POLLHUP; got POLLHUP +ok 14 FIFO state 4: expected 0; got 0 +ok 15 FIFO state 5: expected POLLIN; got POLLIN +ok 16 FIFO state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP +ok 17 FIFO state 6a: expected POLLHUP; got POLLHUP +not ok 18 FIFO state 6b: expected POLLHUP; got 0 +ok 19 FIFO state 6c: expected POLLHUP; got POLLHUP +ok 20 FIFO state 6d: expected POLLHUP; got POLLHUP Added: head/tools/regression/poll/l/pipeselect.out ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/l/pipeselect.out Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,21 @@ +1..20 +ok 1 Pipe state 4: expected clear; got clear +ok 2 Pipe state 5: expected set; got set +ok 3 Pipe state 6: expected set; got set +ok 4 Pipe state 6a: expected set; got set +ok 5 Sock state 4: expected clear; got clear +ok 6 Sock state 5: expected set; got set +ok 7 Sock state 6: expected set; got set +ok 8 Sock state 6a: expected set; got set +not ok 9 FIFO state 0: expected set; got clear +ok 10 FIFO state 1: expected clear; got clear +ok 11 FIFO state 2: expected set; got set +ok 12 FIFO state 2a: expected clear; got clear +ok 13 FIFO state 3: expected set; got set +ok 14 FIFO state 4: expected clear; got clear +ok 15 FIFO state 5: expected set; got set +ok 16 FIFO state 6: expected set; got set +ok 17 FIFO state 6a: expected set; got set +not ok 18 FIFO state 6b: expected set; got clear +ok 19 FIFO state 6c: expected set; got set +ok 20 FIFO state 6d: expected set; got set Added: head/tools/regression/poll/m/pipepoll.out ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/m/pipepoll.out Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,21 @@ +1..20 +ok 1 Pipe state 4: expected 0; got 0 +ok 2 Pipe state 5: expected POLLIN; got POLLIN +ok 3 Pipe state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP +ok 4 Pipe state 6a: expected POLLHUP; got POLLHUP +ok 5 Sock state 4: expected 0; got 0 +ok 6 Sock state 5: expected POLLIN; got POLLIN +ok 7 Sock state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP +ok 8 Sock state 6a: expected POLLHUP; got POLLHUP +ok 9 FIFO state 0: expected 0; got 0 +ok 10 FIFO state 1: expected 0; got 0 +ok 11 FIFO state 2: expected POLLIN; got POLLIN +ok 12 FIFO state 2a: expected 0; got 0 +ok 13 FIFO state 3: expected POLLHUP; got POLLHUP +ok 14 FIFO state 4: expected 0; got 0 +ok 15 FIFO state 5: expected POLLIN; got POLLIN +ok 16 FIFO state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP +ok 17 FIFO state 6a: expected POLLHUP; got POLLHUP +ok 18 FIFO state 6b: expected POLLHUP; got POLLHUP +ok 19 FIFO state 6c: expected POLLHUP; got POLLHUP +ok 20 FIFO state 6d: expected POLLHUP; got POLLHUP Added: head/tools/regression/poll/m/pipeselect.out ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/m/pipeselect.out Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,21 @@ +1..20 +ok 1 Pipe state 4: expected clear; got clear +ok 2 Pipe state 5: expected set; got set +ok 3 Pipe state 6: expected set; got set +ok 4 Pipe state 6a: expected set; got set +ok 5 Sock state 4: expected clear; got clear +ok 6 Sock state 5: expected set; got set +ok 7 Sock state 6: expected set; got set +ok 8 Sock state 6a: expected set; got set +not ok 9 FIFO state 0: expected set; got clear +ok 10 FIFO state 1: expected clear; got clear +ok 11 FIFO state 2: expected set; got set +ok 12 FIFO state 2a: expected clear; got clear +ok 13 FIFO state 3: expected set; got set +ok 14 FIFO state 4: expected clear; got clear +ok 15 FIFO state 5: expected set; got set +ok 16 FIFO state 6: expected set; got set +ok 17 FIFO state 6a: expected set; got set +ok 18 FIFO state 6b: expected set; got set +ok 19 FIFO state 6c: expected set; got set +ok 20 FIFO state 6d: expected set; got set Added: head/tools/regression/poll/n/pipepoll.out ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/n/pipepoll.out Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,21 @@ +1..20 +ok 1 Pipe state 4: expected 0; got 0 +ok 2 Pipe state 5: expected POLLIN; got POLLIN +ok 3 Pipe state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP +ok 4 Pipe state 6a: expected POLLHUP; got POLLHUP +ok 5 Sock state 4: expected 0; got 0 +ok 6 Sock state 5: expected POLLIN; got POLLIN +ok 7 Sock state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP +ok 8 Sock state 6a: expected POLLHUP; got POLLHUP +ok 9 FIFO state 0: expected 0; got 0 +ok 10 FIFO state 1: expected 0; got 0 +ok 11 FIFO state 2: expected POLLIN; got POLLIN +ok 12 FIFO state 2a: expected 0; got 0 +ok 13 FIFO state 3: expected POLLHUP; got POLLHUP +ok 14 FIFO state 4: expected 0; got 0 +ok 15 FIFO state 5: expected POLLIN; got POLLIN +ok 16 FIFO state 6: expected POLLIN | POLLHUP; got POLLIN | POLLHUP +ok 17 FIFO state 6a: expected POLLHUP; got POLLHUP +ok 18 FIFO state 6b: expected 0; got 0 +ok 19 FIFO state 6c: expected POLLHUP; got POLLHUP +ok 20 FIFO state 6d: expected POLLHUP; got POLLHUP Added: head/tools/regression/poll/n/pipeselect.out ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/n/pipeselect.out Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,21 @@ +1..20 +ok 1 Pipe state 4: expected clear; got clear +ok 2 Pipe state 5: expected set; got set +ok 3 Pipe state 6: expected set; got set +ok 4 Pipe state 6a: expected set; got set +ok 5 Sock state 4: expected clear; got clear +ok 6 Sock state 5: expected set; got set +ok 7 Sock state 6: expected set; got set +ok 8 Sock state 6a: expected set; got set +ok 9 FIFO state 0: expected clear; got clear +ok 10 FIFO state 1: expected clear; got clear +ok 11 FIFO state 2: expected set; got set +ok 12 FIFO state 2a: expected clear; got clear +ok 13 FIFO state 3: expected set; got set +ok 14 FIFO state 4: expected clear; got clear +ok 15 FIFO state 5: expected set; got set +ok 16 FIFO state 6: expected set; got set +ok 17 FIFO state 6a: expected set; got set +ok 18 FIFO state 6b: expected clear; got clear +ok 19 FIFO state 6c: expected set; got set +ok 20 FIFO state 6d: expected set; got set Added: head/tools/regression/poll/pipepoll.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/pipepoll.c Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,302 @@ +/* $FreeBSD$ */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define FIFONAME "fifo.tmp" +#define FT_END 3 +#define FT_FIFO 2 +#define FT_PIPE 0 +#define FT_SOCKETPAIR 1 + +static int filetype; + +static const char * +decode_events(int events) +{ + char *ncresult; + const char *result; + + switch (events) { + case POLLIN: + result = "POLLIN"; + break; + case POLLHUP: + result = "POLLHUP"; + break; + case POLLIN | POLLHUP: + result = "POLLIN | 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(" %s state %s: expected %s; got %s\n", + filetype == FT_PIPE ? "Pipe" : + filetype == FT_SOCKETPAIR ? "Sock" : "FIFO", + state, decode_events(expected), decode_events(got)); + fflush(stdout); +} + +static pid_t cpid; +static pid_t ppid; +static volatile sig_atomic_t state; + +static void +catch(int sig) +{ + state++; +} + +static void +child(int fd, int num) +{ + struct pollfd pfd; + int fd2; + char buf[256]; + + if (filetype == FT_FIFO) { + fd = open(FIFONAME, O_RDONLY | O_NONBLOCK); + if (fd < 0) + err(1, "open for read"); + } + pfd.fd = fd; + pfd.events = POLLIN; + + if (filetype == FT_FIFO) { + if (poll(&pfd, 1, 0) < 0) + err(1, "poll"); + report(num++, "0", 0, pfd.revents); + } + kill(ppid, SIGUSR1); + + usleep(1); + while (state != 1) + ; + if (filetype != FT_FIFO) { + /* + * The connection cannot be reestablished. Use the code that + * delays the read until after the writer disconnects since + * that case is more interesting. + */ + state = 4; + goto state4; + } + if (poll(&pfd, 1, 0) < 0) + err(1, "poll"); + report(num++, "1", 0, pfd.revents); + kill(ppid, SIGUSR1); + + usleep(1); + while (state != 2) + ; + if (poll(&pfd, 1, 0) < 0) + err(1, "poll"); + report(num++, "2", POLLIN, pfd.revents); + if (read(fd, buf, sizeof buf) != 1) + err(1, "read"); + if (poll(&pfd, 1, 0) < 0) + err(1, "poll"); + report(num++, "2a", 0, pfd.revents); + kill(ppid, SIGUSR1); + + usleep(1); + while (state != 3) + ; + if (poll(&pfd, 1, 0) < 0) + err(1, "poll"); + report(num++, "3", POLLHUP, pfd.revents); + kill(ppid, SIGUSR1); + + /* + * Now we expect a new writer, and a new connection too since + * we read all the data. The only new point is that we didn't + * start quite from scratch since the read fd is not new. Check + * startup state as above, but don't do the read as above. + */ + usleep(1); + while (state != 4) + ; +state4: + if (poll(&pfd, 1, 0) < 0) + err(1, "poll"); + report(num++, "4", 0, pfd.revents); + kill(ppid, SIGUSR1); + + usleep(1); + while (state != 5) + ; + if (poll(&pfd, 1, 0) < 0) + err(1, "poll"); + report(num++, "5", POLLIN, pfd.revents); + kill(ppid, SIGUSR1); + + usleep(1); + while (state != 6) + ; + /* + * Now we have no writer, but should still have data from the old + * writer. Check that we have both a data-readable condition and a + * hangup condition, and that the data can be read in the usual way. + * Since Linux does this, programs must not quit reading when they + * see POLLHUP; they must see POLLHUP without POLLIN (or another + * input condition) before they decide that there is EOF. gdb-6.1.1 + * is an example of a broken program that quits on POLLHUP only -- + * see its event-loop.c. + */ + if (poll(&pfd, 1, 0) < 0) + err(1, "poll"); + report(num++, "6", POLLIN | POLLHUP, pfd.revents); + if (read(fd, buf, sizeof buf) != 1) + err(1, "read"); + if (poll(&pfd, 1, 0) < 0) + err(1, "poll"); + report(num++, "6a", POLLHUP, pfd.revents); + if (filetype == FT_FIFO) { + /* + * Check that POLLHUP is sticky for a new reader and for + * the old reader. + */ + fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK); + if (fd2 < 0) + err(1, "open for read"); + pfd.fd = fd2; + if (poll(&pfd, 1, 0) < 0) + err(1, "poll"); + report(num++, "6b", POLLHUP, pfd.revents); + pfd.fd = fd; + if (poll(&pfd, 1, 0) < 0) + err(1, "poll"); + report(num++, "6c", POLLHUP, pfd.revents); + close(fd2); + if (poll(&pfd, 1, 0) < 0) + err(1, "poll"); + report(num++, "6d", POLLHUP, pfd.revents); + } + close(fd); + kill(ppid, SIGUSR1); + + exit(0); +} + +static void +parent(int fd) +{ + usleep(1); + while (state != 1) + ; + if (filetype == FT_FIFO) { + fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); + if (fd < 0) + err(1, "open for write"); + } + kill(cpid, SIGUSR1); + + usleep(1); + while (state != 2) + ; + if (write(fd, "", 1) != 1) + err(1, "write"); + kill(cpid, SIGUSR1); + + usleep(1); + while (state != 3) + ; + if (close(fd) != 0) + err(1, "close for write"); + kill(cpid, SIGUSR1); + + usleep(1); + while (state != 4) + ; + if (filetype != FT_FIFO) + return; + fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); + if (fd < 0) + err(1, "open for write"); + kill(cpid, SIGUSR1); + + usleep(1); + while (state != 5) + ; + if (write(fd, "", 1) != 1) + err(1, "write"); + kill(cpid, SIGUSR1); + + usleep(1); + while (state != 6) + ; + if (close(fd) != 0) + err(1, "close for write"); + kill(cpid, SIGUSR1); + + usleep(1); + while (state != 7) + ; +} + +int +main(void) +{ + int fd[2], num; + + num = 1; + printf("1..20\n"); + fflush(stdout); + signal(SIGUSR1, catch); + ppid = getpid(); + for (filetype = 0; filetype < FT_END; filetype++) { + switch (filetype) { + case FT_FIFO: + if (mkfifo(FIFONAME, 0666) != 0) + err(1, "mkfifo"); + fd[0] = -1; + fd[1] = -1; + break; + case FT_SOCKETPAIR: + if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC, + fd) != 0) + err(1, "socketpair"); + break; + case FT_PIPE: + if (pipe(fd) != 0) + err(1, "pipe"); + break; + } + state = 0; + switch (cpid = fork()) { + case -1: + err(1, "fork"); + case 0: + (void)close(fd[1]); + child(fd[0], num); + break; + default: + (void)close(fd[0]); + parent(fd[1]); + break; + } + num += filetype == FT_FIFO ? 12 : 4; + } + (void)unlink(FIFONAME); + return (0); +} Added: head/tools/regression/poll/pipeselect.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/tools/regression/poll/pipeselect.c Sun Jul 12 12:50:43 2009 (r195636) @@ -0,0 +1,318 @@ +/* $FreeBSD$ */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define FIFONAME "fifo.tmp" +#define FT_END 3 +#define FT_FIFO 2 +#define FT_PIPE 0 +#define FT_SOCKETPAIR 1 + +#define SETUP(fd, rfds, tv) do { \ + FD_ZERO(&(rfds)); \ + FD_SET((fd), &(rfds)); \ + (tv).tv_sec = 0; \ + (tv).tv_usec = 0; \ +} while (0) + +static int filetype; + +static const char * +decode_events(int events) +{ + return (events ? "set" : "clear"); +} + +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(" %s state %s: expected %s; got %s\n", + filetype == FT_PIPE ? "Pipe" : + filetype == FT_SOCKETPAIR ? "Sock" : "FIFO", + state, decode_events(expected), decode_events(got)); + fflush(stdout); +} + +static pid_t cpid; +static pid_t ppid; +static volatile sig_atomic_t state; + +static void +catch(int sig) +{ + state++; +} + +static void +child(int fd, int num) +{ + fd_set rfds; + struct timeval tv; + int fd1, fd2; + char buf[256]; + + if (filetype == FT_FIFO) { + fd = open(FIFONAME, O_RDONLY | O_NONBLOCK); + if (fd < 0) + err(1, "open for read"); + } + if (fd >= FD_SETSIZE) + errx(1, "fd = %d too large for select()", fd); + + if (filetype == FT_FIFO) { + SETUP(fd, rfds, tv); + if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) + err(1, "select"); + /* + * This state (a reader for which there has never been a + * writer) is reported quite differently for select() than + * for poll(). select() must see a ready-to-read descriptor + * since read() will see EOF and not block; it cannot + * distinguish this state from the one of a reader for which + * there has been a writer but all writers have gone away + * and all data has been read. poll() and distinguish these + * states by returning POLLHUP only for the latter; it does + * this, although this makes it inconsistent with the + * blockability of read() in the former. + */ + report(num++, "0", 1, FD_ISSET(fd, &rfds)); + } + kill(ppid, SIGUSR1); + + usleep(1); + while (state != 1) + ; + if (filetype != FT_FIFO) { + /* + * The connection cannot be reestablished. Use the code that + * delays the read until after the writer disconnects since + * that case is more interesting. + */ + state = 4; + goto state4; + } + SETUP(fd, rfds, tv); + if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) + err(1, "select"); + report(num++, "1", 0, FD_ISSET(fd, &rfds)); + kill(ppid, SIGUSR1); + + usleep(1); + while (state != 2) + ; + SETUP(fd, rfds, tv); + if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) + err(1, "select"); + report(num++, "2", 1, FD_ISSET(fd, &rfds)); + if (read(fd, buf, sizeof buf) != 1) + err(1, "read"); + SETUP(fd, rfds, tv); + if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) + err(1, "select"); + report(num++, "2a", 0, FD_ISSET(fd, &rfds)); + kill(ppid, SIGUSR1); + + usleep(1); + while (state != 3) + ; + SETUP(fd, rfds, tv); + if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) + err(1, "select"); + report(num++, "3", 1, FD_ISSET(fd, &rfds)); + kill(ppid, SIGUSR1); + + /* + * Now we expect a new writer, and a new connection too since + * we read all the data. The only new point is that we didn't + * start quite from scratch since the read fd is not new. Check + * startup state as above, but don't do the read as above. + */ + usleep(1); + while (state != 4) + ; +state4: + SETUP(fd, rfds, tv); + if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) + err(1, "select"); + report(num++, "4", 0, FD_ISSET(fd, &rfds)); + kill(ppid, SIGUSR1); + + usleep(1); + while (state != 5) + ; + SETUP(fd, rfds, tv); + if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) + err(1, "select"); + report(num++, "5", 1, FD_ISSET(fd, &rfds)); + kill(ppid, SIGUSR1); + + usleep(1); + while (state != 6) + ; + /* + * Now we have no writer, but should still have data from the old + * writer. Check that we have a data-readable condition, and that + * the data can be read in the usual way. + */ + SETUP(fd, rfds, tv); + if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) + err(1, "select"); + report(num++, "6", 1, FD_ISSET(fd, &rfds)); + if (read(fd, buf, sizeof buf) != 1) + err(1, "read"); + SETUP(fd, rfds, tv); + if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) + err(1, "select"); + report(num++, "6a", 1, FD_ISSET(fd, &rfds)); + if (filetype == FT_FIFO) { + /* + * Check that the readable-data condition is sticky for a + * new reader and for the old reader. We really only have + * a hangup condition, but select() can only see this as + * a readable-data condition for null data. select() + * cannot distinguish this state from the initial state + * where there is a reader but has never been a writer, so + * the following tests (to follow the pattern in pipepoll.c) + * essentially test state 0 again. + */ + fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK); + if (fd2 < 0) + err(1, "open for read"); + fd1 = fd; + fd = fd2; + SETUP(fd, rfds, tv); + if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) + err(1, "select"); + report(num++, "6b", 1, FD_ISSET(fd, &rfds)); + fd = fd1; + SETUP(fd, rfds, tv); + if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) + err(1, "select"); + report(num++, "6c", 1, FD_ISSET(fd, &rfds)); + close(fd2); + SETUP(fd, rfds, tv); + if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) + err(1, "select"); + report(num++, "6d", 1, FD_ISSET(fd, &rfds)); + } + close(fd); + kill(ppid, SIGUSR1); + + exit(0); +} + +static void +parent(int fd) +{ + usleep(1); + while (state != 1) + ; + if (filetype == FT_FIFO) { + fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); + if (fd < 0) + err(1, "open for write"); + } + kill(cpid, SIGUSR1); + + usleep(1); + while (state != 2) + ; + if (write(fd, "", 1) != 1) + err(1, "write"); + kill(cpid, SIGUSR1); + + usleep(1); + while (state != 3) + ; + if (close(fd) != 0) + err(1, "close for write"); + kill(cpid, SIGUSR1); + + usleep(1); + while (state != 4) + ; + if (filetype != FT_FIFO) + return; + fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); + if (fd < 0) + err(1, "open for write"); + kill(cpid, SIGUSR1); + + usleep(1); + while (state != 5) + ; + if (write(fd, "", 1) != 1) + err(1, "write"); + kill(cpid, SIGUSR1); + + usleep(1); + while (state != 6) + ; + if (close(fd) != 0) + err(1, "close for write"); + kill(cpid, SIGUSR1); + + usleep(1); + while (state != 7) + ; +} + +int +main(void) +{ + int fd[2], num; + + num = 1; + printf("1..20\n"); + fflush(stdout); + signal(SIGUSR1, catch); + ppid = getpid(); + for (filetype = 0; filetype < FT_END; filetype++) { + switch (filetype) { + case FT_FIFO: + if (mkfifo(FIFONAME, 0666) != 0) + err(1, "mkfifo"); + fd[0] = -1; + fd[1] = -1; + break; + case FT_SOCKETPAIR: + if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC, + fd) != 0) + err(1, "socketpair"); + break; + case FT_PIPE: + if (pipe(fd) != 0) + err(1, "pipe"); + break; + } + state = 0; + switch (cpid = fork()) { + case -1: + err(1, "fork"); + case 0: + (void)close(fd[1]); + child(fd[0], num); + break; + default: + (void)close(fd[0]); + parent(fd[1]); + break; + } + num += filetype == FT_FIFO ? 12 : 4; + } + (void)unlink(FIFONAME); + return (0); +}