This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
Line buffered mode is not set by default
- From: "Fernando Ramos" <bocadillodeatun at gmail dot com>
- To: newlib at sourceware dot org
- Date: Fri, 28 Nov 2008 18:51:05 +0100
- Subject: Line buffered mode is not set by default
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!).