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