Hi Pádraig,
Getting back to this portability question:
On Fri, 2 Dec 2022, Pádraig Brady wrote:
Anyway if it's possible just to use poll(2) (the system one, not the
gnulib replacement), that might simplify the portability logic.
Yes it would be better to use poll() if possible,
and that's what I attempted with tail(1) recently.
From the gnulib docs on poll():
"
Portability problems fixed by Gnulib:
This function is missing on some platforms:
mingw, MSVC 14, HP NonStop.
This function doesn't work on special files like @file{/dev/null} and ttys
like
@file{/dev/tty} on some platforms:
AIX 5.3, Mac OS X 10.4.0
Portability problems not fixed by Gnulib:
Under Windows, when passing a pipe, Gnulib's @code{poll} replacement might
return 0 even before the timeout has passed. Programs using it with pipes
can
thus busy wait.
On some platforms, file descriptors other than sockets do not support
POLLHUP; they will return a "readable" or "writable" status instead:
AIX 7.2, HP NonStop.
"
So to use poll() everywhere we'd need the gnulib module.
But empirically the replacement didn't work on macos at least
for this use case, and we know the select emulation wouldn't work on AIX.
So portable use of poll() will be awkward.
Don't remember if i said so already or not, but thanks for the summary!
In my last patch i made a first attempt to define a
HAVE_POLL_PIPE_CLOSE_DETECTION in configure.ac using AC_RUN_IFELSE to test
poll() functionality. Arsen pointed out that this does not work for
cross-compiling. (That's too bad, but, i think i understand now why it's
a problem.)
We could still do just an AC_COMPILE_IFELSE to test whether native poll()
is available, though if i understand your summary right there are a number
of platforms where native poll() is available but won't work correctly
here.
So, if we need to separate out the poll() vs select() implementations
using a list of platforms, do we have a good idea what list of platforms
are "ok for native poll pipe detection", or alternatively a list of
platforms that are not ok?
So tail.c uses:
#if defined _AIX || defined __sun || defined __APPLE__ || HAVE_INOTIFY
but as far as i can tell HAVE_INOTIFY relates to the use of inotify in
tail, which is specific to "tail -f" mode, and perhaps not relevant to the
logic in tee (or other filters).
The section you quoted "From the gnulib docs on poll()" makes it sound
like there might be problems with: Windows, mingw, MSVC 14, HP NonStop,
AIX 5.3 & 7.2, and Mac OS X 10.4.0. (Already that makes me wonder about
_AIX and __APPLE__ being in the list of platforms to use poll().)
Anyway, just trying to get a handle on what might be a good way to do the
preprocessor macro logic to decide between the poll() and select()
implementations.
I guess in worst case, it sounds like select() could be used everywhere.
And there is some appeal to having a single implementation. But select()
does seem less efficient if poll() is available; for instance with
select(), two fd_sets need to be zeroed out (128 bytes each) before every
call to read(), compared to the poll() version that only needs to
initialize two struct pollfds (8 bytes each). So i still see some value
in doing poll() where possible.
Any thoughts on how to put together preprocessor logic that gets at the
heart of the issue?
Thanks,
Carl