[comp.unix.questions] Stdio buffer flushing

les@chinet.chi.il.us (Leslie Mikesell) (07/06/90)

Does the putc macro have any strange side effects (such as flushing
an unfilled buffer) under SysV when setbuf is used?  I'm seeing
occasional lines in a logfile that should be:
    line1
    line2
       become:
    line1line2
    blank_line
The relevant code is:  (from smail 3.1, incidentally...)
static char logbuf[BUFSIZ]; /* stdio buffer to avoid mallocs */
fd = open(log_fn, O_CREAT|O_APPEND|O_WRONLY, log_mode);
logfile = fdopen(fd, "a");
(void) setbuf(logfile, logbuf);	/* associate stream and buffer */
	...
(void)vfprintf(logfile, fmt, ap);
putc('\n', logfile);	/* log messages don't come with \n */
(void)fflush(logfile);

Apparently the putc is performing a flush *before* adding the \n, so
that a concurrent process can write it's entry first.  Is this a
bug or are you not supposed to mix different forms of buffered output?

Les Mikesell
  les@chinet.chi.il.us

gwyn@smoke.BRL.MIL (Doug Gwyn) (07/08/90)

In article <1990Jul5.220009.3724@chinet.chi.il.us> les@chinet.chi.il.us (Leslie Mikesell) writes:
>(void)vfprintf(logfile, fmt, ap);
>putc('\n', logfile);	/* log messages don't come with \n */
>(void)fflush(logfile);
>Apparently the putc is performing a flush *before* adding the \n, so
>that a concurrent process can write it's entry first.  Is this a
>bug or are you not supposed to mix different forms of buffered output?

All stdio I/O operations are defined in terms of getc() and putc(),
so clearly "mixing forms" of output is not an issue.  However, there
is no particular guarantee that an output operation will not cause
an actual write() at some point, even if you have setbuf()ed and have
not yet invoked fflush().  Certainly when the buffer is full it will
be automatically flushed.  While I'm not sure why your implementation
of vfprintf() (or less likely, putc()) would flush the buffer where
you say it did, there is no rule that prohibits it from doing so.
The C standard does not require that no extra buffer flushing occur,
although it does suggest that it is not intended.

les@chinet.chi.il.us (Leslie Mikesell) (07/14/90)

In article <13315@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
   >>(void)vfprintf(logfile, fmt, ap);
   >>putc('\n', logfile);	/* log messages don't come with \n */
   >>(void)fflush(logfile);
   >>Apparently the putc is performing a flush *before* adding the \n, so
   >>that a concurrent process can write it's entry first.  Is this a
   >>bug or are you not supposed to mix different forms of buffered output?

>All stdio I/O operations are defined in terms of getc() and putc(),
>so clearly "mixing forms" of output is not an issue.  However, there
>is no particular guarantee that an output operation will not cause
>an actual write() at some point, even if you have setbuf()ed and have
>not yet invoked fflush().  Certainly when the buffer is full it will
>be automatically flushed.  While I'm not sure why your implementation
>of vfprintf() (or less likely, putc()) would flush the buffer where
>you say it did, there is no rule that prohibits it from doing so.
>The C standard does not require that no extra buffer flushing occur,
>although it does suggest that it is not intended.

OK, if it's not a bug it's at least "interesting behaviour" that the
timing of the write() depends on whether or not setbuf() has been
called.  Under SysVr3.2 (3B2 & 386), if setbuf() is called, the
putc('\n',...) above causes a write() of the previous buffered contents
(even though the buffer is not full).  Without setbuf(), it doesn't.
This may only occur the first time putc() is called.

Les Mikesell
  les@chinet.chi.il.us