using select() with pipe
Asked Answered
D

2

9

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.

Drinkwater answered 5/8, 2011 at 1:33 Comment(0)
H
14

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
}
Hilly answered 5/8, 2011 at 1:49 Comment(11)
Pretty sure ret == 0 upon interrupt also.Bloomfield
Interrupt will cause select() to return a -1 with errno set to EINTR.Hilly
One suggestion to improve your answer: it might be prudent for the OP to use read(2) here, rather than fgets(3).Morpheus
@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.Drinkwater
@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?Drinkwater
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.Hilly
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.Kaveri
@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?Drinkwater
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.Hilly
Awesome. Thanks a bunch. I wish I could give you more than 1 voteup :DDrinkwater
I've a related que that I just posted: #6962650Drinkwater
B
0

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

Bloomfield answered 5/8, 2011 at 1:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.