Popen and EVFILT_WRITE question

Mel fbsd.hackers at rachie.is-a-geek.net
Mon Mar 31 12:46:02 PDT 2008

On Monday 31 March 2008 05:49:33 Dag-Erling Smørgrav wrote:
> Mel <fbsd.hackers at rachie.is-a-geek.net> writes:
> > Hi,
> >
> > from reading the manpage on EVFILT_WRITE I thought it would be an easy to
> > use interface to detect when a program wants input.
> > So far, that doesn't seem to be the case. Ultimately what I want to do is
> > pipe all the popen(3)'d output to a logfile and act on any input it
> > wants.
> >
> > Could anyone explain to me why I'm never getting the EVFILT_WRITE event
> > in below testcode?
> > (It doesn't matter if I open the pipe with w+ or r+).
> >
> > test.c:
> > #include <sys/types.h>
> > #include <sys/event.h>
> > #include <sys/time.h>
> > #include <sysexits.h>
> > #include <err.h>
> > #include <stdio.h>
> >
> > int main(int argc, char **argv)
> > {
> > 	FILE *proc;
> > 	int kq;
> > 	struct kevent changes[2], events[2];
> >
> > 	proc = popen("./test.sh", "w+");
> > 	if( -1 == (kq = kqueue()) )
> > 		err(EX_OSERR, "Cannot get a kqueue");
> >
> > 	EV_SET(&changes[0], fileno(proc), EVFILT_WRITE, EV_ADD|EV_ENABLE, 0,
> > 			0, 0);
> > 	EV_SET(&changes[1], fileno(proc), EVFILT_READ, EV_ADD|EV_ENABLE, 0,
> > 			0, 0);
> This is never going to work.
> First, the second kevent overrides the first, because they both have the
> same ident.

No, the ident is one part of the uniqueness. The filter type is the second.

> Third, an EVFILT_WRITE event will trigger as long as there is space in
> the pipe buffer.

> There is no such thing as "when a program wants input" 
> in Unix;

Yeah, I figured that out. Still, the write never fires and that seems like a 
bug to me, cause it should fire since there's space in the buffer. In fact, 
if you fill the buffer partially before going into the event loop, it does 
fire each loop.
Plan was to use trickery like fill the buffer up to PIPE_SIZE and when it's 
drained means the child read the input and we should fill it again.
Then I saw the various pipe sizes and didn't think it would be a good idea, so 
went with a timeout of 'no input received' instead.

> it will either read input or it won't, and what happens when it 
> reads depends entirely on what the fd it reads from is connected to,
> whether it's a slow or fast device, blocking or non-blocking, etc.

The kernel knows that the fd at the end of the pipe is blocked for reading. 
Does it also know it's the end of a pipe and what's on the other end? Cause 
it would be a cool filter to have, if you could detect a blocked child as a 
parent. It sure is better then arbitrary timeouts (this code will run 'make 
install' as a daemon(3) and write 'yes' on those nasty post-install questions 
in ports).


More information about the freebsd-hackers mailing list