summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPádraig Brady <P@draigBrady.com>2023-02-28 18:36:02 +0000
committerPádraig Brady <P@draigBrady.com>2023-03-01 19:27:36 +0000
commit76b5843ff99977107580cd581213ea2b5b3a81a7 (patch)
tree6a609b39fd0ada8899892e40dbea7befbb2ffd9e
parent5bcc2912e7d7c16d3052a7ed4f0904f72573255e (diff)
downloadcoreutils-76b5843ff99977107580cd581213ea2b5b3a81a7.tar.gz
maint: refactor tail.c to use iopoll
* src/tail.c (check_output_alive): Reuse iopoll() rather than directly calling poll() or select(). * src/iopoll.c (iopoll): Refactor to support non blocking operation, or ignoring descriptors by passing a negative value. * src/iopoll.h (iopoll): Adjust to support a BLOCK parameter. * src/tee.c (tee_files): Adjust iopoll() call to explicitly block. * src/local.mk: Have tail depend on iopoll.c.
-rw-r--r--src/iopoll.c66
-rw-r--r--src/iopoll.h2
-rw-r--r--src/local.mk2
-rw-r--r--src/tail.c40
-rw-r--r--src/tee.c3
5 files changed, 51 insertions, 62 deletions
diff --git a/src/iopoll.c b/src/iopoll.c
index ceb1b43ad..a73ce05bf 100644
--- a/src/iopoll.c
+++ b/src/iopoll.c
@@ -18,6 +18,8 @@
#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
@@ -26,6 +28,12 @@
#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
@@ -39,62 +47,74 @@
#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().
diff --git a/src/iopoll.h b/src/iopoll.h
index 85935e960..00fc99836 100644
--- a/src/iopoll.h
+++ b/src/iopoll.h
@@ -1,6 +1,6 @@
#define IOPOLL_BROKEN_OUTPUT -2
#define IOPOLL_ERROR -3
-int iopoll (int fdin, int fdout);
+int iopoll (int fdin, int fdout, bool block);
bool iopoll_input_ok (int fdin);
bool iopoll_output_ok (int fdout);
diff --git a/src/local.mk b/src/local.mk
index 8269a2f68..13eeea8e0 100644
--- a/src/local.mk
+++ b/src/local.mk
@@ -396,7 +396,9 @@ src_arch_SOURCES = src/uname.c src/uname-arch.c
src_cut_SOURCES = src/cut.c src/set-fields.c
src_numfmt_SOURCES = src/numfmt.c src/set-fields.c
+src_tail_SOURCES = src/tail.c src/iopoll.c
src_tee_SOURCES = src/tee.c src/iopoll.c
+
src_sum_SOURCES = src/sum.c src/sum.h src/digest.c
src_sum_CPPFLAGS = -DHASH_ALGO_SUM=1 $(AM_CPPFLAGS)
diff --git a/src/tail.c b/src/tail.c
index 78022fc4b..92534a592 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -28,7 +28,6 @@
#include <stdio.h>
#include <assert.h>
#include <getopt.h>
-#include <sys/select.h>
#include <sys/types.h>
#include <signal.h>
@@ -38,6 +37,7 @@
#include "die.h"
#include "error.h"
#include "fcntl--.h"
+#include "iopoll.h"
#include "isapipe.h"
#include "posixver.h"
#include "quote.h"
@@ -52,11 +52,8 @@
#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. */
@@ -352,39 +349,8 @@ check_output_alive (void)
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
diff --git a/src/tee.c b/src/tee.c
index e328e6f04..dcf773e16 100644
--- a/src/tee.c
+++ b/src/tee.c
@@ -290,7 +290,8 @@ tee_files (int nfiles, char **files)
if (pipe_check && out_pollable[first_out])
{
/* Monitor for input, or errors on first valid output. */
- int err = iopoll (STDIN_FILENO, fileno (descriptors[first_out]));
+ int err = iopoll (STDIN_FILENO, fileno (descriptors[first_out]),
+ true);
/* Close the output if it became a broken pipe. */
if (err == IOPOLL_BROKEN_OUTPUT)