This is the mail archive of the newlib@sources.redhat.com mailing list for the newlib project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: newlib reentrancy question


"J. Johnston" wrote:
> 
> Joel Sherrill wrote:
> >
> > Where's the best description and/or example of how to
> > implement newlib pre-thread reentrancy support these
> > days?
> >
> > I am investigating a case where cout does not work
> > for the 2nd task in a system unless the 1st task
> > uses it.  All of the standard C routines work fine.
> > In fact, the printf immediately before the cout calls
> > in the 2nd task prints.  The clue I think is that
> > printf does not call fwrite and cout does.  Here
> > is how we do the per-task reentrancy structures
> > now.
> >
> > + At system initialization, we use a global struct _reent.
> >   It is initialized using _REENT_INIT.
> >
> > + Each task has its own copy of the reent structure.
> >
> > + As part of a context switch the contents of _impure_ptr
> > are switched.
> >
> > + As each task begins execution time, the following code
> > is executed:
> >
> >   ptr = (struct _reent *) calloc(1, sizeof(struct _reent));
> >   *ptr = (struct _reent) _REENT_INIT((*ptr));
> >
> > What seems to be happening is that the 2nd task gets to
> > CHECK_INIT:
> >
> > #define CHECK_INIT(fp) \
> >   do                                    \
> >     {                                   \
> >       if ((fp)->_data == 0)             \
> >         (fp)->_data = _REENT;           \
> >       if (!(fp)->_data->__sdidinit)     \
> >         __sinit ((fp)->_data);          \
> >     }                                   \
> >   while (0)
> >
> > and it decides to do the copy in the first if.  But since
> > _REENT_INIT at task_begin time set __sdidinit to 1, it
> > skips the __sinit portion.  Any ideas?  Do you think
> > that our per-task initialization should be different
> > and make sure __sdidinit is 0?
> >
> >
> 
> Please clarify.  The _REENT_INIT macro in newlib/libc/include/sys/reent.h initializes __sdidinit to
> 0.  Have you modified this in your copy?

No.  But I think I have a better description and narrowing of the
problem.  

RTEMS starts with _impure_ptr pointing to libc_global_reent.  
In this application, libc_global_reent is never used.  

libio apparently grabs the stdout pointer from there
at system initialization time and thus never sees any of the
per thread reent data.  So with this sequence of code:

printf uses the per-thread stdout FILE * but cout ends
up using the one from libc_global_reent.  newlib gets
confused because the FILE * passed to fwrite() does not
correspond to the one for the task's reent structure.

I think I am technically out of newlib's domain now but
if anyone has ideas on how to fix this correctly, please 
pass them along.  At this point, I don't know enough
about libio to even know how it is grabbing the FILE *
initially that it plans to use.  

This brings to mind a broader question.  Is RTEMS the
only target switching the reent structure like this?
Should we be doing something different?  

> 
> -- Jeff J.

-- 
Joel Sherrill, Ph.D.             Director of Research & Development
joel@OARcorp.com                 On-Line Applications Research
Ask me about RTEMS: a free RTOS  Huntsville AL 35805
   Support Available             (256) 722-9985


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]