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: errno handling in nonreentrant syscalls (fwd)


On Fri, 25 May 2001, Dmitry Timoshkov wrote:

> "Joachim Falk" <jfalk@netxpress.de> wrote:
> 
> > there seam to be 3 cases for syscall dispatching in newlib
> 
> [big snip]
> 
> I'm sorry to not answer your question. I asked a similar question
> on the Cygwin mailing list, but unfortunately it seemed that my
> question was leaved unanswered. You can inspect the whole thread
> of questions/answers in the archives of cygwin@cygwin.com mailing
> list (subjects: "__errno_location() like functionality in Cygwin" and
> "oldhand cygwinner needed: RE: __errno_location() like functionality in Cygwin".
> 
> Basically I need to define my own function that will return a pointer
> to my own errno variable. That approach works fine under other Unix OSes,
> but doesn't work with newlib (Cygwin's libc).
> Linux uses for that functionality __errno_location(), FreeBSD - __error(),
> Solaris - ___errno(), UnixWare - __thr_errno().
> 
> Perhaps jointly we could work out a way to bypass that limitation of newlib?
> --
> Dmitry.
> 

Quote from newlib info:
[[[
Reentrancy
**********

Reentrancy is a characteristic of library functions which allows
multiple processes to use the same address space with assurance that the
values stored in those spaces will remain constant between calls.
Cygnus's implementation of the library functions ensures that whenever
possible, these library functions are reentrant.  However, there are
some functions that can not be trivially made reentrant.  Hooks have
been provided to allow you to use these functions in a fully reentrant
fashion.
 
   These hooks use the structure `_reent' defined in `reent.h'.  A
variable defined as `struct _reent' is called a "reentrancy structure".
All functions which must manipulate global information are available in
two versions.  The first version has the usual name, and uses a single
global instance of the reentrancy structure.  The second has a different
name, normally formed by prepending `_' and appending `_r', and takes a
pointer to the particular reentrancy structure to use.
 
   For example, the function `fopen' takes two arguments, FILE and MODE,
and uses the global reentrancy structure.  The function `_fopen_r' takes
the arguments, STRUCT_REENT, which is a pointer to an instance of the
reentrancy structure, FILE and MODE.
 
   Each function which uses the global reentrancy structure uses the
global variable `_impure_ptr', which points to a reentrancy structure.
 
   This means that you have two ways to achieve reentrancy.  Both
require that each thread of execution control initialize a unique global
variable of type `struct _reent':
 
  1. Use the reentrant versions of the library functions, after
     initializing a global reentrancy structure for each process.  Use
     the pointer to this structure as the extra argument for all
     library functions.
 
  2. Ensure that each thread of execution control has a pointer to its
     own unique reentrancy structure in the global variable
]]]

1. newlib has __errno_location() it is is called __errno

cat newlib/libc/include/sys/errno.h
  .
  . [ SNIP ]
  .
  #ifndef _REENT_ONLY
  # define errno (*__errno())
  extern int *__errno _PARAMS ((void));
  #endif
  .
  . [ SNIP ]
  .

cat newlib/libc/errno/errno.c
  .
  . [ SNIP ]
  .
  #ifndef _REENT_ONLY
  int *
  __errno () {
    return &_REENT->_errno;
  }
  #endif
  .
  . [ SNIP ]
  .

cat newlib/libc/include/sys/reent.h
  .
  . [ SNIP ]
  .
  extern struct _reent *_impure_ptr;
  .
  . [ SNIP ]
  .
  #ifndef _REENT_ONLY
  # define _REENT _impure_ptr
  #endif
  .
  . [ SNIP ]
  .

=> If you can get cygwin to have his own copy of 
   struct _reent for each threat and you can
   get _impure_ptr to point to it in the context of
   this threat than your errno will work.

   I don't know If cygwin does this automatically or if you have
   to do it from hand.

   In case not:
   
=> The problem now I believe is to modify
   _impure_ptr accordingly for each threat context switch.
   What you want I believe is a 
   __impure_ptr_location()    

change newlib/libc/include/sys/reent.h to
  #ifndef _REENT_ONLY
  # define _REENT (*__impure_ptr_location())
  extern int *__impure_ptr_location _PARAMS ((void));
  #endif
  
be sure to change
 ./libc/include/stdio.h:#define stdin  (_impure_ptr->_stdin)
 ./libc/include/stdio.h:#define stdout (_impure_ptr->_stdout)
 ./libc/include/stdio.h:#define stderr (_impure_ptr->_stderr)
./libc/reent/reent.c:  if (ptr != _impure_ptr)
to
 ./libc/include/stdio.h:#define stdin (_REENT->_stdin)
 ./libc/include/stdio.h:#define stdout (_REENT->_stdout)
 ./libc/include/stdio.h:#define stderr (_REENT->_stderr)
./libc/reent/reent.c:  if (ptr != _REENT)

Than _impure_ptr will only be referenced with _REENT and this will call
__impure_ptr_location

init a new struct _reent x with 
x = _REENT_INIT(x)
and free it with
_reclaim_reent ( &x )

Than you should be all set
good luck :-)

							MfG
							Joachim Falk


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