1 /* $OpenBSD: poll_iocond.c,v 1.3 2021/12/27 16:38:06 visa Exp $ */
2
3 /*
4 * Copyright (c) 2021 Visa Hankala
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 /*
20 * Test poll(2) with various I/O conditions.
21 */
22
23 #include <sys/types.h>
24 #include <sys/ioctl.h>
25 #include <sys/socket.h>
26 #include <sys/stat.h>
27 #include <sys/wait.h>
28 #include <netinet/in.h>
29 #include <netinet/tcp.h>
30 #include <arpa/inet.h>
31
32 #include <assert.h>
33 #include <err.h>
34 #include <fcntl.h>
35 #include <poll.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40
41 #if defined(__OpenBSD__)
42 /* for pty */
43 #include <termios.h>
44 #include <util.h>
45 #endif
46
47 #if !defined(__linux__)
48 #define HAVE_SOCKADDR_LEN 1
49 #endif
50
51 #define MIN(a, b) ((a) <= (b) ? (a) : (b))
52
53 #define TEST_FIFO_NAME "iocond_fifo"
54
55 enum filetype {
56 FTYPE_NONE,
57 FTYPE_FIFO,
58 FTYPE_PIPE,
59 FTYPE_PTY,
60 FTYPE_SOCKET_TCP,
61 FTYPE_SOCKET_UDP,
62 FTYPE_SOCKET_UNIX,
63 };
64
65 static struct {
66 const char *name;
67 enum filetype type;
68 } filetypes[] = {
69 { "fifo", FTYPE_FIFO },
70 { "pipe", FTYPE_PIPE },
71 #if defined(__OpenBSD__)
72 { "pty", FTYPE_PTY },
73 #endif
74 { "socket-tcp", FTYPE_SOCKET_TCP },
75 { "socket-udp", FTYPE_SOCKET_UDP },
76 { "socket-unix", FTYPE_SOCKET_UNIX },
77 };
78
79 static enum filetype filetype = FTYPE_NONE;
80
81 static void cleanup(void);
82 static void proc_barrier(int);
83 static void proc_child(int, int);
84 static void proc_parent(int, int);
85
86 int
main(int argc,char * argv[])87 main(int argc, char *argv[])
88 {
89 const char *ftname;
90 int bfd[2], fds[2];
91 int child_fd = -1;
92 int parent_fd = -1;
93 int sock = -1;
94 unsigned int i;
95 pid_t pid;
96
97 /* Enforce test timeout. */
98 alarm(10);
99
100 if (argc != 2) {
101 fprintf(stderr, "usage: %s filetype\n", argv[0]);
102 return 1;
103 }
104 ftname = argv[1];
105
106 for (i = 0; i < sizeof(filetypes) / sizeof(filetypes[0]); i++) {
107 if (strcmp(ftname, filetypes[i].name) == 0) {
108 filetype = filetypes[i].type;
109 break;
110 }
111 }
112 if (filetype == FTYPE_NONE)
113 errx(1, "unknown filetype");
114
115 /* Open barrier sockets. */
116 if (socketpair(AF_UNIX, SOCK_STREAM, 0, bfd) == -1)
117 err(1, "socketpair");
118
119 atexit(cleanup);
120
121 switch (filetype) {
122 case FTYPE_FIFO:
123 (void)unlink(TEST_FIFO_NAME);
124 if (mkfifo(TEST_FIFO_NAME, 0644) == -1)
125 err(1, "mkfifo");
126 break;
127 case FTYPE_PIPE:
128 if (pipe(fds) == -1)
129 err(1, "pipe");
130 parent_fd = fds[0];
131 child_fd = fds[1];
132 break;
133 #if defined(__OpenBSD__)
134 case FTYPE_PTY:
135 if (openpty(&parent_fd, &child_fd, NULL, NULL, NULL) == -1)
136 err(1, "openpty");
137 break;
138 #endif
139 case FTYPE_SOCKET_TCP: {
140 struct sockaddr_in inaddr;
141
142 sock = socket(AF_INET, SOCK_STREAM, 0);
143
144 memset(&inaddr, 0, sizeof(inaddr));
145 #ifdef HAVE_SOCKADDR_LEN
146 inaddr.sin_len = sizeof(inaddr);
147 #endif
148 inaddr.sin_family = AF_INET;
149 inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
150 if (bind(sock, (struct sockaddr *)&inaddr,
151 sizeof(inaddr)) == -1)
152 err(1, "bind");
153 if (listen(sock, 1) == -1)
154 err(1, "listen");
155 break;
156 }
157 case FTYPE_SOCKET_UDP: {
158 struct sockaddr_in inaddr;
159
160 sock = socket(AF_INET, SOCK_DGRAM, 0);
161
162 memset(&inaddr, 0, sizeof(inaddr));
163 #ifdef HAVE_SOCKADDR_LEN
164 inaddr.sin_len = sizeof(inaddr);
165 #endif
166 inaddr.sin_family = AF_INET;
167 inaddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
168 if (bind(sock, (struct sockaddr *)&inaddr,
169 sizeof(inaddr)) == -1)
170 err(1, "bind");
171 break;
172 }
173 case FTYPE_SOCKET_UNIX:
174 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) == -1)
175 err(1, "socketpair");
176 parent_fd = fds[0];
177 child_fd = fds[1];
178 break;
179 default:
180 errx(1, "unhandled filetype");
181 }
182
183 pid = fork();
184 switch (pid) {
185 case -1:
186 err(1, "fork");
187 case 0:
188 switch (filetype) {
189 case FTYPE_FIFO:
190 child_fd = open(TEST_FIFO_NAME, O_WRONLY);
191 if (child_fd == -1)
192 err(1, "child: open");
193 break;
194 case FTYPE_SOCKET_TCP: {
195 struct sockaddr_in inaddr;
196 socklen_t inaddrlen;
197 int on = 1;
198
199 /* Get the bound address. */
200 inaddrlen = sizeof(inaddr);
201 if (getsockname(sock, (struct sockaddr *)&inaddr,
202 &inaddrlen) == -1)
203 err(1, "child: getsockname");
204
205 child_fd = socket(AF_INET, SOCK_STREAM, 0);
206 if (child_fd == -1)
207 err(1, "child: socket");
208 if (connect(child_fd, (struct sockaddr *)&inaddr,
209 sizeof(inaddr)) == -1)
210 err(1, "child: connect");
211 if (setsockopt(child_fd, IPPROTO_TCP, TCP_NODELAY,
212 &on, sizeof(on)) == -1)
213 err(1, "child: setsockopt(TCP_NODELAY)");
214 break;
215 }
216 case FTYPE_SOCKET_UDP: {
217 struct sockaddr_in inaddr;
218 socklen_t inaddrlen;
219
220 /* Get the bound address. */
221 inaddrlen = sizeof(inaddr);
222 if (getsockname(sock, (struct sockaddr *)&inaddr,
223 &inaddrlen) == -1)
224 err(1, "child: getsockname");
225
226 child_fd = socket(AF_INET, SOCK_DGRAM, 0);
227 if (child_fd == -1)
228 err(1, "child: socket");
229 if (connect(child_fd, (struct sockaddr *)&inaddr,
230 sizeof(inaddr)) == -1)
231 err(1, "child: connect");
232 break;
233 }
234 default:
235 break;
236 }
237 if (parent_fd != -1) {
238 close(parent_fd);
239 parent_fd = -1;
240 }
241 if (sock != -1) {
242 close(sock);
243 sock = -1;
244 }
245 proc_child(child_fd, bfd[1]);
246 _exit(0);
247 default:
248 switch (filetype) {
249 case FTYPE_FIFO:
250 parent_fd = open(TEST_FIFO_NAME, O_RDONLY);
251 if (parent_fd == -1)
252 err(1, "parent: open");
253 break;
254 case FTYPE_SOCKET_TCP: {
255 int on = 1;
256
257 parent_fd = accept(sock, NULL, NULL);
258 if (parent_fd == -1)
259 err(1, "parent: accept");
260 if (setsockopt(parent_fd, IPPROTO_TCP, TCP_NODELAY,
261 &on, sizeof(on)) == -1)
262 err(1, "parent: setsockopt(TCP_NODELAY)");
263 break;
264 }
265 case FTYPE_SOCKET_UDP:
266 parent_fd = sock;
267 sock = -1;
268 break;
269 default:
270 break;
271 }
272 if (child_fd != -1) {
273 close(child_fd);
274 child_fd = -1;
275 }
276 if (sock != -1) {
277 close(sock);
278 sock = -1;
279 }
280 proc_parent(parent_fd, bfd[0]);
281 break;
282 }
283
284 if (waitpid(pid, NULL, 0) == -1)
285 err(1, "waitpid");
286
287 return 0;
288 }
289
290 static void
cleanup(void)291 cleanup(void)
292 {
293 if (filetype == FTYPE_FIFO)
294 (void)unlink(TEST_FIFO_NAME);
295 }
296
297 static void
proc_barrier(int fd)298 proc_barrier(int fd)
299 {
300 int ret;
301 char b = 0;
302
303 ret = write(fd, &b, 1);
304 assert(ret == 1);
305 ret = read(fd, &b, 1);
306 assert(ret == 1);
307 }
308
309 static void
proc_child(int fd,int bfd)310 proc_child(int fd, int bfd)
311 {
312 struct pollfd pfd[2];
313 char buf[1024];
314 size_t nbytes;
315 int ret;
316 char b = 0;
317
318 memset(&pfd, 0, sizeof(pfd));
319
320 proc_barrier(bfd);
321
322 pfd[0].fd = fd;
323 pfd[0].events = POLLIN | POLLOUT | POLLPRI;
324
325 ret = poll(pfd, 1, 1);
326 assert(ret == 1);
327 assert(pfd[0].revents == POLLOUT);
328
329 proc_barrier(bfd);
330
331 ret = write(fd, &b, 1);
332 assert(ret == 1);
333
334 proc_barrier(bfd);
335
336 ret = poll(pfd, 1, 1);
337 assert(ret == 1);
338 assert(pfd[0].revents == POLLOUT);
339
340 proc_barrier(bfd);
341
342 /* parent: read */
343
344 proc_barrier(bfd);
345
346 if (filetype != FTYPE_SOCKET_UDP) {
347 /* write until full */
348 memset(buf, 0, sizeof(buf));
349 nbytes = 0;
350 for (;;) {
351 pfd[0].fd = fd;
352 pfd[0].events = POLLOUT;
353 ret = poll(pfd, 1, 0);
354 if (ret == 0)
355 break;
356 assert(ret == 1);
357 assert(pfd[0].revents == POLLOUT);
358 ret = write(fd, buf, sizeof(buf));
359 assert(ret > 0);
360 nbytes += ret;
361 }
362 ret = write(bfd, &nbytes, sizeof(nbytes));
363 assert(ret == sizeof(nbytes));
364
365 proc_barrier(bfd);
366
367 /* parent: read until empty */
368 }
369
370 proc_barrier(bfd);
371
372 /* Test out-of-band data. */
373 switch (filetype) {
374 #if defined(__OpenBSD__)
375 case FTYPE_PTY: {
376 /* parent: enable user ioctl command mode */
377
378 proc_barrier(bfd);
379
380 ret = write(fd, &b, 1);
381 assert(ret == 1);
382
383 if (ioctl(fd, UIOCCMD(42), NULL) == -1)
384 err(1, "child: ioctl(UIOCCMD)");
385
386 ret = write(fd, &b, 1);
387 assert(ret == 1);
388
389 proc_barrier(bfd);
390
391 /* parent: read, and disable user ioctl command mode */
392
393 proc_barrier(bfd);
394 break;
395 }
396 #endif /* __OpenBSD__ */
397
398 case FTYPE_SOCKET_TCP:
399 ret = send(fd, &b, 1, 0);
400 assert(ret == 1);
401
402 ret = send(fd, &b, 1, MSG_OOB);
403 assert(ret == 1);
404
405 ret = send(fd, &b, 1, 0);
406 assert(ret == 1);
407
408 proc_barrier(bfd);
409
410 /* parent: read */
411
412 proc_barrier(bfd);
413 break;
414
415 default:
416 break;
417 }
418
419 /* Test socket shutdown. */
420 switch (filetype) {
421 case FTYPE_SOCKET_TCP:
422 case FTYPE_SOCKET_UNIX:
423 ret = write(fd, &b, 1);
424 assert(ret == 1);
425
426 ret = shutdown(fd, SHUT_WR);
427 assert(ret == 0);
428
429 proc_barrier(bfd);
430
431 /* parent: read and shutdown */
432
433 proc_barrier(bfd);
434
435 /* Let inet sockets take their time. */
436 if (filetype == FTYPE_SOCKET_TCP)
437 usleep(10000);
438
439 pfd[0].fd = fd;
440 pfd[0].events = POLLIN | POLLOUT | POLLPRI;
441 pfd[1].fd = fd;
442 pfd[1].events = 0;
443
444 ret = poll(pfd, 2, 1);
445 #if defined(__linux__)
446 assert(ret == 2);
447 assert(pfd[0].revents == (POLLIN | POLLOUT | POLLHUP));
448 assert(pfd[1].revents == POLLHUP);
449 #else
450 #if defined(__OpenBSD__)
451 /* XXX */
452 if (filetype == FTYPE_SOCKET_UNIX) {
453 assert(ret == 1);
454 assert(pfd[0].revents == (POLLIN | POLLOUT));
455 assert(pfd[1].revents == 0);
456 } else {
457 #endif /* __OpenBSD__ */
458 assert(ret == 2);
459 assert(pfd[0].revents == (POLLIN | POLLHUP));
460 assert(pfd[1].revents == POLLHUP);
461 #if defined(__OpenBSD__)
462 }
463 #endif /* __OpenBSD__ */
464 #endif
465 break;
466
467 case FTYPE_FIFO:
468 case FTYPE_PIPE:
469 case FTYPE_PTY:
470 case FTYPE_SOCKET_UDP:
471 default:
472 break;
473 }
474
475 proc_barrier(bfd);
476
477 close(fd);
478
479 proc_barrier(bfd);
480
481 pfd[0].fd = fd;
482 pfd[0].events = 0;
483
484 ret = poll(pfd, 1, 1);
485 assert(ret == 1);
486 assert(pfd[0].revents == POLLNVAL);
487 }
488
489 static void
proc_parent(int fd,int bfd)490 proc_parent(int fd, int bfd)
491 {
492 struct pollfd pfd[2];
493 char buf[1024];
494 size_t nbytes;
495 int ret, retries;
496 char b = 0;
497
498 memset(&pfd, 0, sizeof(pfd));
499
500 proc_barrier(bfd);
501
502 pfd[0].fd = fd;
503 pfd[0].events = POLLIN | POLLOUT | POLLPRI;
504 if (filetype == FTYPE_FIFO || filetype == FTYPE_PIPE)
505 pfd[0].events &= ~POLLOUT;
506
507 ret = poll(pfd, 1, 1);
508 switch (filetype) {
509 case FTYPE_FIFO:
510 case FTYPE_PIPE:
511 assert(ret == 0);
512 assert(pfd[0].revents == 0);
513 break;
514 default:
515 assert(ret == 1);
516 assert(pfd[0].revents == POLLOUT);
517 break;
518 }
519
520 proc_barrier(bfd);
521
522 /* child: write */
523
524 proc_barrier(bfd);
525
526 /* Let inet sockets take their time. */
527 if (filetype == FTYPE_SOCKET_TCP ||
528 filetype == FTYPE_SOCKET_UDP)
529 usleep(10000);
530
531 ret = poll(pfd, 1, 1);
532 switch (filetype) {
533 case FTYPE_FIFO:
534 case FTYPE_PIPE:
535 assert(ret == 1);
536 assert(pfd[0].revents == POLLIN);
537 break;
538 case FTYPE_PTY:
539 case FTYPE_SOCKET_TCP:
540 case FTYPE_SOCKET_UDP:
541 case FTYPE_SOCKET_UNIX:
542 assert(ret == 1);
543 assert(pfd[0].revents == (POLLIN | POLLOUT));
544 break;
545 default:
546 assert(0);
547 }
548
549 proc_barrier(bfd);
550
551 ret = read(fd, &b, 1);
552 assert(ret == 1);
553
554 pfd[0].fd = fd;
555 pfd[0].events = POLLIN;
556
557 ret = poll(pfd, 1, 1);
558 assert(ret == 0);
559
560 proc_barrier(bfd);
561
562 if (filetype != FTYPE_SOCKET_UDP) {
563 /* child: write until full */
564 nbytes = 0;
565 ret = read(bfd, &nbytes, sizeof(nbytes));
566 assert(ret == sizeof(nbytes));
567
568 proc_barrier(bfd);
569
570 /* read until empty */
571 retries = 5;
572 while (retries > 0) {
573 pfd[0].fd = fd;
574 pfd[0].events = POLLIN;
575 ret = poll(pfd, 1, 0);
576 if (ret == 0) {
577 retries--;
578 /* Let inet sockets take their time. */
579 if (nbytes > 0 && retries > 0)
580 usleep(10000);
581 continue;
582 }
583 assert(ret == 1);
584 assert(pfd[0].revents == POLLIN);
585 assert(nbytes > 0);
586 ret = read(fd, buf, MIN(sizeof(buf), nbytes));
587 assert(ret > 0);
588 nbytes -= ret;
589 }
590 assert(nbytes == 0);
591 }
592
593 proc_barrier(bfd);
594
595 /* Test out-of-band data. */
596 switch (filetype) {
597 #if defined(__OpenBSD__)
598 case FTYPE_PTY: {
599 int off = 0;
600 int on = 1;
601
602 if (ioctl(fd, TIOCUCNTL, &on) == -1)
603 err(1, "parent: ioctl(TIOCUCNTL, 1)");
604
605 proc_barrier(bfd);
606
607 /* child: write */
608
609 proc_barrier(bfd);
610
611 pfd[0].fd = fd;
612 pfd[0].events = POLLIN | POLLOUT | POLLPRI;
613 pfd[1].fd = fd;
614 pfd[1].events = 0;
615
616 ret = poll(pfd, 2, 1);
617 assert(ret == 1);
618 assert(pfd[0].revents == (POLLIN | POLLOUT | POLLPRI));
619 assert(pfd[1].revents == 0);
620
621 /* Read out-of-band data. */
622 ret = read(fd, buf, sizeof(buf));
623 assert(ret == 1);
624
625 ret = poll(pfd, 2, 1);
626 assert(ret == 1);
627 assert(pfd[0].revents == (POLLIN | POLLOUT));
628 assert(pfd[1].revents == 0);
629
630 /* Read normal data. */
631 ret = read(fd, buf, sizeof(buf));
632 assert(ret == 3);
633
634 ret = poll(pfd, 2, 1);
635 assert(ret == 1);
636 assert(pfd[0].revents == POLLOUT);
637 assert(pfd[1].revents == 0);
638
639 if (ioctl(fd, TIOCUCNTL, &off) == -1)
640 err(1, "parent: ioctl(TIOCUCNTL, 0)");
641
642 proc_barrier(bfd);
643 break;
644 }
645 #endif /* __OpenBSD__ */
646
647 case FTYPE_SOCKET_TCP: {
648 int atmark;
649 int on = 1;
650
651 /* child: write */
652
653 if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &on,
654 sizeof(on)) == -1)
655 err(1, "parent: setsockopt(SO_OOBINLINE)");
656
657 proc_barrier(bfd);
658
659 pfd[0].fd = fd;
660 pfd[0].events = POLLIN | POLLOUT | POLLPRI;
661 pfd[1].fd = fd;
662 pfd[1].events = 0;
663
664 ret = poll(pfd, 2, 1);
665 assert(ret == 1);
666 assert(pfd[0].revents == (POLLIN | POLLOUT | POLLPRI));
667 assert(pfd[1].revents == 0);
668
669 /* Read normal data. */
670 atmark = 0;
671 if (ioctl(fd, SIOCATMARK, &atmark) == -1)
672 err(1, "parent: ioctl(SIOCATMARK)");
673 assert(atmark == 0);
674 ret = recv(fd, buf, sizeof(buf), 0);
675 assert(ret == 1);
676
677 ret = poll(pfd, 2, 1);
678 assert(ret == 1);
679 assert(pfd[0].revents == (POLLIN | POLLOUT | POLLPRI));
680 assert(pfd[1].revents == 0);
681
682 /* Read out-of-band data. */
683 atmark = 0;
684 if (ioctl(fd, SIOCATMARK, &atmark) == -1)
685 err(1, "parent: ioctl(SIOCATMARK)");
686 assert(atmark != 0);
687 ret = recv(fd, &b, 1, 0);
688 assert(ret == 1);
689
690 ret = poll(pfd, 2, 1);
691 assert(ret == 1);
692 assert(pfd[0].revents == (POLLIN | POLLOUT));
693 assert(pfd[1].revents == 0);
694
695 /* Read normal data. */
696 atmark = 0;
697 if (ioctl(fd, SIOCATMARK, &atmark) == -1)
698 err(1, "parent: ioctl(SIOCATMARK)");
699 assert(atmark == 0);
700 ret = recv(fd, buf, sizeof(buf), 0);
701 assert(ret == 1);
702
703 ret = poll(pfd, 2, 1);
704 assert(ret == 1);
705 assert(pfd[0].revents == POLLOUT);
706 assert(pfd[1].revents == 0);
707
708 proc_barrier(bfd);
709 break;
710 }
711
712 default:
713 break;
714 }
715
716 /* Test socket shutdown. */
717 switch (filetype) {
718 case FTYPE_SOCKET_TCP:
719 case FTYPE_SOCKET_UNIX:
720 /* child: write and shutdown */
721
722 proc_barrier(bfd);
723
724 /* Let inet sockets take their time. */
725 if (filetype == FTYPE_SOCKET_TCP)
726 usleep(10000);
727
728 pfd[0].fd = fd;
729 pfd[0].events = POLLIN | POLLOUT | POLLPRI;
730
731 ret = poll(pfd, 1, 1);
732 assert(ret == 1);
733 assert(pfd[0].revents == (POLLIN | POLLOUT));
734
735 ret = read(fd, &b, 1);
736 assert(ret == 1);
737
738 ret = poll(pfd, 1, 1);
739 assert(ret == 1);
740 assert(pfd[0].revents == (POLLIN | POLLOUT));
741
742 ret = read(fd, &b, 1);
743 assert(ret == 0);
744
745 ret = shutdown(fd, SHUT_WR);
746 assert(ret == 0);
747
748 proc_barrier(bfd);
749
750 pfd[0].fd = fd;
751 pfd[0].events = POLLIN | POLLOUT | POLLPRI;
752 pfd[1].fd = fd;
753 pfd[1].events = 0;
754
755 ret = poll(pfd, 2, 1);
756 #if defined(__linux__)
757 assert(ret == 2);
758 assert(pfd[0].revents == (POLLIN | POLLOUT | POLLHUP));
759 assert(pfd[1].revents == POLLHUP);
760 #else
761 #if defined(__OpenBSD__)
762 /* XXX */
763 if (filetype == FTYPE_SOCKET_UNIX) {
764 assert(ret == 1);
765 assert(pfd[0].revents == (POLLIN | POLLOUT));
766 assert(pfd[1].revents == 0);
767 } else {
768 #endif /* __OpenBSD__ */
769 assert(ret == 2);
770 assert(pfd[0].revents == (POLLIN | POLLHUP));
771 assert(pfd[1].revents == POLLHUP);
772 #if defined(__OpenBSD__)
773 }
774 #endif /* __OpenBSD__ */
775 #endif
776 break;
777
778 case FTYPE_FIFO:
779 case FTYPE_PIPE:
780 case FTYPE_PTY:
781 case FTYPE_SOCKET_UDP:
782 default:
783 break;
784 }
785
786 proc_barrier(bfd);
787
788 /* child: close */
789
790 proc_barrier(bfd);
791
792 pfd[0].fd = fd;
793 pfd[0].events = POLLIN | POLLOUT | POLLPRI;
794 pfd[1].fd = fd;
795 pfd[1].events = 0;
796
797 ret = poll(pfd, 2, 1);
798 switch (filetype) {
799 case FTYPE_FIFO:
800 case FTYPE_PIPE:
801 case FTYPE_PTY:
802 assert(ret == 2);
803 #if defined(__linux__)
804 assert(pfd[0].revents == POLLHUP);
805 assert(pfd[1].revents == POLLHUP);
806 #else
807 assert(pfd[0].revents == (POLLIN | POLLHUP));
808 assert(pfd[1].revents == POLLHUP);
809 #endif
810 break;
811 case FTYPE_SOCKET_TCP:
812 case FTYPE_SOCKET_UNIX:
813 assert(ret == 2);
814 #if defined(__linux__)
815 assert(pfd[0].revents == (POLLIN | POLLOUT | POLLHUP));
816 assert(pfd[1].revents == POLLHUP);
817 #else
818 assert(pfd[0].revents == (POLLIN | POLLHUP));
819 assert(pfd[1].revents == POLLHUP);
820 #endif
821 break;
822 case FTYPE_SOCKET_UDP:
823 assert(ret == 1);
824 assert(pfd[0].revents == POLLOUT);
825 assert(pfd[1].revents == 0);
826 break;
827 default:
828 assert(0);
829 }
830
831 close(fd);
832 }
833