I open a named pipe (fifo created by mkfifo) with non blocking flag (open(...O_NONBLOCK)) then start polling (poll(...)). So far so good.
Then from the command line I do a couple of
echo 123 > /tmp/fifo
They are all read out of the pipe as expected (at least I expect that's how they should work normally).
My problem is that after the first echo, POLLHUP is set and it is stuck, poll returns immediately from that point.
How do I clear / get rid of POLLHUP ?
It starts to drive me crazy :(
Yes the other end of the pipe got closed (after it was opened previously), so it became half closed, but my end is still open and alive and I like it that way. It's not dead, I can still receive new echoes via the pipe, it's just poll cries a river of POLLHUP (which I didn't even requested in the first place in events, but poll can just tag them on anyway [man poll: "revents can include any of those specified in events, or one of the values POLLERR, POLLHUP"]) and pretty much useless because of that.
Obviously I cannot get that fd out of the set, because I still want to be notified about new data on it.
I do NOT want to close it, because it's not a use-once-pipe, I like reusing the same thing and not throw them away... among other things I do not have the pipe name anymore, I only have the file descriptor (and getting the filename from fd seems like a bitch... I Googled that too...)
I still believe in the power of Linux, and that there must be a better (more performance efficient / race condition safe) way to do this.
Here is what I have read, but did not help solving the problem.
In my desperation I tried doing even things like this (which did not help):
int newfd = dup(fds[i].fd);
close(fds[i].fd);
dup2(newfd, fds[i].fd);
close(newfd);
Any ideas? Am I doing something completely wrong?
(I can always go back to just trying to read all pipes periodically (which actually works), this right now is not latency critical, but I don't know what would I do if it were...)
Here are some code to reproduce my problem (This is not the production code that I'm trying to build, there are obviously more than 1 pipe that I want to poll...)
#include <stdio.h>
#include <sys/types.h> // mkfifo
#include <sys/stat.h> // mkfifo
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <poll.h>
int main(int argc, char **argv) {
char* pipename = "/tmp/fifo";
mkfifo(pipename, S_IWUSR | S_IRUSR | S_IRGRP);
int fd = open(pipename, O_RDONLY | O_NONBLOCK); /// O_ASYNC, O_SYNC
struct pollfd fds[1];
fds[0].fd = fd;
fds[0].events = POLLIN;
fds[0].revents = 0;
while (1) {
int res = poll(fds, 1, 1000);
if (res<0) { perror("poll"); return 1; }
if (res==0) { printf(".
"); continue; }
printf("Poll [%d]: 0x%04x on %d
", 0, fds[0].revents, fds[0].fd);
char buff[512];
int count = (int)read(fds[0].fd, buff, (size_t)(sizeof(buff)-1));
if (count>=0) {
buff[count] = 0;
printf("Pipe read %d bytes: '%s'
", count, buff);
usleep(1000*100); /// cpu protector sleep for POLLHUP :)
}
}
return 0;
}
Notes:
I'm using gcc (4.6.3) on Linux (lubuntu) platform (x64). But in the end I want to cross compile it for embedded target.
I'm sure I must have missed some information peaces out, so ask away...
Solution/Workaround:
- Workaround #1 suggested by mark4o is to open the pipe with
O_RDWR
instead of O_RDONLY
. This way you won't get constant POLLHUP
-s (of course you won't get any witch might be a problem). Also the reader will need write permission to the pipe (which you might not have in certain cases).
See Question&Answers more detail:
os