chris@mimsy.umd.edu (Chris Torek) (02/04/90)
This has little to do with C per se, and belongs in comp.unix.questions. In article <273@ndla.UUCP> platt@ndla.UUCP (Daniel E. Platt) writes: >I have a question about what happens to the buffering of stdio >when stdio is re-directed via a dup() from a pipe()'ed file >descriptor before exec'ing. exec() throws away the current program, *including all information stdio has ever built up*. (Some people attempt to shut off buffering by adding a `setbuf(stdout, (char *)NULL)' call before the exec. This cannot work, because exec() throws out that information.) >In the [child program with stdin & stdout being a pipe], if I have >something like: > > while(scanf("%d", &i) == 1) > printf("%d", i * i); > >without first calling: > > setbuf(stdin, NULL); > setbuf(stdout, NULL); (Unless you have a machine that uses function prototypes, these should be `setbuf(stdin, (char *)NULL)' and `setbuf(stdout, (char *)NULL)'.) >what happens is the parent hangs. It would appear that the child won't >write its buffer until it fills it up... just like it was writing to >a disk. In some versions of Unix, a pipe *is* a disk file. (In others it is a `stream' or a `socket'; but in most if not all Unix systems, a pipe is not a `tty' device.) Stdio believe in buffering: with the exception of `tty' devices, all output is buffered in large chunks. On `tty's (whatever those are: in 4BSD, a tty is a device that allows ioctl(TIOCGETP)), stdio buffers output only to a newline (or a `large chunk', whichever comes first). >However, with the setbuf()'s present, there is no hangup. I assume >that it knows to create the buffer when it determines that it has been >re-directed. The child is a completely new program. The first time it tries to do something with stdio, it decides that it should buffer stdout. If stdout is a `tty', stdio buffers it up to newlines; otherwise stdio buffers it fully. >However, doesn't it know that it was redirected from >a pipe as opposed to being re-directed to or from a disk file? Stdio cares not in the least about anything except `tty' devices. >If I'm trying to do this to a program for which I only have the binary, >and which uses stdio buffered, is there a way to fool it into not using >a buffer? Such a program is, as far I am concerned, buggy. Programs that interact, but depend on `tty' style buffering, are in need of repair. ANY program that intends to interact---whether with a person or another program---should, if it uses stdio, use fflush() before each input request to make sure that its output goes out. I think it was a mistake to add line-buffering to stdio at all: convenient perhaps, but a mistake, for it voids the model `everything is a byte stream file'. Programs that cheat---that call setbuf to disable all buffering---are not so broken, but are performance disasters. The right solution is to put fflush calls into the offending program. Of course, this is sometimes not possible. If all else fails, the last trick is to run the program after connecting its stdout to what the program will think *is* a `tty'. Most modern Unix systems have `pseudo terminals' that can be used for this purpose. In extreme situations, you can connect a real terminal port back to a second terminal port, and make the machine talk to itself over a serial line. (This particular kludge is something you would expect of an IBM O/S, not of Unix.) -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163) Domain: chris@cs.umd.edu Path: uunet!mimsy!chris