Subject: read() and select()
To: None <tech-userlevel@netbsd.org>
From: Michael Cuddy <mcuddy@fensende.com>
List: tech-userlevel
Date: 11/17/2000 12:58:43
I'm not sure this is the right location for this query, but here goes...

I have a process which fork()/exec()'s a child, passing it a pipe to 
use for stdout/stderr, and holding on to the other end of the pipe.

When the child runs, I alternately waitpid(WNOHANG) for the process and
select() for output on the pipe.  If I get any output on the pipe,
I fork()/exec() another process, passing it the read end of the pipe as 
stdin.

The problem is that select() is returning that the read-side fd is ready
for reading, when the process exits (closing the write side) -- but a read()
will return 0.  

Is there any way to detect the difference between the child exiting and there
actually being data to read?

My current solution is to eat one byte of the input with read(fd,&c,1), 
but I'd rather not lose the byte of output (and I'd rather not sit and
direct traffic down the pipe through another pair of FD's)

Here's some pseudo code ...

    int fds[3];
    int pfd[2];

    pipe(pfd);

    fds[0] = 0;
    fds[1] = fds[2] = pfd[1];

    if ((pid = fork())==0) {
        if (fds[0] != 0) dup2(_fds[0],0);
        if (fds[1] != 1) dup2(_fds[1],1);
        if (fds[2] != 2) dup2(_fds[2],2);
        execv( ... script, if in which there's an error will output data ... )
    }
    close(pfd[1]);      // close writer side

    while (!done) {
        FD_ZERO(&rd);
        FD_SET(pfd[0],&rd);
        tv.tv_sec = 0; tv.tv_usec = 250000;

        n = select(pfd[0]+1, &rd, NULL, NULL, &tv);

        if (n > 0) {
            if (FD_ISSET(pfd[0],&rd)) {
                // ... fork/exec alarm script with pfd[0] connected to stdin.
            }
        }
    }
--
Mike Cuddy (mcuddy@FensEnde.com, MC312), Programmer, Daddy, Human.
Fen's Ende Software, Redwood City, CA, USA, Earth, Sol System, Milky Way.
I remember asking why ... Let it rain, and protect us from this Cruel Sun.

       Join CAUCE: The Coalition Against Unsolicited Commercial E-mail.
                          <http://www.cauce.org/>