Why Does Poll Keep Returning Although There Is No Input

Why does poll keep returning although there is no input?

An EOF condition in a regular file is still readable. In other words, your read() won't block. Here's a nice list of how different implementations of poll() react to EOF in different sorts of file descriptors: http://www.greenend.org.uk/rjk/tech/poll.html

Note that regular files always return POLLIN. So you need to test for EOF separately. In fact, poll on a regular file doesn't do anything for you. You'll need sockets or pipes or something to test your code.

Other notes: you probably want to check for other results in .revents. POLLERR, POLLHUP, and POLLNVAL all signal different error conditions, and need special handling.

use poll() timeout only for new data on socket

Probably been answered in the linked posts, but the basic idea is that the poll, select, and other mechanisms do not tell you when there is new data on the socket. As you mention correctly, they only tell you when a read() would not block.

You may use EPOLLET with Linux's epoll(7) interface (other systems might have other equivalents) to do what you want; however keep in mind this is not portable.

The correct and accepted design is to either consume the network buffer fully, keep partial messages in a application-defined buffer (i.e. not in the socket's buffer) and keep track of how much additional data you need to read from the network.

Poll works on stdin when entering manually, but not when input is piped and not redirected

The problem is that poll (just like select) only tell you that a call to e.g. read will not block. It doesn't tell you if there's actually anything to read.

And if you read the read manual page you will see that when it returns 0 it means end of file (or connection closed for sockets).

What poll is telling you is that read can be called without blocking, and what read tells you by returning 0 is that there is nothing more to read.

You will get a similar "false positive" by pressing the end-of-file shortcut key (by default Ctrl-D on POSIX systems like Linux) for the non-piped or -redirected input example.

Why poll() returns immediately on regular files and blocks on fifo?

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 of poll() 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.

Why in this case the stdin fd is not ready

Polling works at the file descriptor level while fscanf works at the higher file handle level.

At the higher level, the C runtime library is free to cache the input stream in such a way that it would affect what you can see at the lower level.

For example (and this is probably what's happening here), the first time you fscanf your word aa, the entire line is read from the file descriptor and cached, before that first word is handed back to you.

A subsequent fscanf (with no intervening poll) would first check the cache to get the next word and, if it weren't there, it would go back to the file descriptor to get more input.

Unfortunately, the fact that you're checking for a poll event before doing this is causing problems. As far as the file descriptor level goes, the entire line has been read by your first fscanf so no further input is available - poll will therefore wait until such information does become available.

You can see this in action if you change:

n = fscanf(stdin, "%s", buffer);

into:

n = read(STDIN_FILENO, buffer, 3);

and change the printf to:

printf("data from stdin: %*.*s\n", n, n, buffer);

In that case, you do get the output you expect as soon as you press the ENTER key:

data from stdin: aa
data from stdin: bb
data from stdin: cc
data from stdin: dd

Just keep in mind that sample code is reading up to three characters (like aa<space>) rather than a word. It's more to illustrate what the problem is rather than give you the solution (to match your question "Can you explain why this happens?").

The solution is not to mix descriptor and handle based I/O when the caching of the latter can affect the former.

How can a C program poll for user input while simultaneously performing other actions in a Linux environment?

Your task requires an event loop based on select or epoll. One event it would wait for is user input - when STDIN_FILENO becomes ready for read. Another is the 1-second periodic timer when you need to poll the controller.

There are quite a few libraries that implement an event loop for you so that you can focus on what events you need to handle and how. libevent is one of the oldest, feature rich and popular.



Related Topics



Leave a reply



Submit