The reentrancy structure?
J. Johnston
jjohnstn@redhat.com
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