1 /* iopoll.c -- broken pipe detection / non blocking output handling
2 Copyright (C) 2022-2024 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>.
17 Written by Carl Edquist in collaboration with Arsen Arsenović. */
21 /* poll(2) is needed on AIX (where 'select' gives a readable
22 event immediately) and Solaris (where 'select' never gave
23 a readable event). Also use poll(2) on systems we know work
24 and/or are already using poll (linux). */
26 #if defined _AIX || defined __sun || defined __APPLE__ || \
27 defined __linux__ || defined __ANDROID__
28 # define IOPOLL_USES_POLL 1
29 /* Check we've not enabled gnulib's poll module
30 as that will emulate poll() in a way not
31 currently compatible with our usage. */
32 # if defined HAVE_POLL
33 # error "gnulib's poll() replacement is currently incompatible"
40 # include <sys/select.h>
49 /* BROKEN_OUTPUT selects the mode of operation of this function.
50 If BROKEN_OUTPUT, wait for FDIN to become ready for reading
51 or FDOUT to become a broken pipe.
52 If !BROKEN_OUTPUT, wait for FDIN or FDOUT to become ready for writing.
53 If either of those are -1, then they're not checked. Set BLOCK to true
54 to wait for an event, otherwise return the status immediately.
55 Return 0 if not BLOCKing and there is no event on the requested descriptors.
56 Return 0 if FDIN can be read() without blocking, or IOPOLL_BROKEN_OUTPUT if
57 FDOUT becomes a broken pipe. If !BROKEN_OUTPUT return 0 if FDOUT writable.
58 Otherwise return IOPOLL_ERROR if there is a poll() or select() error. */
61 iopoll_internal (int fdin
, int fdout
, bool block
, bool broken_output
)
63 affirm (fdin
!= -1 || fdout
!= -1);
66 struct pollfd pfds
[2] = { /* POLLRDBAND needed for illumos, macOS. */
67 { .fd
= fdin
, .events
= POLLIN
| POLLRDBAND
, .revents
= 0 },
68 { .fd
= fdout
, .events
= POLLRDBAND
, .revents
= 0 },
70 int check_out_events
= POLLERR
| POLLHUP
| POLLNVAL
;
75 pfds
[0].events
= pfds
[1].events
= POLLOUT
;
76 check_out_events
= POLLOUT
;
79 while (0 <= ret
|| errno
== EINTR
)
81 ret
= poll (pfds
, 2, block
? -1 : 0);
85 if (ret
== 0 && ! block
)
88 if (pfds
[0].revents
) /* input available or pipe closed indicating EOF; */
89 return 0; /* should now be able to read() without blocking */
90 if (pfds
[1].revents
& check_out_events
)
91 return broken_output
? IOPOLL_BROKEN_OUTPUT
: 0;
94 #else /* fall back to select()-based implementation */
96 int nfds
= (fdin
> fdout
? fdin
: fdout
) + 1;
99 if (FD_SETSIZE
< nfds
)
105 /* If fdout has an error condition (like a broken pipe) it will be seen
106 as ready for reading. Assumes fdout is not actually readable. */
107 while (0 <= ret
|| errno
== EINTR
)
114 FD_SET (fdout
, &fds
);
116 struct timeval delay
= {0};
118 broken_output
? &fds
: nullptr,
119 broken_output
? nullptr : &fds
,
120 nullptr, block
? nullptr : &delay
);
124 if (ret
== 0 && ! block
)
127 if (0 <= fdin
&& FD_ISSET (fdin
, &fds
)) /* input available or EOF; */
128 return 0; /* should now be able to read() without blocking */
129 if (0 <= fdout
&& FD_ISSET (fdout
, &fds
)) /* equiv to POLLERR */
130 return broken_output
? IOPOLL_BROKEN_OUTPUT
: 0;
138 iopoll (int fdin
, int fdout
, bool block
)
140 return iopoll_internal (fdin
, fdout
, block
, true);
145 /* Return true if fdin is relevant for iopoll().
146 An fd is not relevant for iopoll() if it is always ready for reading,
147 which is the case for a regular file or block device. */
150 iopoll_input_ok (int fdin
)
153 bool always_ready
= fstat (fdin
, &st
) == 0
154 && (S_ISREG (st
.st_mode
)
155 || S_ISBLK (st
.st_mode
));
156 return ! always_ready
;
159 /* Return true if fdout is suitable for iopoll().
160 Namely, fdout refers to a pipe. */
163 iopoll_output_ok (int fdout
)
165 return isapipe (fdout
) > 0;
169 # define IS_EAGAIN(errcode) ((errcode) == EAGAIN || (errcode) == EWOULDBLOCK)
171 # define IS_EAGAIN(errcode) ((errcode) == EAGAIN)
174 /* Inspect the errno of the previous syscall.
175 On EAGAIN, wait for the underlying file descriptor to become writable.
176 Return true, if EAGAIN has been successfully handled. */
179 fwait_for_nonblocking_write (FILE *f
)
181 if (! IS_EAGAIN (errno
))
182 /* non-recoverable write error */
189 /* wait for the file descriptor to become writable */
190 if (iopoll_internal (-1, fd
, true, false) != 0)
193 /* successfully waited for the descriptor to become writable */
203 /* wrapper for fclose() that also waits for F if non blocking. */
206 fclose_wait (FILE *f
)
213 if (! fwait_for_nonblocking_write (f
))
217 return fclose (f
) == 0;
221 /* wrapper for fwrite() that also waits for F if non blocking. */
224 fwrite_wait (char const *buf
, ssize_t size
, FILE *f
)
228 const size_t written
= fwrite (buf
, 1, size
, f
);
231 if (size
<= 0) /* everything written */
234 if (! fwait_for_nonblocking_write (f
))