darkpbj
darkpbj

Reputation: 2992

How to see if a pipe is empty

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
}

Upvotes: 14

Views: 37604

Answers (3)

hippiemancam
hippiemancam

Reputation: 121

R..'s answer is good however poll returns the number of file descriptor structs that have flags set in "revents". This will be 1 if you can read from fd but will also be 1 if any of the error flags are set. This means R..'s answer will say the pipe is readable if it ever enters an error state. A more robust check could be something like this:

bool canReadFromPipe(){
    //file descriptor struct to check if POLLIN bit will be set
    //fd is the file descriptor of the pipe
    struct pollfd fds{ .fd = fd, .events = POLLIN };
    //poll with no wait time
    int res = poll(&fds, 1, 0);
    
    //if res < 0 then an error occurred with poll
    //POLLERR is set for some other errors
    //POLLNVAL is set if the pipe is closed
    if(res < 0 || fds.revents & (POLLERR | POLLNVAL))
    {
        //an error occurred, check errno
    }
    return fds.revents & POLLIN;
}

Upvotes: 3

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215387

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.

Upvotes: 15

7heo.tk
7heo.tk

Reputation: 1411

You can check if there is data to be read with the read() function. From read(3):

When attempting to read from an empty pipe or FIFO:

* If some process has the pipe open for writing and
O_NONBLOCK is set, read() shall return -1 and set
errno to [EAGAIN].

* If some process has the pipe open for writing and
O_NONBLOCK  is  clear,  read() shall block the calling
thread until some data is written or the pipe is
closed by all processes that had the pipe open for
writing.

The read() function shall fail if:

EAGAIN or EWOULDBLOCK

    The file descriptor is for a socket, is marked
    O_NONBLOCK, and no data is waiting to be received.

So if you set O_NONBLOCK, you will be able to tell if something is to be read on the pipe, by simply calling read().

As a reminder, from open(3):

SYNOPSIS
    int open(const char *path, int oflag, ...  );

DESCRIPTION
    Values for oflag are constructed by a
    bitwise-inclusive OR of flags from the following
    list, defined in <fcntl.h>. Applications shall
    specify exactly one  of  the first three values
    (file access modes) below in the value of oflag:

    O_NONBLOCK [...]

I hope it helps.

Upvotes: 4

Related Questions