On Thu, 22 Aug 2002 03:53:51 +0900
"Jeff Putsch" <putsch / mxim.com> wrote:

> It seems that select() is claiming file descriptors are ready whether or
> not they are.
> 
> The simple program I'm trying as a test is:

> This does not seem right. First, there is never any data on the error
> object, so why is select saying there is? Second once the end of the
> file is reached, why is select continuing to claim both descriptors
> have data? I'm sure I'm doing something wrong...

I ran into something like the programming in C: it seemed that select
simply didn't work on pipes. 

I was doing this:

	writer -> proc1 -> proc2 -> ... -> procN -> reader

Basically, forking an arbitrary # of procs in a pipeline, and getting
the writer on one end and the reader at the other. I found what I
had to do was make the writer and reader non blocking, use read()
and write() and catch EAGAIN when the operations failed. It looked
like this:

    if (fcntl(reader, F_SETFL, O_NONBLOCK) < 0) 
        exit(fprintf(stderr, "fcntl(reader, F_SETFL, O_NONBLOCK): %s\n", strerror(errno)));

    if (fcntl(writer, F_SETFL, O_NONBLOCK) < 0) 
        exit(fprintf(stderr, "fcntl(reader, F_SETFL, O_NONBLOCK): %s\n", strerror(errno)));

    while (1) {               
	if ((from_stdin_bytes = read(0, to_pipe_buf, BUFSIZE)) < 0)
            exit(fprintf(stderr, "read from stdin %d: (%d) %s\n", 0, errno, strerror(errno)));
	if (to_pipe_bytes == 0)
            break;
         while ((to_pipe_bytes = write(writer, to_pipe_buf, from_stdin_bytes)) < 0) {
            if (errno == EAGAIN) {
                if ((from_pipe_bytes = read(reader, from_pipe_buf, BUFSIZE)) < 0) { 
                    if (errno == EAGAIN) { 
                        continue;
                    } else { 
                        exit(fprintf(stderr, "read from pipe %d: (%d) %s\n", 
			     reader, errno, strerror(errno)));
                    }
                } else { 
                    if (write(1, from_pipe_buf, from_pipe_bytes) < 0) { 
                        exit(fprintf(stderr, "write to stdout: %s\n", strerror(errno)));
                    }
                    continue;
                }
            } else { 
                exit(fprintf(stderr, "write to pipe: %s\n", strerror(errno)));
            }
        }
    }
    close(writer);
    tv.tv_sec = 0;
    tv.tv_usec = 10;
    numreads = 0;
    while (1) {
        if (numreads == MAXREADS) { 
            char *msg = "Error: reached max # reads\n";
            write(2, msg, strlen(msg));
            break;
        }
        numreads++; 
        if ((from_pipe_bytes = read(reader, from_pipe_buf, BUFSIZE)) < 0) { 
            if (errno == EAGAIN) { 
                select(32, NULL, NULL, NULL, &tv); /* pause for 1/100th of a 
						      sec to allow other procs to finish */
                continue;
            } else { 
                exit(fprintf(stderr, "read from pipe %d: (%d) %s\n", reader, errno,
			     strerror(errno)));
            }
        } else if (from_pipe_bytes == 0) { 
            break;
        } else { 
            numreads = 0;
            if (write(1, from_pipe_buf, from_pipe_bytes) < 0) { 
                exit(fprintf(stderr, "write to stdout: %s\n", strerror(errno)));
            }
            continue;
        }
    }

The kicker was the select() in the read loop after the writer had been closed.
I had to add a tiny bit of delay to ensure all the procs in the pipeline
finished.

Anyway, this worked for me -- I'm sure other Unix folks on the list can add
more insight.

Jim