Use thread-local storage for Newlib reentrancy objects
Original author: sebastian.huber
Problem
The state of the art architectures supported by RTEMS have all efficient support for thread-local storage (MIPS has issues with thread-local storage, however, is MIPS state of the art?).
Newlib currently uses a huge object of type struct _reent
to store thread-specific data. This object is returned by __getreent()
. It is related to the __DYNAMIC_REENT__
Newlib configuration option which is always defined for RTEMS.
The reentrancy structure contains errno
and also the standard input, output, and error file streams. This means that if an application only uses errno
it has a dependency on the file stream support event if it does not use it. This is an issue for lower end targets and the pre-qualification of RTEMS.
Solution
One approach to disentangle the dependencies introduced by struct _reent
is to get rid of this structure and replace the individual members of the structure with thread-local objects. For example, instead of
struct _reent {
int _errno;
__FILE *_stdin;
__FILE *_stdout;
__FILE *_stderr;
};
use
_Thread_local int _errno;
_Thread_local __FILE *_stdin;
_Thread_local __FILE *_stdout;
_Thread_local __FILE *_stderr;
Newlib already has access macros for the struct _reent
members, for example:
#define _REENT_SIGNGAM(ptr) ((ptr)->_new._reent._gamma_signgam)
#define _REENT_RAND_NEXT(ptr) ((ptr)->_new._reent._rand_next)
#define _REENT_RAND48_SEED(ptr) ((ptr)->_new._reent._r48._seed)
#define _REENT_RAND48_MULT(ptr) ((ptr)->_new._reent._r48._mult)
#define _REENT_RAND48_ADD(ptr) ((ptr)->_new._reent._r48._add)
How-to Implement
The member access macros are incomplete. The first step is to use the Newlib configuration for RTEMS as is and rename all struct _reent
members, for example add an TEMPORARY
prefix to all member names, _errno
to TEMPORARY_errno
. Then add member access macros until Newlib builds again. Install this Newlib and check that RTEMS and libbsd compiles. Run the RTEMS and libbsd test suites to check for regressions.
In a second step to this for the _REENT_SMALL
configuration of Newlib.
The third step is to add a new Newlib configuration option, for example _REENT_THREAD_LOCAL
which turns the struct _reent
members into thread-local objects with corresponding "member" access macros. Define _REENT
to NULL
.
Skills
C and assembly
Difficulty
This is a large (350-hour) project of hard difficulty.