Line buffered mode is not set by default

Fernando Ramos bocadillodeatun@gmail.com
Mon Dec 1 13:37:00 GMT 2008


Hello everyone :)

For some reason, "stdout" is set to "full buffered" mode, where
nothing will be output until either

  a) A fflush(stdout) is manually called from the code
  b) The (default) 1024 bytes buffer gets full

What I want is the "line buffered" mode (which should be the default
one, right?)

I've been working on this for a few hours, and I promise I'll keep
investigating in the weekend :) but It would be really nice if you
could help me out.

This is what I have found out so far:

When create a new thread, I init the per thread _reent struct:

  _REENT_INIT_PTR(&(ptcb->reentrant));
   |
   |--> ptcb->reentrant->__sdidinit = 0;

Later, on the OS thread switching routine, I update the global _impure_ptr:

  _impure_ptr = &(new_TCB->reentrant);

 Finally, when I first call "iprintf("Whatever\n");",

iprintf()
|
|-->vfiprintf(stdout)
      |
      |-->CHECK_INIT(stdout)
             |
             |-->(if _impure_ptr->sdidinit == 0)
                       __sinit (_impure_ptr)
                         |
                         |--> s->__sdidinit = 1;
                                ...
                                #ifdef HAVE_FCNTL
                                  std (s->_stdout, __SWR, 1, s);
                                #else
                                   std (s->_stdout, __SWR | __SLBF, 1, s);
                                #endif


Soooo.... I looks like the "line buffered" mode is only set when
"HAVE_FCNTL" is not defined (and it *is* defined in my case). I guess
there must be a good reason for this, but the comment near the above
code is not very explicit (at least not to me :) ). This is what it
says:

  /* on platforms that have true file system I/O, we can verify whether stdout
     is an interactive terminal or not.  For all other platforms, we will
     default to line buffered mode here.  */

What I understand from this is that later, somehow, the libc will call
_fcntl_r() (provided by me) and, depending on the answer, it will
later decide to set (or not) the __SLBF flag.

However, I'm still trying to find where this happens.

A quick "grep" of "__SLBF" on the whole source code reveals that there
are only a bunch of places where the flag is set:

1) From _sinit() (as we have just seen)
2) From setlinebuffer(), which is an exported function only called
from outside the libc.
3) From __smakebuf()

Regarding option number 2, If I manually call "setlinebuffer()" before
the first printf(), it does work (as expected). But the idea is not to
have to do this.

So it's only option number 3 left. In that function the __SLBF flag is
set when "isatty(stdout)" returns true. On my platform (xtensa)
"isatty" is already included in the libc and defined like this:

int
isatty (int fd)
{
  struct stat buf;

  if (fstat (fd, &buf) < 0)
    return 0;
  if (S_ISCHR (buf.st_mode))
    return 1;
  return 0;
}

Which gets to the only function I'm responsible for: _fstat_r()
However I used the recommended minimum implementation, ie:

int _fstat_r(struct _reent *_r, int fd, struct stat *pstat){
  pstat->st_mode = S_IFCHR;
  return 0;
}

And this is where I am right now... not sure what my next step should be :)

Any idea?

Thank you very much.


NOTE: One option could be to NOT define "HAVE_FCNTL", however I'm
working under certain restrains, and one of them is that I am not
allowed to recompile the libc library (ugh!).



More information about the Newlib mailing list