Question

The program below works well under OS X but not in linux. It continues to loop through the perror("read error") line, with no bytes in the read buffer, and EWOULDBLOCK isn't the errno (errno=0);

In OS X the program works as expected, which is that it reads from three named pipes, and prints any data from any of them to the console.

        #include <sys/types.h>
        #include <sys/select.h>
        #include <sys/time.h>
        #include <sys/types.h>
        #include <errno.h>
        #include <stdlib.h>
        #include <stdio.h>
        #include <fcntl.h>
        #include <unistd.h>


        int readPipe(int fd)
        {
            ssize_t bytes;
            size_t total_bytes = 0;
            char buffer[100*1024];

            printf("\nReading pipe descriptor # %d\n",fd);
            for(;;) {
                bytes = read(fd, buffer, sizeof(buffer));
                if (bytes > 0) {
                    total_bytes += (size_t)bytes;
                    printf("%s", buffer);
                } 
                else {
                    if (errno == EWOULDBLOCK) {
                        break; // recieve buffer is empty so return to main loop
                    } 
                    else {
                        perror("read error"); 
                        return EXIT_FAILURE;
                    }
                }
            }
            return EXIT_SUCCESS;
        }


        int main(int argc, char* argv[])
        {
            int fd_a, fd_b, fd_c;   // file descriptors for each pipe
            int nfd;                // select() return value
            fd_set read_fds;        // file descriptor read flags
            struct timeval tv;
            tv.tv_sec = 0;
            tv.tv_usec = 10000;

            // create pipes to monitor (if they don't already exist)
            system("mkfifo /tmp/PIPE_A");
            system("mkfifo /tmp/PIPE_B");
            system("mkfifo /tmp/PIPE_C");
            system("chmod 666 /tmp/PIPE_*");

            // open file descriptors of named pipes to watch
            fd_a = open("/tmp/PIPE_A", O_RDONLY | O_NONBLOCK); // the O_RDWR flag is undefined on a FIFO.
            if (fd_a == -1) {
                perror("open error");
                return EXIT_FAILURE;
            }

            fd_b = open("/tmp/PIPE_B", O_RDONLY | O_NONBLOCK);
            if (fd_b == -1) {
                perror("open error");
                return EXIT_FAILURE;
            }

            fd_c = open("/tmp/PIPE_C", O_RDONLY | O_NONBLOCK);
            if (fd_c == -1) {
                perror("open error");
                return EXIT_FAILURE;
            }

            // check for new data in each of the pipes
            for(;;)
            {
                // clear fds read flags
                FD_ZERO(&read_fds);

                // PIPE_A
                FD_SET(fd_a, &read_fds);
                nfd = select(fd_a+1, &read_fds, NULL, NULL, &tv);
                if (nfd != 0) {
                    if (nfd == -1) {
                        perror("select error");
                        return EXIT_FAILURE;
                    }
                    if (FD_ISSET(fd_a, &read_fds)) {
                        readPipe(fd_a);
                    }
                }

                // PIPE_B
                FD_SET(fd_b, &read_fds);
                nfd = select(fd_b+1, &read_fds, NULL, NULL, &tv);
                if (nfd != 0) {
                    if (nfd == -1) {
                        perror("select error");
                        return EXIT_FAILURE;
                    }
                    if (FD_ISSET(fd_b, &read_fds)){
                        readPipe(fd_b);
                    }
                }

                // PIPE_C
                FD_SET(fd_c, &read_fds);
                nfd = select(fd_c+1, &read_fds, NULL, NULL, &tv);
                if (nfd != 0) {
                    if (nfd == -1) {
                        perror("select error");
                        return EXIT_FAILURE;
                    }
                    if (FD_ISSET(fd_c, &read_fds)){
                        readPipe(fd_c);
                    }
                }
            }
            return EXIT_SUCCESS;
        }
Was it helpful?

Solution

It is allowable (and expected) that read can return 0. This means the pipe is returning EOF. You are not handling this condition. The contents of errno are irrelevant unless the call fails and returns -1.

for (;;)
{
    bytes = read(fd, buffer, sizeof(buffer));

    if (bytes > 0)
    {
        total_bytes += (size_t)bytes;
        printf("%s", buffer);
    }

    if (bytes == 0)
        return //something appropriate

    if (bytes == -1)
    {
        if (errno == EWOULDBLOCK)
           break; // recieve buffer is empty so return to main loop
        else
        {
            perror("read error");
            return EXIT_FAILURE;
        }
    }
}

You are going through the effort to return different codes but you don't pay any attention to them in main.

Also, what's with the 3 select statements again? I thought that was cleared up in a previous question.

Edit

for (;;)
{
    // clear fds read flags
    FD_ZERO(&read_fds);
    FD_SET(fd_a, &read_fds);
    FD_SET(fd_b, &read_fds);
    FD_SET(fd_c, &read_fds);

    tv.tv_sec = 0;
    tv.tv_usec = 10000;

    nfd = select(fd_c + 1, &read_fds, NULL, NULL, &tv);

    if (nfd == 0) //timeout - continue or do something else for a bit
        continue;

    if (nfd == -1)
    {
        perror("select error");
        return EXIT_FAILURE;
    }

    if (FD_ISSET(fd_a, &read_fds))
        readPipe(fd_a);

    if (FD_ISSET(fd_b, &read_fds))
        readPipe(fd_b);

    if (FD_ISSET(fd_c, &read_fds))
        readPipe(fd_c);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top