1 /* $FreeBSD$ */ 2 3 #include <sys/socket.h> 4 #include <sys/select.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 #define SETUP(fd, rfds, tv) do { \ 21 FD_ZERO(&(rfds)); \ 22 FD_SET((fd), &(rfds)); \ 23 (tv).tv_sec = 0; \ 24 (tv).tv_usec = 0; \ 25 } while (0) 26 27 static int filetype; 28 29 static const char * 30 decode_events(int events) 31 { 32 return (events ? "set" : "clear"); 33 } 34 35 static void 36 report(int num, const char *state, int expected, int got) 37 { 38 if (!expected == !got) 39 printf("ok %-2d ", num); 40 else 41 printf("not ok %-2d", num); 42 printf(" %s state %s: expected %s; got %s\n", 43 filetype == FT_PIPE ? "Pipe" : 44 filetype == FT_SOCKETPAIR ? "Sock" : "FIFO", 45 state, decode_events(expected), decode_events(got)); 46 fflush(stdout); 47 } 48 49 static pid_t cpid; 50 static pid_t ppid; 51 static volatile sig_atomic_t state; 52 53 static void 54 catch(int sig) 55 { 56 state++; 57 } 58 59 static void 60 child(int fd, int num) 61 { 62 fd_set rfds; 63 struct timeval tv; 64 int fd1, fd2; 65 char buf[256]; 66 67 if (filetype == FT_FIFO) { 68 fd = open(FIFONAME, O_RDONLY | O_NONBLOCK); 69 if (fd < 0) 70 err(1, "open for read"); 71 } 72 if (fd >= FD_SETSIZE) 73 errx(1, "fd = %d too large for select()", fd); 74 75 if (filetype == FT_FIFO) { 76 SETUP(fd, rfds, tv); 77 if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 78 err(1, "select"); 79 /* 80 * This state (a reader for which there has never been a 81 * writer) is reported quite differently for select() than 82 * for poll(). select() must see a ready-to-read descriptor 83 * since read() will see EOF and not block; it cannot 84 * distinguish this state from the one of a reader for which 85 * there has been a writer but all writers have gone away 86 * and all data has been read. poll() and distinguish these 87 * states by returning POLLHUP only for the latter; it does 88 * this, although this makes it inconsistent with the 89 * blockability of read() in the former. 90 */ 91 report(num++, "0", 1, FD_ISSET(fd, &rfds)); 92 } 93 kill(ppid, SIGUSR1); 94 95 usleep(1); 96 while (state != 1) 97 ; 98 if (filetype != FT_FIFO) { 99 /* 100 * The connection cannot be reestablished. Use the code that 101 * delays the read until after the writer disconnects since 102 * that case is more interesting. 103 */ 104 state = 4; 105 goto state4; 106 } 107 SETUP(fd, rfds, tv); 108 if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 109 err(1, "select"); 110 report(num++, "1", 0, FD_ISSET(fd, &rfds)); 111 kill(ppid, SIGUSR1); 112 113 usleep(1); 114 while (state != 2) 115 ; 116 SETUP(fd, rfds, tv); 117 if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 118 err(1, "select"); 119 report(num++, "2", 1, FD_ISSET(fd, &rfds)); 120 if (read(fd, buf, sizeof buf) != 1) 121 err(1, "read"); 122 SETUP(fd, rfds, tv); 123 if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 124 err(1, "select"); 125 report(num++, "2a", 0, FD_ISSET(fd, &rfds)); 126 kill(ppid, SIGUSR1); 127 128 usleep(1); 129 while (state != 3) 130 ; 131 SETUP(fd, rfds, tv); 132 if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 133 err(1, "select"); 134 report(num++, "3", 1, FD_ISSET(fd, &rfds)); 135 kill(ppid, SIGUSR1); 136 137 /* 138 * Now we expect a new writer, and a new connection too since 139 * we read all the data. The only new point is that we didn't 140 * start quite from scratch since the read fd is not new. Check 141 * startup state as above, but don't do the read as above. 142 */ 143 usleep(1); 144 while (state != 4) 145 ; 146 state4: 147 SETUP(fd, rfds, tv); 148 if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 149 err(1, "select"); 150 report(num++, "4", 0, FD_ISSET(fd, &rfds)); 151 kill(ppid, SIGUSR1); 152 153 usleep(1); 154 while (state != 5) 155 ; 156 SETUP(fd, rfds, tv); 157 if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 158 err(1, "select"); 159 report(num++, "5", 1, FD_ISSET(fd, &rfds)); 160 kill(ppid, SIGUSR1); 161 162 usleep(1); 163 while (state != 6) 164 ; 165 /* 166 * Now we have no writer, but should still have data from the old 167 * writer. Check that we have a data-readable condition, and that 168 * the data can be read in the usual way. 169 */ 170 SETUP(fd, rfds, tv); 171 if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 172 err(1, "select"); 173 report(num++, "6", 1, FD_ISSET(fd, &rfds)); 174 if (read(fd, buf, sizeof buf) != 1) 175 err(1, "read"); 176 SETUP(fd, rfds, tv); 177 if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 178 err(1, "select"); 179 report(num++, "6a", 1, FD_ISSET(fd, &rfds)); 180 if (filetype == FT_FIFO) { 181 /* 182 * Check that the readable-data condition is sticky for a 183 * new reader and for the old reader. We really only have 184 * a hangup condition, but select() can only see this as 185 * a readable-data condition for null data. select() 186 * cannot distinguish this state from the initial state 187 * where there is a reader but has never been a writer, so 188 * the following tests (to follow the pattern in pipepoll.c) 189 * essentially test state 0 again. 190 */ 191 fd2 = open(FIFONAME, O_RDONLY | O_NONBLOCK); 192 if (fd2 < 0) 193 err(1, "open for read"); 194 fd1 = fd; 195 fd = fd2; 196 SETUP(fd, rfds, tv); 197 if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 198 err(1, "select"); 199 report(num++, "6b", 1, FD_ISSET(fd, &rfds)); 200 fd = fd1; 201 SETUP(fd, rfds, tv); 202 if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 203 err(1, "select"); 204 report(num++, "6c", 1, FD_ISSET(fd, &rfds)); 205 close(fd2); 206 SETUP(fd, rfds, tv); 207 if (select(fd + 1, &rfds, NULL, NULL, &tv) < 0) 208 err(1, "select"); 209 report(num++, "6d", 1, FD_ISSET(fd, &rfds)); 210 } 211 close(fd); 212 kill(ppid, SIGUSR1); 213 214 exit(0); 215 } 216 217 static void 218 parent(int fd) 219 { 220 usleep(1); 221 while (state != 1) 222 ; 223 if (filetype == FT_FIFO) { 224 fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); 225 if (fd < 0) 226 err(1, "open for write"); 227 } 228 kill(cpid, SIGUSR1); 229 230 usleep(1); 231 while (state != 2) 232 ; 233 if (write(fd, "", 1) != 1) 234 err(1, "write"); 235 kill(cpid, SIGUSR1); 236 237 usleep(1); 238 while (state != 3) 239 ; 240 if (close(fd) != 0) 241 err(1, "close for write"); 242 kill(cpid, SIGUSR1); 243 244 usleep(1); 245 while (state != 4) 246 ; 247 if (filetype != FT_FIFO) 248 return; 249 fd = open(FIFONAME, O_WRONLY | O_NONBLOCK); 250 if (fd < 0) 251 err(1, "open for write"); 252 kill(cpid, SIGUSR1); 253 254 usleep(1); 255 while (state != 5) 256 ; 257 if (write(fd, "", 1) != 1) 258 err(1, "write"); 259 kill(cpid, SIGUSR1); 260 261 usleep(1); 262 while (state != 6) 263 ; 264 if (close(fd) != 0) 265 err(1, "close for write"); 266 kill(cpid, SIGUSR1); 267 268 usleep(1); 269 while (state != 7) 270 ; 271 } 272 273 int 274 main(void) 275 { 276 int fd[2], num; 277 278 num = 1; 279 printf("1..20\n"); 280 fflush(stdout); 281 signal(SIGUSR1, catch); 282 ppid = getpid(); 283 for (filetype = 0; filetype < FT_END; filetype++) { 284 switch (filetype) { 285 case FT_FIFO: 286 if (mkfifo(FIFONAME, 0666) != 0) 287 err(1, "mkfifo"); 288 fd[0] = -1; 289 fd[1] = -1; 290 break; 291 case FT_SOCKETPAIR: 292 if (socketpair(AF_UNIX, SOCK_STREAM, AF_UNSPEC, 293 fd) != 0) 294 err(1, "socketpair"); 295 break; 296 case FT_PIPE: 297 if (pipe(fd) != 0) 298 err(1, "pipe"); 299 break; 300 } 301 state = 0; 302 switch (cpid = fork()) { 303 case -1: 304 err(1, "fork"); 305 case 0: 306 (void)close(fd[1]); 307 child(fd[0], num); 308 break; 309 default: 310 (void)close(fd[0]); 311 parent(fd[1]); 312 break; 313 } 314 num += filetype == FT_FIFO ? 12 : 4; 315 } 316 (void)unlink(FIFONAME); 317 return (0); 318 } 319