#include <config.h>
+#include <assert.h>
+
/* poll(2) is needed on AIX (where 'select' gives a readable
event immediately) and Solaris (where 'select' never gave
a readable event). Also use poll(2) on systems we know work
#if defined _AIX || defined __sun || defined __APPLE__ || \
defined __linux__ || defined __ANDROID__
# define IOPOLL_USES_POLL 1
+ /* Check we've not enabled gnulib's poll module
+ as that will emulate poll() in a way not
+ currently compatible with our usage. */
+# if defined HAVE_POLL
+# error "gnulib's poll() replacement is currently incompatible"
+# endif
#endif
#if IOPOLL_USES_POLL
#include "isapipe.h"
-/* Wait for fdin to become ready for reading or fdout to become a broken pipe.
- Return 0 if fdin can be read() without blocking, or IOPOLL_BROKEN_OUTPUT if
- fdout becomes a broken pipe, otherwise IOPOLL_ERROR if there is a poll()
+/* Wait for FDIN to become ready for reading or FDOUT to become a broken pipe.
+ If either of those are -1, then they're not checked. Set BLOCK to true
+ to wait for an event, otherwise return the status immediately.
+ Return 0 if not BLOCKing and there is no event on the requested descriptors.
+ Return 0 if FDIN can be read() without blocking, or IOPOLL_BROKEN_OUTPUT if
+ FDOUT becomes a broken pipe, otherwise IOPOLL_ERROR if there is a poll()
or select() error. */
-#if IOPOLL_USES_POLL
-
extern int
-iopoll (int fdin, int fdout)
+iopoll (int fdin, int fdout, bool block)
{
+#if IOPOLL_USES_POLL
+
struct pollfd pfds[2] = { /* POLLRDBAND needed for illumos, macOS. */
{ .fd = fdin, .events = POLLIN | POLLRDBAND, .revents = 0 },
{ .fd = fdout, .events = POLLRDBAND, .revents = 0 },
};
+ int ret = 0;
- while (poll (pfds, 2, -1) > 0 || errno == EINTR)
+ while (0 <= ret || errno == EINTR)
{
- if (errno == EINTR)
+ ret = poll (pfds, 2, block ? -1 : 0);
+
+ if (ret < 0)
continue;
+ if (ret == 0 && ! block)
+ return 0;
+ assert (0 < ret);
if (pfds[0].revents) /* input available or pipe closed indicating EOF; */
return 0; /* should now be able to read() without blocking */
if (pfds[1].revents) /* POLLERR, POLLHUP (or POLLNVAL) */
return IOPOLL_BROKEN_OUTPUT; /* output error or broken pipe */
}
- return IOPOLL_ERROR; /* poll error */
-}
#else /* fall back to select()-based implementation */
-extern int
-iopoll (int fdin, int fdout)
-{
int nfds = (fdin > fdout ? fdin : fdout) + 1;
int ret = 0;
/* If fdout has an error condition (like a broken pipe) it will be seen
as ready for reading. Assumes fdout is not actually readable. */
- while (ret >= 0 || errno == EINTR)
+ while (0 <= ret || errno == EINTR)
{
fd_set rfds;
FD_ZERO (&rfds);
- FD_SET (fdin, &rfds);
- FD_SET (fdout, &rfds);
- ret = select (nfds, &rfds, NULL, NULL, NULL);
+ if (0 <= fdin)
+ FD_SET (fdin, &rfds);
+ if (0 <= fdout)
+ FD_SET (fdout, &rfds);
+
+ struct timeval delay = { .tv_sec = 0, .tv_usec = 0 };
+ ret = select (nfds, &rfds, NULL, NULL, block ? NULL : &delay);
if (ret < 0)
continue;
- if (FD_ISSET (fdin, &rfds)) /* input available or EOF; should now */
- return 0; /* be able to read() without blocking */
- if (FD_ISSET (fdout, &rfds)) /* POLLERR, POLLHUP (or POLLIN) */
- return IOPOLL_BROKEN_OUTPUT; /* output error or broken pipe */
+ if (ret == 0 && ! block)
+ return 0;
+ assert (0 < ret);
+ if (0 <= fdin && FD_ISSET (fdin, &rfds)) /* input available or EOF; */
+ return 0; /* should now be able to read() without blocking */
+ if (0 <= fdout && FD_ISSET (fdout, &rfds)) /* equiv to POLLERR */
+ return IOPOLL_BROKEN_OUTPUT; /* output error or broken pipe */
}
- return IOPOLL_ERROR; /* select error */
-}
#endif
+ return IOPOLL_ERROR;
+}
+
/* Return true if fdin is relevant for iopoll().
#include <stdio.h>
#include <assert.h>
#include <getopt.h>
-#include <sys/select.h>
#include <sys/types.h>
#include <signal.h>
#include "die.h"
#include "error.h"
#include "fcntl--.h"
+#include "iopoll.h"
#include "isapipe.h"
#include "posixver.h"
#include "quote.h"
#if HAVE_INOTIFY
# include "hash.h"
-# include <sys/inotify.h>
-#endif
-
-#if defined _AIX || defined __sun || defined __APPLE__ || HAVE_INOTIFY
# include <poll.h>
+# include <sys/inotify.h>
#endif
/* Linux can optimize the handling of local files. */
if (! monitor_output)
return;
- /* Check we've not enabled gnulib's poll module
- as that will emulate poll() in a way not
- currently compatible with tail's usage. */
-#if defined HAVE_POLL
-# error "gnulib's poll() replacement is currently incompatible"
-#endif
-
- /* poll(2) is needed on AIX (where 'select' gives a readable
- event immediately) and Solaris (where 'select' never gave
- a readable event). Also use poll(2) on systems we know work
- and/or are already using poll (inotify). */
-#if defined _AIX || defined __sun || defined __APPLE__ || HAVE_INOTIFY
- struct pollfd pfd;
- pfd.fd = STDOUT_FILENO;
- pfd.events = pfd.revents = 0;
- pfd.events |= POLLRDBAND; /* Needed for illumos, macOS. */
-
- if (poll (&pfd, 1, 0) > 0 && (pfd.revents & (POLLERR | POLLHUP)))
+ if (iopoll (-1, STDOUT_FILENO, false) == IOPOLL_BROKEN_OUTPUT)
die_pipe ();
-#else
- struct timeval delay;
- delay.tv_sec = delay.tv_usec = 0;
-
- fd_set rfd;
- FD_ZERO (&rfd);
- FD_SET (STDOUT_FILENO, &rfd);
-
- /* readable event on STDOUT is equivalent to POLLERR,
- and implies an error condition on output like broken pipe. */
- if (select (STDOUT_FILENO + 1, &rfd, NULL, NULL, &delay) == 1)
- die_pipe ();
-#endif
-
}
static bool