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