I’m getting blocked at a select() while working with a pipe. The first select() will unblock when we get data on stdin (I just type one letter and press Enter).
Then I write data to the write-end of a pipe, but the select() doesn’t recognize any data on the pipe’s read fd. So it blocks indefinitely.
int fd_pipe[2];
char buf[20];
fd_set set;
pipe(fd_pipe);
FD_ZERO(&set);
FD_SET(fd_pipe[0], &set); // Pipe read fd
FD_SET(0 , &set); // stdin fd
select(fd_pipe[0]+1, &set, NULL, NULL, NULL); // I type 1 char + ENTER to get past this point
if (FD_ISSET(0, &set))
{
read(0, buf, 20); // Can confirm we do get here
write(fd_pipe[1], buf, 1); // Lets put just one character in the pipe
}
select(fd_pipe[0]+1, &set, NULL, NULL, NULL); // <-- We get stuck here
if (FD_ISSET(fd_pipe[0], &set))
{
char d;
read(0, &d, 1);
assert(d == buf[0]);
}
If I do this without select(), things work fine:
int fd_pipe[2];
pipe(fd_pipe);
char c = 'x';
write( fd_pipe[1], &c, 1);
c = 'a';
read( fd_pipe[0], &c, 1);
assert(c == 'x');
In the larger picture, I have a multi-threaded program which is using select() and pipe() to emulate canceling a read() operation. I write to the pipe with a single character with the intent of forcing select() to return so I can shutdown the operation instead of trying to send a signal to cancel a blocking read() on the main FD. But select() doesn’t return.
>Solution :
The select function modifies the sets you pass to it. When select return the sets will contain only the active descriptors.
In your case only STDIN_FILENO will be set, so the second call to select will not have fd_pipe[0] in it.
The solution is actually not to re-add the pipe to the set and call select a second time, but to only call select once:
FD_ZERO(&set);
FD_SET(fd_pipe[0], &set); // Pipe read fd
FD_SET(0 , &set); // stdin fd
select(fd_pipe[0]+1, &set, NULL, NULL, NULL); // I type 1 char + ENTER to get past this point
if (FD_ISSET(0, &set))
{
read(0, buf, 20); // Can confirm we do get here
write(fd_pipe[1], buf, 1); // Lets put just one character in the pipe
}
else if (FD_ISSET(fd_pipe[0], &set))
{
char d;
read(fd_pipe[0], &d, 1);
assert(d == buf[0]);
}
You also need to check what select actually returns. It could return -1 which means there’s an error.
If you do need to call select more than once. Then you’ll need to re-zero/re-set the fd_set.