Xref: utzoo comp.unix.questions:30844 comp.lang.c:38827 Path: utzoo!utgpu!news-server.csri.toronto.edu!rpi!zaphod.mps.ohio-state.edu!samsung!uunet!stanford.edu!shap@shasta.Stanford.EDU From: shap@shasta.Stanford.EDU (shap) Newsgroups: comp.unix.questions,comp.lang.c Subject: Re: UNIX commands in C Message-ID: <174@shasta.Stanford.EDU> Date: 29 Apr 91 16:28:50 GMT References: <1991Apr28.153127.24926@jack.sns.com> Organization: Stanford University Computer Systems Laboratory Lines: 73 In article glenn@curie.ces.cwru.edu (Glenn Crocker) writes: > >Check out the popen() function. It allows you to open a pipe to a >specified program and then read from it or write to it just like a >normal file descriptor (FILE *). If you'd like an example program >that uses it, mail me. popen(3) also has an interesting "feature." It is essentially useless unless the program you run from it doesn't read from stdin. Here's why. A typical filter works, logically, on the model read all input process (churn churn) write all output A real UNIX filter, on the other hand, frequently operates on the model read some input process it write result read some more input process it ... So here's what can happen if you aren't careful: 1. Parent program does a popen(3), and happily starts writing to the pipe, assuming that it should dump the whole of the input into the child program. 2. Child program (the filter) processes some input and writes results to it's output (which the parent will eventually read). 3. Pipe buffer on the child output fills, because the parent hasn't done any reads of the results yet. 4. Child blocks, trying to write output to the pipe. 5. Pipe buffer on the child input fills, because the child is no longer reading it. 6. Parent blocks. Et Voilla! instant deadlock. For those of you who don't believe this happens, talk to some people who have had to port various window managers. Now here's the bad news. To work around this limitation, you either have to 1. Know the pipe buffer size and operate accordingly 2. Use asynchronous IO and buffer up the return stuff yourself both of which are machine dependent (buf size clearly, not all machines have asynch I/O). The portable solution is to check how many bytes are writeable to the pipe at any given time and if there aren't enough switch to buffering up the input for a while to allow the child to run. Needless to say, this solution is UGLY. Expert quiz question for the week: write a version of popen(3) that doesn't have this feature. [This problem was first brought to my attention by Mike Bianchi. I think he may have been the author of popen(3).] Jonathan Shapiro