1 /* $FreeBSD$ */ 2 3 #include <sys/poll.h> 4 #include <sys/socket.h> 5 #include <sys/stat.h> 6 7 #include <err.h> 8 #include <fcntl.h> 9 #include <signal.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <unistd.h> 13 14 #define FIFONAME "fifo.tmp" 15 #define FT_END 3 16 #define FT_FIFO 2 17 #define FT_PIPE 0 18 #define FT_SOCKETPAIR 1 19 20 static int filetype; 21 22 static const char * 23 decode_events(int events) 24 { 25 char *ncresult; 26 const char *result; 27 28 switch (events) { 29 case POLLIN: 30 result = "POLLIN"; 31 break; 32 case POLLHUP: 33 result = "POLLHUP"; 34 break; 35 case POLLIN | POLLHUP: 36 result = "POLLIN | POLLHUP"; 37 break; 38 default: 39 asprintf(&ncresult, "%#x", events); 40 result = ncresult; 41 break; 42 } 43 return (result); 44 } 45 46 static void 47 report(int num, const char *state, int expected, int got) 48 { 49 if (expected == got) 50 printf("ok %-2d ", num); 51 else 52 printf("not ok %-2d", num); 53 printf(" %s state %s: expected %s; got %s\n", 54 filetype == FT_PIPE ? "Pipe" : 55 filetype == FT_SOCKETPAIR ? "Sock" : "FIFO", 56 state, decode_events(expected), decode_events(got)); 57 fflush(stdout); 58 } 59 60 static pid_t cpid; 61 static pid_t ppid; 62 static volatile sig_atomic_t state; 63 64 static void 65 catch(int sig) 66 { 67 state++; 68 } 69 70 static void 71 child(int fd, int num) 72 { 73 struct pollfd pfd; 74 int fd2; 75 char buf[256]; 76 77 if (filetype == FT_FIFO) { 78 fd = open(FIFONAME, O_RDONLY | O_NONBLOCK); 79 if (fd < 0) 80 err(1, "open for read"); 81 } 82 pfd.fd = fd; 83 pfd.events = POLLIN; 84 85 if (filetype == FT_FIFO) { 86 if (poll(&pfd, 1, 0) < 0) 87 err(1, "poll"); 88 report(num++, "0", 0, pfd.revents); 89 } 90 kill(ppid, SIGUSR1); 91 92 usleep(1); 93 while (state != 1) 94 ; 95 if (filetype != FT_FIFO) { 96 /* 97 * The connection cannot be reestablished. Use the code that 98 * delays the read until after the writer disconnects since 99 * that case is more interesting. 100 */ 101 state = 4; 102 goto state4; 103 } 104 if (poll(&pfd, 1, 0) < 0) 105 err(1, "poll"); 106 report(num++, "1", 0, pfd.revents); 107 kill(ppid, SIGUSR1); 108 109 usleep(1); 110 while (state != 2) 111 ; 112 if (poll(&pfd, 1, 0) < 0) 113 err(1, "poll"); 114 report(num++, "2", POLLIN, pfd.revents); 115 if (read(fd, buf, sizeof buf) != 1) 116 err(1, "read"); 117 if (poll(&pfd, 1, 0) < 0) 118 err(1, "poll"); 119 report(num++, "2a", 0, pfd.revents); 120 kill(ppid, SIGUSR1); 121 122 usleep(1); 123 while (state != 3) 124 ; 125 if (poll(&pfd, 1, 0) < 0) 126 err(1, "poll"); 127 report(num++, "3", POLLHUP, pfd.revents); 128 kill(ppid, SIGUSR1); 129 130 /* 131 * Now we expect a new writer, and a new connection too since 132 * we read all the data. The only new point is that we didn't 133 * start quite from scratch since the read fd is not new. Check 134 * startup state as above, but don't do the read as above. 135 */ 136 usleep(1); 137 while (state != 4) 138 ; 139 state4: 140 if (poll(&pfd, 1, 0) < 0) 141 err(1, "poll"); 142 report(num++, "4", 0, pfd.revents); 143 kill(ppid, SIGUSR1); 144 145 usleep(1); 146 while (state != 5) 147 ; 148 if (poll(&pfd, 1, 0) < 0) 149 err(1, "poll"); 150 report(num++, "5", POLLIN, pfd.revents); 151 kill(ppid, SIGUSR1); 152 153 usleep(1); 154 while (state != 6) 155 ; 156 /* 157 * Now we have no writer, but should still have data from the old 158 * writer. Check that we have both a data-readable condition and a 159 * hangup condition, and that the data can be read in the usual way. 160 * Since Linux does this, programs must not quit reading when they 161 * see POLLHUP; they must see POLLHUP without POLLIN (or another 162 * input condition) before they decide that there is EOF. gdb-6.1.1 163 * is an example of a broken program that quits on POLLHUP only -- 164 * see its event-loop.c. 165 */ 166 if (poll(&pfd, 1, 0) < 0) 167 err(1, "poll"); 168 report(num++, "6", POLLIN | POLLHUP, pfd.revents); 169 if (read(fd, buf, sizeof buf) != 1) 170 err(1, "read"); 171 if (poll(&pfd, 1, 0) < 0) 172 err(1, "poll"); 173 report(num++, "6a", POLLHUP, pfd.revents); 174 if (filetype == FT_FIFO) { 175 /* 176 * Check that POLLHUP is sticky for a new reader and for 177 * the old reader. 178 */ 179 fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK); 180 if (fd2 < 0) 181 err(1, "open for read"); 182 pfd.fd = fd2; 183 if (poll(&pfd, 1, 0) < 0) 184 err(1, "poll"); 185 report(num++, "6b", POLLHUP, pfd.revents); 186 pfd.fd = fd; 187 if (poll(&pfd, 1, 0) < 0) 188 err(1, "poll"); 189 report(num++, "6c", POLLHUP, pfd.revents); 190 close(fd2); 191 if (poll(&pfd, 1, 0) < 0) 192 err(1, "poll"); 193 report(num++, "6d", POLLHUP, pfd.revents); 194 } 195 close(fd); 196 kill(ppid, SIGUSR1); 197 198 exit(0); 199 } 200 201 static void 202 parent(int fd) 203 { 204 usleep(1); 205 while (state != 1) 206 ; 207 if (filetype == FT_FIFO) { 208 fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); 209 if (fd < 0) 210 err(1, "open for write"); 211 } 212 kill(cpid, SIGUSR1); 213 214 usleep(1); 215 while (state != 2) 216 ; 217 if (write(fd, "", 1) != 1) 218 err(1, "write"); 219 kill(cpid, SIGUSR1); 220 221 usleep(1); 222 while (state != 3) 223 ; 224 if (close(fd) != 0) 225 err(1, "close for write"); 226 kill(cpid, SIGUSR1); 227 228 usleep(1); 229 while (state != 4) 230 ; 231 if (filetype != FT_FIFO) 232 return; 233 fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); 234 if (fd < 0) 235 err(1, "open for write"); 236 kill(cpid, SIGUSR1); 237 238 usleep(1); 239 while (state != 5) 240 ; 241 if (write(fd, "", 1) != 1) 242 err(1, "write"); 243 kill(cpid, SIGUSR1); 244 245 usleep(1); 246 while (state != 6) 247 ; 248 if (close(fd) != 0) 249 err(1, "close for write"); 250 kill(cpid, SIGUSR1); 251 252 usleep(1); 253 while (state != 7) 254 ; 255 } 256 257 int 258 main(void) 259 { 260 int fd[2], num; 261 262 num = 1; 263 printf("1..20\n"); 264 fflush(stdout); 265 signal(SIGUSR1, catch); 266 ppid = getpid(); 267 for (filetype = 0; filetype < FT_END; filetype++) { 268 switch (filetype) { 269 case FT_FIFO: 270 if (mkfifo(FIFONAME, 0666) != 0) 271 err(1, "mkfifo"); 272 fd[0] = -1; 273 fd[1] = -1; 274 break; 275 case FT_SOCKETPAIR: 276 if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC, 277 fd) != 0) 278 err(1, "socketpair"); 279 break; 280 case FT_PIPE: 281 if (pipe(fd) != 0) 282 err(1, "pipe"); 283 break; 284 } 285 state = 0; 286 switch (cpid = fork()) { 287 case -1: 288 err(1, "fork"); 289 case 0: 290 (void)close(fd[1]); 291 child(fd[0], num); 292 break; 293 default: 294 (void)close(fd[0]); 295 parent(fd[1]); 296 break; 297 } 298 num += filetype == FT_FIFO ? 12 : 4; 299 } 300 (void)unlink(FIFONAME); 301 return (0); 302 } 303