Reputation: 8141
I checked this code several times and cannot understand why does poll() return immediately?
Here file is opened for read and should wait for event. How to make it wait for input?
#include <iostream>
#include <poll.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
using namespace std;
ssize_t read_out_to_the_end(int fd){
char chunk[1024];
ssize_t ret = 0, n;
while((n = ::read(fd, chunk, sizeof chunk)) > 0){
ret += n;
cerr << "read chunk: " << n << " | ";
cerr.write(chunk, n);
cerr << endl;
}
if (n < 0) {
cerr << "err in read" << endl;
}
else if (ret == 0){
cerr << "nothing to read" << endl;
}
return ret;
}
int main() {
int bininfd = open("bin-in", O_RDONLY | O_CREAT);//, 0644/*S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH*/);
if (bininfd < 0) {
perror("err in open(binin)");
return -1;
}
struct pollfd pollfds[] = {
{bininfd, POLLIN, 0},
};
auto&[pfd] = pollfds;
while (1) {
pfd.revents = 0; // cleanup, shouldn't it be redundant
int pollret = poll(pollfds, 1, -1);
if (pollret > 0) {
if (pfd.revents & POLLIN) {
cerr << "(pfd.revents & POLLIN)" << endl;
read_out_to_the_end(pfd.fd);
}
} else if (pollret == 0) {
cerr << "poll timed out" << endl;
continue;
} else {
cerr << "check for error" << endl;
continue;
}
}
}
the output is
(pfd.revents & POLLIN)
nothing to read
(pfd.revents & POLLIN)
nothing to read
(pfd.revents & POLLIN)
nothing to read
(pfd.revents & POLLIN)
nothing to read
(pfd.revents & POLLIN)
............... etc ....................
UPDATE:
Upvotes: 0
Views: 1980
Reputation:
poll()
or select()
never block on regular files. They always return a regular file as "ready". If you want to use poll()
to do what tail -f
does, you're on the wrong track.
Quoting from the SUSv4 standard:
The
poll()
function shall support regular files, terminal and pseudo-terminal devices, FIFOs, pipes, sockets and[OB XSR]
STREAMS-based files. The behavior ofpoll()
on elements of fds that refer to other types of file is unspecified.Regular files shall always poll TRUE for reading and writing.
Since using poll()
or select()
on regular files is pretty much useless, newer interfaces have tried to remedy that. On BSD, you could use kqueue(2)
with EVFILT_READ
, and on Linux inotify(2)
with IN_MODIFY
. The newer epoll(7)
interface on Linux will simply error out with EPERM
if you try to watch a regular file.
Unfortunately, neither of those is standard.
Upvotes: 3
Reputation: 595991
read_out_to_the_end()
has several issues:
ret
is uninitialized.
The while
loop is incrementing n
when it should be assigning it instead. But then if the while
loop hits the EOF, if( n == 0)
will be true even if data was actually read before hitting EOF.
chunk
may be null-terminated, but it may also receive nulls too, depending on the input data. So it should not be written to cerr
(why not cout
?) using operator<<
, use cerr.write()
instead so that you can pass it the actual number of bytes read.
Try this instead:
ssize_t read_out_to_the_end(int fd){
char chunk[1024];
ssize_t ret = 0, n;
while((n = ::read(fd, chunk, sizeof chunk)) > 0){
ret += n;
cerr << "read chunk: " << n << " | ";
cerr.write(chunk, n);
cerr << endl;
}
if (n < 0) {
cerr << "err in read" << endl;
}
else if (ret == 0){
cerr << "nothing to read" << endl;
}
return ret;
}
int main() {
int bininfd = open("bin-in", O_RDONLY | O_CREAT);//, 0644/*S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH*/);
if (bininfd < 0) {
perror("err in open(binin)");
return -1;
}
pollfd pfd = {};
pfd.fd = bininfd;
pfd.events = POLLIN;
while (true) {
pfd.revents = 0; // cleanup, shouldn't it be redundant
int pollret = poll(&pfd, 1, -1);
if (pollret > 0) {
if (pfd.revents & POLLIN) {
cerr << "(pfd.revents & POLLIN)" << endl;
read_out_to_the_end(pfd.fd);
}
} else if (pollret == 0) {
cerr << "poll timed out" << endl;
continue;
} else {
cerr << "poll error " << errno << endl;
break;
}
}
}
Also, on a side note, the open()
documentation says:
The
mode
argument specifies the file mode bits be applied when a new file is created. This argument must be supplied when O_CREAT or O_TMPFILE is specified inflags
; if neither O_CREAT nor O_TMPFILE is specified, thenmode
is ignored. The effective mode is modified by the process'sumask
in the usual way: in the absence of a default ACL, the mode of the created file is(mode & ~umask)
. Note that this mode applies only to future accesses of the newly created file; theopen()
call that creates a read-only file may well return a read/write file descriptor.
Upvotes: 1