I'm trying to use poll(2) on FIFO on various platforms, but (compared to Linux, Solaris, AIX), HP-UX's behavior is somewhat different to other platforms.
Below code creates a FIFO(named pipe) and poll it with 3s timeout. Since this code doesn't write to the FIFO, I expect poll result would be 0.
#include <fcntl.h>
#include <poll.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#if defined(CLOCK_MONOTONIC)
#define MY_CLOCK_TIME CLOCK_MONOTONIC
#elif defined(CLOCK_REALTIME)
#define MY_CLOCK_TIME CLOCK_REALTIME
#else
#error neither CLOCK_REALTIME nor CLOCK_MONOTONIC defined.
#endif
#define HANDLE_ERROR(expr, msg) \
do \
{ \
if ((expr) < 0) \
{ \
perror(msg); \
exit(EXIT_FAILURE); \
} \
} while (0);
namespace {
const char pipename[] = "pipe";
template <size_t N>
struct type_of_size
{
typedef char type[N];
};
template <typename T, size_t Size>
typename type_of_size<Size>::type& sizeof_array_helper(T (&)[Size]);
#define SIZE_OF_ARR(pArray) sizeof(sizeof_array_helper(pArray))
int my_unlink(const char* name)
{
int result = unlink(name);
if (result < 0)
{
if (errno == ENOENT)
{
result = 0;
errno = 0;
}
}
return result;
}
double timediff(const struct timespec& t1, const struct timespec& t2)
{
return static_cast<double>(static_cast<int64_t>(
(t1.tv_sec - t2.tv_sec) * 1000000000LL + (t1.tv_nsec - t2.tv_nsec))) /
1000000000LL;
}
} // namespace
int main()
{
HANDLE_ERROR(my_unlink(pipename), "unlink");
HANDLE_ERROR(mkfifo(pipename, 0600), "mkfifo");
int result = 0;
int poll_timeout = 3000; // 3s
struct timespec before;
memset(&before, 0, sizeof(struct timespec));
struct timespec after;
memset(&after, 0, sizeof(struct timespec));
int fd = open(pipename, O_RDONLY | O_NONBLOCK);
HANDLE_ERROR((fd < 0), "open");
pollfd fds[1];
memset(fds, 0, sizeof(pollfd) * SIZE_OF_ARR(fds));
fds[0].fd = fd;
fds[0].events = POLLIN;
HANDLE_ERROR(clock_gettime(MY_CLOCK_TIME, &before), "clock_gettime");
#ifdef USE_FAKE_OPEN
int fakeopen_fd = open(pipename, O_WRONLY | O_NONBLOCK);
HANDLE_ERROR((fakeopen_fd < 0), "open");
#endif
result = poll(fds, SIZE_OF_ARR(fds), poll_timeout);
memset(&after, 0, sizeof(struct timespec));
HANDLE_ERROR(clock_gettime(MY_CLOCK_TIME, &after), "clock_gettime");
double interval = timediff(after, before);
printf("call interval: %.3f, poll result: %d, errr: %s\n", interval, result, strerror(errno));
#ifdef USE_FAKE_OPEN
close(fakeopen_fd);
#endif
close(fd);
return (interval > 2.0) ? EXIT_SUCCESS : EXIT_FAILURE;
}
On Linux, Solaris 10, AIX 7.1, it works as expected(call interval: 3.000, poll result: 0, errr: Error 0
), but HP-UX(11.31) doesn't obey timeout parameter and returns immediately(call interval: 0.000, poll result: 1, errr: Error 0
).
If I open FIFO for writing before polling for reading it, (define USE_FAKE_OPEN
) it works as expected even for HP-UX.
What makes this behavior?
Is HP-UX's poll POSIX Compliant?
Okay, there is a rule of programming that "It's Always Your Fault (Select Isn't Broken)", but HP says their poll on FIFO is broken in their documentation for HP-UX patch PHKL_41419:
poll(2) sets POLLIN (data ready for reading)event even if there is no writer at the other end when a FIFO is opened with O_RDONLY in non blocking mode(O_NONBLOCK set).
Case closed.