The reentrancy structure?

J. Johnston
Mon Jul 8 13:22:00 GMT 2002

"H. Peter Anvin" wrote:
> J. Johnston wrote:
> >
> > The reentrancy structure is tightly integrated into newlib.  Can you explain
> > in greater detail what you want to do?  For example, what do you do
> > differently if you find out stdin is linked in vs if it isn't?
> >
> Absolutely.
> My platform doesn't have shared libraries, nor does it have device
> drivers for anything but bulk storage.  Therefore, device drivers have
> to exist in user space.  stdin et al therefore require the presence of
> the console device driver.  For open() I'm relying on magic strings,
> like the following [simplified]:
> extern const struct __device_driver __dev_console;
> #define DEV_CONSOLE ((const char *)__dev_console)
>         fd = open(DEV_CONSOLE, ...);
> ... which means that the reference to __dev_console would pull the
> console device driver into the program.
> However, stdin/stdout/stderr are presumed to be already open, which
> means the device driver for the console.  Since not all programs are
> likely to actually use this functionality, it's a real waste to link
> this code into all programs.  What I was hoping to do was to write a
> module like this:
> FILE *stdin, FILE *stdout, FILE *stderr;
> int __init_stdio(void)
> {
>         stdin = fopen(DEV_CONSOLE, "r");
>         stdout = stderr = fopen(DEV_CONSOLE, "w");
>         return !(stdin && stdout);
> }
> /* Through linker magic, iff this module is linked in, add
>     __init_stdio to the list of functions to be invoked
>     before main() */
> INIT_FUNC(__init_stdio);
> [The linker magic is simply a separate section containing a list of
> pointers to functions to be invoked by crt0.S.]

Alright, now that I know what you want to do, there are a couple of things you
haven't thought of.

First of all, the library routines dealing with default std streams, use
the _r macros - e.g. a getchar() call won't link in your code.

Secondly, you have to deal with the std stream initialization routines in
libc/stdio/findfp.c.  These routines get triggered by the CHECK_INIT macro
which looks at the __sdidinit flag in the reent struct.

What you could do is to create a sys directory for your platform and add
a sys/stdio.h header file.  In it, create a reference to an external integer
(e.g. extern int __io_initialized; ).

Add your own versions of the std stream macros that are identical to the ones
in stdio.h, only they also set __io_initialized to a value.

#define stdin  (__io_initialized = 1, _REENT->_stdin)
#define _stdin_r(x)     (__io_initialized = 1, (x)->_stdin)


Now, the only thing you have to do is skip the current definitions in stdio.h.
Just protect them with a #ifndef __STD_STREAMS_DEFINED__ which you set in
your sys/stdio.h.

The __io_initialized integer is defined in your special code.  You will also want 
to catch a user who might access the std file descriptors
directly (e.g. write (2, "hello world\n", 12); ).  If you can dup2() the
file descriptors, then you are set.  Otherwise, you should use freopen() so that 
the __sdidinit flag is set and then you will have to intercept any base OS calls 
that use the std fds so that they translate to the fds opened at initialization.

-- Jeff J.

More information about the Newlib mailing list