dup()'ed pipe()'s to stdio

Chris Torek chris at mimsy.umd.edu
Sun Feb 4 07:04:06 AEST 1990


This has little to do with C per se, and belongs in comp.unix.questions.

In article <273 at ndla.UUCP> platt at 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 at cs.umd.edu	Path:	uunet!mimsy!chris



More information about the Comp.unix.questions mailing list