Reduce stack usage of _vfiprintf_r()

Freddie Chopin freddie_chopin@op.pl
Wed Oct 10 17:06:00 GMT 2012


Hi!

I'm using newlib on ARM microcontrollers that have limited amount of RAM 
("few" to "few tens" of kilobytes). Due to design of _vfiprintf_r() it's 
almost unusable for such targets, as static function __sbprintf() is 
inlined into it - sbprintf() has a 1kB buffer on stack. This buffer is 
there for optimizing access to unbuffered streams, but my application 
does not use them and 1kB is a tremendous waste of space... If I would 
be using such buffer, there would be a waste of space too, as 
__sbprintf() recursively calls _vfiprintf() which would have a buffered 
"fake" file now, but still allocate 1kB on stack in case it's unbuffered...

I've changed that for myself to use dynamic allocation like this (that's 
from version 1.19.0):

>
> /*
>  * Helper function for `fprintf to unbuffered unix file': creates a
>  * temporary buffer.  We only work on write-only files; this avoids
>  * worries about ungetc buffers and so forth.
>  */
> static int
> _DEFUN(__sbprintf, (rptr, fp, fmt, ap),
>        struct _reent *rptr _AND
>        register FILE *fp   _AND
>        _CONST char *fmt  _AND
>        va_list ap)
> {
> 	int ret;
> 	FILE fake;
> 	unsigned char *buf;
>
> 	/* copy the important variables */
> 	fake._flags = fp->_flags & ~__SNBF;
> 	fake._flags2 = fp->_flags2;
> 	fake._file = fp->_file;
> 	fake._cookie = fp->_cookie;
> 	fake._write = fp->_write;
>
> 	buf = _malloc_r(rptr, BUFSIZ);
>
> 	if (buf == NULL)
> 		return EOF;
>
> 	/* set up the buffer */
> 	fake._bf._base = fake._p = buf;
> 	fake._bf._size = fake._w = BUFSIZ;
> 	fake._lbfsize = 0;	/* not actually used, but Just In Case */
> #ifndef __SINGLE_THREAD__
> 	__lock_init_recursive (fake._lock);
> #endif
>
> 	/* do the work, then copy any error status */
> 	ret = _VFPRINTF_R (rptr, &fake, fmt, ap);
> 	if (ret >= 0 && _fflush_r (rptr, &fake))
> 		ret = EOF;
> 	if (fake._flags & __SERR)
> 		fp->_flags |= __SERR;
>
> 	_free_r(rptr, buf);
>
> #ifndef __SINGLE_THREAD__
> 	__lock_close_recursive (fake._lock);
> #endif
> 	return (ret);
> }

I can provide a patch against current trunk if you think this solution 
is reasonable - I hope you do, because such a waste of stack on small 
microcontrollers is unacceptable...

Regards,
Freddie Chopin



More information about the Newlib mailing list