Assuming a pipe,
int pipe_fd[2];
pipe(pipe_fd);
We fork, and expect that one process will write into the pipe at an arbitrary time. In one of the processes, we want to be able to check the contents of the pipe without blocking.
i.e. While a typical read will block if nothing is present and the write end remains open. I want to go do other stuff and potentially even read a bit at a time, do some stuff, and then check back to see if there's more, a la:
close(pipe_fd[1]);
while(1){
if(/**Check pipe contents**/){
int present_chars = 0;
while( read(pipe_fd[0],&buffer[present_chars],1) != 0)
++present_chars;
//do something
}
else
//do something else
}
When a user process attempts to read from an empty pipe (or FIFO), the following happens: If one end of the pipe is closed, 0 is returned, indicating the end of the file. If the write side of the FIFO has closed, read(2) returns 0 to indicate the end of the file.
The first element of the pipefd array, pipefd[0] is used for reading data from the pipe. The second element of the pipefd array, pipefd[1] is used for writing data to the pipe. On success, the pipe() function returns 0. If an error occurs during pipe initialization, then the pipe() function returns -1.
If there is nothing in the pipe (or queue), nothing is read. When other process writes to pipe, you can read it on read side. So it is perfectly valid to read empty pipe (you will read 0 entries). The behavior is described in the relevant man page.
Your logic is wrong in that read
will not return 0 when it runs out of characters; instead, it will block until it receives more, unless you put the file in non-blocking mode, but then it will return -1 and set errno
to EWOULDBLOCK
or EAGAIN
rather than returning 0. The only time read
can ever return 0 is when the size argument was 0 or end-of-file has been reached. And, for pipes, end-of-file means the writing end of the pipe has been closed; end-of-file status does not occur just because there's not any input available yet.
With that said, the simplest way to check is:
if (poll(&(struct pollfd){ .fd = fd, .events = POLLIN }, 1, 0)==1) {
/* data available */
}
but unless you're using nonblocking mode, you'll need to make this check before every single read operation. Passing a larger buffer to read
rather than doing it a byte-at-a-time would eliminate most of the cost of checking.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With