Search code examples
clinuxsocketsstdinpolling

How to poll simultaneously from stdin and from sockets?


I wanted to write a C program that would simultaneously wait for data from stdin and from a socket. To achieve this, I wanted to use poll().

But it seems I misunderstood how poll works on stdin... I expected it to behave just like it behaves on sockets, that is: Report POLLIN if and only if I actually typed something in the terminal (and preferably also pressed RETURN).

To test if this assumption is correct, I wrote a simple program that polls only on stdin:

#include <poll.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main()
{
  int ret_poll; ssize_t ret_read;
  struct pollfd input[1] = {{fd: 0, events: POLLIN}};
  char buff[100];
  while(1) {
    ret_poll = poll(input, 1, 0);
    printf("ret_poll:\t%d\nerrno:\t%d\nstrerror:\t%s\n",
        ret_poll, errno, strerror(errno));
    ret_read = read(0, buff, 99);
    printf("ret_read:\t%zd\nerrno:\t%d\nstrerror:\t%s\nbuff:\t%s\n",
        ret_read, errno, strerror(errno), buff);
  }
}

However, I found that in the above example (when I told poll to wait for POLLIN on stdin) poll returns immediately all the time, whether or not I actually type something. Then, of course, the subsequent read() on stdin blocks. So I guess this means I can’t simultaneously wait from input to the terminal and from a socket :(

Is it possible to make poll report POLLIN on stdin only when there actually is data to read?


Solution

  • As it was mentioned above by @Roecrew, poll() returns immediately because you gave 0 timeout. As man page said:

    Note that the timeout interval will be rounded up to the system clock granularity, and kernel scheduling delays mean that the blocking interval may overrun by a small amount. Specifying a negative value in timeout means an infinite timeout. Specifying a timeout of zero causes poll() to return immediately, even if no file descriptors are ready.

    If you change: ret_poll = poll(input, 1, 0); to ret_poll = poll(input, 1, -1); it'll work as you expected.