Ad

Check If A `read` Would Return EOF Without Consuming Any Data

- 1 answer

I have a C program that receives data from another program over a (Linux) pipe. I want the program to behave differently if the pipe was closed before writing any data.

The natural way to do this is to try to read from the pipe and check if I get EOF, but that consumes some data from the pipe if there is any available, and (as far as I know) there's no way to put data "back" in a pipe.

The part of the program where I want to check if the pipe is empty is pretty far away from where I process the data, so I'd rather not have to deal with saving the data from my first read until then.

Is there any way to check if a pipe is empty (read would return EOF) without consuming any data in the case it's not empty?

Note: I do want this to block if the pipe has not been written to or closed yet.

Ad

Answer

No, there is no way to do what you describe. The way to determine whether you have reached the end of a non-seekable file such as a pipe is to attempt to read from it. This is not just the natural way, it is the way.

but that consumes some data from the pipe if there is any available,

Yes.

and (as far as I know) there's no way to put data "back" in a pipe.

That depends. If you are reading with POSIX read(), then no. If you are wrapping the the pipe end in a FILE and using stdio functions to read it then there is ungetc().

Nevertheless, this:

The part of the program where I want to check if the pipe is empty is pretty far away from where I process the data

seems like a design problem. You cannot know whether you will ever get data until you actually do get data or see EOF. The process(es) at the write end of the pipe can delay an arbitrary amount of time before doing anything with the pipe, and even if that process is provided by you, you cannot be fully in control of this aspect of its behavior. Thus, it doesn't make much sense to try to check for EOF before you're ready, in some sense, to consume data, because you cannot rely on getting an answer without blocking.

, so I'd rather not have to deal with saving the data from my first read until then.

I suppose you must want to avoid performing some kind of heavyweight initialization in the event that there is no data to process. Ok, but I don't see what the big deal is. You need to provide storage into which to read the data anyway. What's wrong with something like this:

void consume_pipe_data(int fd) {
    char buffer[BUFFER_SIZE];
    ssize_t count;

    count = read(fd, buffer, BUFFER_SIZE);
    if (count == 0) {
        handle_no_data();
        return;
    } else if (count > 0) {
        perform_expensive_initialization();
    }
    do {
        if (count == -1) {
            handle_error();
            return;
        }
        consume_data(buffer);
        count = read(fd, buffer, BUFFER_SIZE);
    } while (count);
}

The point is not that that's necessarily an appropriate structure for your program, but rather that it is possible to structure the program so that storing the data, if any, from the initial read is pretty clean and natural.

Ad
source: stackoverflow.com
Ad