Why is a named pipe selection without any writers blocked indefinitely?

I am calling select with one named pipe fd in read_fds. This named pipe has no writers and is open only in non-blocking read-only mode. I would expect the selection to return with the named pipe fd marked ready to read, and that trying to read from the pipe returns 0:

From the man page in read mode:

When trying to read from an empty pipe or FIFO:

  • If no process has a pipe open for writing, read () should return 0 at> end of file.

However, select only blocks indefinitely. Why is this so?

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>

#include <stdexcept>
#include <thread>
#include <iostream>

int main()
{
    char buf[4096];

    // Create a named pipe
    auto err = mkfifo("/tmp/whatever",0666);
    if(err) {
        throw std::runtime_error(
                    std::string("Failed to create fifo ")+
                    strerror(errno));
    }

    std::thread reader_thread(
                [&](){
        auto fd = open("/tmp/whatever",O_RDONLY|O_NONBLOCK);
        if(fd < 0) {
            throw std::runtime_error("Failed to open fifo");
        }

        fd_set fds;
        while(1) {
            FD_ZERO(&fds);
            FD_SET(fd,&fds);
            std::cerr << "calling select" << std::endl;
            auto retval = select(fd+1,&fds,nullptr,nullptr,nullptr);
            if(retval < 0) {
                std::runtime_error("Failed to call select");
            }

            if(FD_ISSET(fd,&fds)) {
                auto read_bytes = read(fd,buf,4096);
                std::cerr << "read " << read_bytes << std::endl;
                if(read_bytes==0) {
                    break;
                }
            }
        }

        close(fd);
    });

    reader_thread.join();

    return 0;
}

      

+3


source to share


1 answer


In the POSIX fo documentation select

:

A descriptor is considered read ready for reading when a call to the input function with O_NONBLOCK clearing will not block, regardless of whether the function successfully transfers data. (The function may return data, an end-of-file indication, or an error other than one indicating that it is locked, and in each of these cases, the descriptor is considered read ready for reading.

...

If none of the selected descriptors are ready for the requested operation, the pselect () or select () function should block until at least one of the requested operations is ready , until a timeout occurs, or until it is interrupted by a signal ...

From the pipe(7)

manpage (which is the underlying FIFO object):

If all file descriptors referring to the end of the pipe record have been closed , then trying to read (2) from the pipe will see the end of the file (read (2) will return 0).



Remember to use the present perfect tense! This means the FIFO must be open on both sides of the fiorst , closed on the write side (for your application) to create the condition EOF

.

So, if phyto is not closed by the writer, why go select

back? The parameter to the (fifo) file itself is irrelevant for a good reason: it will introduce a race condition between opening on both sides when using the most efficient method to read more than one byte at a time. This is the usual way, for example a command pipe: start the read process and start the write (which is usually a completely unrelated program when using a named pipe).

If you want to select

return earlier, use an argument timeout

. But usually a separate thread is used, which can be interrupted by a signal (see the Man-page for more details select

).

As a side note: One good thing about Linux / POSIX is that it doesn't really matter if you use a FIFO or a file or your microphone driver.

+4


source







All Articles