8

I am reading/writing to a pipe created by pipe(pipe_fds). So basically with following code, I am reading from that pipe:

fp = fdopen(pipe_fds[0], "r"); 

And when ever I get something, I print it out by:

while (fgets(buf, 200, fp)) {
    printf("%s", buf);
}

What I want is, when for certain amount of time nothing appears on the pipe to read from, I want to know about it and do:

printf("dummy");

Can this be achieved by select() ? Any pointers on how to do that will be great.

O.C.
  • 6,711
  • 1
  • 25
  • 26
hari
  • 9,439
  • 27
  • 76
  • 110

2 Answers2

12

Let's say you wanted to wait 5 seconds and then if nothing was written to the pipe, you print out "dummy."

fd_set set;
struct timeval timeout;

/* Initialize the file descriptor set. */
FD_ZERO(&set);
FD_SET(pipe_fds[0], &set);

/* Initialize the timeout data structure. */
timeout.tv_sec = 5;
timeout.tv_usec = 0;

/* In the interest of brevity, I'm using the constant FD_SETSIZE, but a more
   efficient implementation would use the highest fd + 1 instead. In your case
   since you only have a single fd, you can replace FD_SETSIZE with
   pipe_fds[0] + 1 thereby limiting the number of fds the system has to
   iterate over. */
int ret = select(FD_SETSIZE, &set, NULL, NULL, &timeout);

// a return value of 0 means that the time expired
// without any acitivity on the file descriptor
if (ret == 0)
{
    printf("dummy");
}
else if (ret < 0)
{
    // error occurred
}
else
{
    // there was activity on the file descripor
}
Eugene S
  • 3,092
  • 18
  • 34
  • 2
    Pretty sure `ret == 0` upon interrupt also. – Aaron D. Marasco Aug 05 '11 at 01:51
  • 5
    Interrupt will cause ``select()`` to return a -1 with ``errno`` set to ``EINTR``. – Eugene S Aug 05 '11 at 01:55
  • 3
    One suggestion to improve your answer: it might be prudent for the OP to use read(2) here, rather than fgets(3). – Joseph Quinsey Aug 05 '11 at 01:59
  • @unluddite: Thanks much for the code snippet. So, in the last `else`, I should do my regular printing (my while (fgets.... loop) because when `ret > 0`, that indicates that I have something to read on file. – hari Aug 05 '11 at 05:58
  • @unluddite: This whole patch of code you pasted needs to be in some sort of loop, right? Also, what should be the termination condition of that loop? What happens when EOF reaches? – hari Aug 05 '11 at 06:07
  • I was just trying to give you some basic groundwork based on your question regarding timed reads. You can certainly put the select statement in a loop (in fact, this is how nearly all event-based applications work). The termination condition would be whatever is required by your program (e.g., the pipe is closed, some special code is read from the pipe, etc). It really depends on what you're trying to accomplish. – Eugene S Aug 05 '11 at 13:10
  • A nit pick because I am sure you were trying to minimize the example code size but using FD_SETSIZE in the select shouldn't be encouraged. – Duck Aug 05 '11 at 15:08
  • @unluddite: Thanks a lot for the detailed answer. I have one last question: What does it mean when we say `pipe_fds[0] + 1` for the first arg? I only want `select` to observe `pipe_fds[0]` and nothing else then why `+ 1`? What purpose does that serve? – hari Aug 05 '11 at 16:46
  • 1
    Because ``fd_set`` is a fixed-size array (of size ``FD_SETSIZE``). It has a slot for all the possible values that a file descriptor can have (up to 1024 on most systems). When you call ``FD_SET``, it uses the file descriptor number to index into the array. From the documentation: "The ``select()`` function tests file descriptors in the range of ``0`` to ``nfds-1``" so we need to add 1 to make sure our file descriptor is within the range. – Eugene S Aug 05 '11 at 17:40
  • Awesome. Thanks a bunch. I wish I could give you more than 1 voteup :D – hari Aug 05 '11 at 17:41
  • I've a related que that I just posted: http://stackoverflow.com/questions/6962150/catching-signals-while-reading-from-pipe-with-select – hari Aug 05 '11 at 20:20
0

IIRC, select has a timeout that you then check with FD_ISSET to tell if it was I/O or not that returned.

Aaron D. Marasco
  • 6,506
  • 3
  • 26
  • 39