mailing list of musl libc
 help / color / mirror / code / Atom feed
From: Rich Felker <dalias@libc.org>
To: musl@lists.openwall.com
Subject: Re: Enforcing expected ordering of operations on stdout, stdin, and stderr
Date: Wed, 10 Feb 2016 18:39:01 -0500	[thread overview]
Message-ID: <20160210233900.GG9349@brightrain.aerifal.cx> (raw)
In-Reply-To: <CAD+Cw=cVbgEUz_VETZL9-rOP+aaDxGqW0CGAbKYi+cbpq9GwhA@mail.gmail.com>

On Wed, Feb 10, 2016 at 06:08:47PM -0500, Max Ruttenberg wrote:
> >
> > fflush(stdout);
> > This is more of a basic C thing than a libc ml thing. You should
> > consider picking up a copy of The C Programming Language by Kernighan
> > and Ritchie. It will explain all of this.
> 
> 
> I know about fflush, thanks.
> 
> Consider this program:
> 
> int main()
> {
>    char buff[2];
>    puts("enter a character");
>    buff[0] = getchar();
>    buff[1] = '\0';
>    puts(buff);
>    return 0;
> }
> 
> If I compile that on linux-amd64, with or without musl, I will see "enter a
> character" printed to my console and then be prompted for a character, as
> opposed to the other way around. I don't know if this is formally
> guaranteed by the C standard, but somehow that order seems to be
> maintained.
> 
> But if I grep the source code in musl/src/stdio for "fflush" I don't see a
> bunch of calls to fflush. I see a call to it in fclose and freopen... but
> that's neither surprising nor helpful. If I do the same in
> musl/src/internal I also don't get anything. I've even tried just greping
> for "flush."
> 
> And yet somehow the order is maintained within those calls to puts and
> getchar. So what I'm asking is: how? What part of the internal musl source
> even attempts to enforce that ordering? I know the calling application can
> do it with calls to fflush, but somehow that doesn't seem to be necessary
> short of a signal interrupting the expected flow of execution. Am I just
> getting lucky 100% of the time or is there some source in the stdio library
> that's enforcing this?

When attached to a terminal ("interactive device" in the terminology
of the C standard), stdout is line-buffered by default. This means
that writing a newline, which puts() inherently does at the end of its
output, causes output to be flushed. The code path from puts.c is via
the macro form of putc_unlocked, which is defined in
src/internal/stdio_impl.h, and bypasses the fast write-to-buffer code
path when c==f->lbf (f->lbf is set to '\n' for line-buffered mode, -1
for other modes). Actually even if stdout were not a terminal you
would _happen_ to see this behavior on musl because whether stdout is
line-buffered is decided lazily at the first encounter of '\n', so the
"first line of output" is always line-buffered. But this is an
implementation detail and not something you should rely on. If you
want line-buffered behavior even for non-interactive stdout, you need
to call setvbuf (as the first action on the file).

Also, ISO C permitted and even encouraged (but made optional) a
behavior whereby attempting to read from a line-buffered input stream
causes all line-buffered output streams to be flushed. While this is
convenient for programmers who write prompt strings not ending in
newlines, and who don't want to be bothered with calling fflush, this
feature was conceived in an era where C did not have multi-threading,
and providing it when you have threads imposes a heavy synchronization
burden and can even lead to deadlock. Therefore musl does not do it.
So if you want to print prompt strings that don't end in a newline,
and have them appear before input is read, you have to use fflush
yourself.

Does this help?

Rich


  parent reply	other threads:[~2016-02-10 23:39 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-10 21:49 Max Ruttenberg
2016-02-10 22:05 ` Joakim Sindholt
2016-02-10 23:08   ` Max Ruttenberg
2016-02-10 23:22     ` Szabolcs Nagy
2016-02-10 23:39     ` Rich Felker [this message]
2016-02-11  1:17       ` Max Ruttenberg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20160210233900.GG9349@brightrain.aerifal.cx \
    --to=dalias@libc.org \
    --cc=musl@lists.openwall.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/musl/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).