Add --enable-newlib-reent-thread-local option

By default, Newlib uses a huge object of type struct _reent to store
thread-specific data.  This object is returned by __getreent() if the
__DYNAMIC_REENT__ Newlib configuration option is defined.

The reentrancy structure contains for example errno and 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 even if it does not use
it.  This is an issue for lower end targets and applications which need to
qualify the software according to safety standards (for example ECSS-E-ST-40C,
ECSS-Q-ST-80C, IEC 61508, ISO 26262, DO-178, DO-330, DO-333).

If the new _REENT_THREAD_LOCAL configuration option is enabled, then struct
_reent is replaced by dedicated thread-local objects for each struct _reent
member.  The thread-local objects are defined in translation units which use
the corresponding object.
This commit is contained in:
Matt Joyce 2022-05-16 11:51:54 +02:00 committed by Sebastian Huber
parent 1a09082036
commit ea99f21ce6
33 changed files with 267 additions and 0 deletions

View File

@ -304,6 +304,14 @@ One feature can be enabled by specifying `--enable-FEATURE=yes' or
layout.
Disabled by default.
`--enable-newlib-reent-thread-local'
Enable thread-local storage objects as a replacement for struct _reent
members. If enabled, then struct _reent is not defined and dedicated
thread-local storage objects are provided for each member of the default
struct _reent. For statically linked executables only the objects
required by the application are linked in.
Disabled by default.
`--disable-newlib-fvwrite-in-streamio'
NEWLIB implements the vector buffer mechanism to support stream IO
buffering required by C standard. This feature is possibly

21
newlib/configure vendored
View File

@ -973,6 +973,7 @@ enable_newlib_atexit_dynamic_alloc
enable_newlib_global_atexit
enable_newlib_reent_small
enable_newlib_reent_binary_compat
enable_newlib_reent_thread_local
enable_newlib_global_stdio_streams
enable_newlib_fvwrite_in_streamio
enable_newlib_fseek_optimization
@ -1641,6 +1642,7 @@ Optional Features:
--enable-newlib-global-atexit enable atexit data structure as global
--enable-newlib-reent-small enable small reentrant struct support
--enable-newlib-reent-binary-compat enable backward binary compatibility for struct _reent
--enable-newlib-reent-thread-local enable thread-local storage objects as a replacment for struct _reent members
--enable-newlib-global-stdio-streams enable global stdio streams
--disable-newlib-fvwrite-in-streamio disable iov in streamio
--disable-newlib-fseek-optimization disable fseek optimization
@ -2404,6 +2406,19 @@ else
newlib_reent_binary_compat=no
fi
# Check whether --enable-newlib-reent-thread-local was given.
if test "${enable_newlib_reent_thread_local+set}" = set; then :
enableval=$enable_newlib_reent_thread_local; if test "${newlib_reent_thread_local+set}" != set; then
case "${enableval}" in
yes) newlib_reent_thread_local=yes ;;
no) newlib_reent_thread_local=no ;;
*) as_fn_error $? "bad value ${enableval} for newlib-enable-reent-thread-local option" "$LINENO" 5 ;;
esac
fi
else
newlib_reent_thread_local=no
fi
# Check whether --enable-newlib-global-stdio-streams was given.
if test "${enable_newlib_global_stdio_streams+set}" = set; then :
enableval=$enable_newlib_global_stdio_streams; case "${enableval}" in
@ -6437,6 +6452,12 @@ $as_echo "#define _WANT_REENT_BACKWARD_BINARY_COMPAT 1" >>confdefs.h
fi
if test "${newlib_reent_thread_local}" = "yes"; then
$as_echo "#define _WANT_REENT_THREAD_LOCAL 1" >>confdefs.h
fi
_mb_len_max=1
if test "${newlib_mb}" = "yes"; then

View File

@ -173,6 +173,17 @@ AC_ARG_ENABLE(newlib-reent-binary-compat,
esac
fi], [newlib_reent_binary_compat=no])dnl
dnl Support --enable-newlib-reent-thread-local
AC_ARG_ENABLE(newlib-reent-thread-local,
[ --enable-newlib-reent-thread-local enable thread-local storage objects as a replacment for struct _reent members],
[if test "${newlib_reent_thread_local+set}" != set; then
case "${enableval}" in
yes) newlib_reent_thread_local=yes ;;
no) newlib_reent_thread_local=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for newlib-enable-reent-thread-local option) ;;
esac
fi], [newlib_reent_thread_local=no])dnl
dnl Support --enable-newlib-global-stdio-streams
dnl This is no longer optional. It is enabled in all Newlib configurations.
AC_ARG_ENABLE(newlib-global-stdio-streams,
@ -435,6 +446,10 @@ if test "${newlib_reent_binary_compat}" = "yes"; then
AC_DEFINE(_WANT_REENT_BACKWARD_BINARY_COMPAT, 1, [Define to enable backward binary compatibility for struct _reent.])
fi
if test "${newlib_reent_thread_local}" = "yes"; then
AC_DEFINE(_WANT_REENT_THREAD_LOCAL, 1, [Define to enable thread-local storage objects as a replacment for struct _reent members.])
fi
_mb_len_max=1
if test "${newlib_mb}" = "yes"; then
AC_DEFINE(_MB_CAPABLE, 1, [Multibyte supported.])

View File

@ -5,6 +5,10 @@
#include <errno.h>
#include <reent.h>
#ifdef _REENT_THREAD_LOCAL
_Thread_local int _tls_errno;
#else /* !_REENT_THREAD_LOCAL */
#ifndef _REENT_ONLY
int *
@ -14,3 +18,5 @@ __errno ()
}
#endif
#endif /* _REENT_THREAD_LOCAL */

View File

@ -297,6 +297,12 @@
#endif
#endif
#ifdef _WANT_REENT_THREAD_LOCAL
#ifndef _REENT_THREAD_LOCAL
#define _REENT_THREAD_LOCAL
#endif
#endif
/* If _MB_EXTENDED_CHARSETS_ALL is set, we want all of the extended
charsets. The extended charsets add a few functions and a couple
of tables of a few K each. */

View File

@ -10,11 +10,17 @@ extern "C" {
#include <sys/reent.h>
#ifdef _REENT_THREAD_LOCAL
#define errno (_tls_errno)
#else /* _REENT_THREAD_LOCAL */
#ifndef _REENT_ONLY
#define errno (*__errno())
extern int *__errno (void);
#endif
#endif /* _REENT_THREAD_LOCAL */
/* Please don't use these variables directly.
Use strerror instead. */
extern __IMPORT const char * const _sys_errlist[];

View File

@ -301,6 +301,8 @@ struct _rand48 {
#define _REENT_ASCTIME_SIZE 26
#define _REENT_SIGNAL_SIZE 24
#ifndef _REENT_THREAD_LOCAL
#ifdef _REENT_BACKWARD_BINARY_COMPAT
#define _REENT_INIT_RESERVED_0 0,
#define _REENT_INIT_RESERVED_1 0,
@ -767,6 +769,96 @@ extern struct _reent _impure_data __ATTRIBUTE_IMPURE_DATA__;
#define _GLOBAL_REENT (&_impure_data)
#else /* _REENT_THREAD_LOCAL */
#define _REENT NULL
#define _GLOBAL_REENT NULL
/*
* Since _REENT is defined as NULL, this macro ensures that calls to
* CHECK_INIT() do not automatically fail.
*/
#define _REENT_IS_NULL(_ptr) 0
#define _REENT_CHECK_RAND48(ptr) /* nothing */
#define _REENT_CHECK_MP(ptr) /* nothing */
#define _REENT_CHECK_TM(ptr) /* nothing */
#define _REENT_CHECK_ASCTIME_BUF(ptr) /* nothing */
#define _REENT_CHECK_EMERGENCY(ptr) /* nothing */
#define _REENT_CHECK_MISC(ptr) /* nothing */
#define _REENT_CHECK_SIGNAL_BUF(ptr) /* nothing */
extern _Thread_local char _tls_asctime_buf[_REENT_ASCTIME_SIZE];
#define _REENT_ASCTIME_BUF(_ptr) (_tls_asctime_buf)
extern _Thread_local char *_tls_cvtbuf;
#define _REENT_CVTBUF(_ptr) (_tls_cvtbuf)
extern _Thread_local int _tls_cvtlen;
#define _REENT_CVTLEN(_ptr) (_tls_cvtlen)
extern _Thread_local void (*_tls_cleanup)(struct _reent *);
#define _REENT_CLEANUP(_ptr) (_tls_cleanup)
extern _Thread_local char _tls_emergency;
#define _REENT_EMERGENCY(_ptr) (_tls_emergency)
extern _Thread_local int _tls_errno;
#define _REENT_ERRNO(_ptr) (_tls_errno)
extern _Thread_local int _tls_getdate_err;
#define _REENT_GETDATE_ERR_P(_ptr) (&_tls_getdate_err)
extern _Thread_local int _tls_inc;
#define _REENT_INC(_ptr) (_tls_inc)
extern _Thread_local char _tls_l64a_buf[8];
#define _REENT_L64A_BUF(_ptr) (_tls_l64a_buf)
extern _Thread_local struct __locale_t *_tls_locale;
#define _REENT_LOCALE(_ptr) (_tls_locale)
extern _Thread_local _mbstate_t _tls_mblen_state;
#define _REENT_MBLEN_STATE(_ptr) (_tls_mblen_state)
extern _Thread_local _mbstate_t _tls_mbrlen_state;
#define _REENT_MBRLEN_STATE(_ptr) (_tls_mbrlen_state)
extern _Thread_local _mbstate_t _tls_mbrtowc_state;
#define _REENT_MBRTOWC_STATE(_ptr) (_tls_mbrtowc_state)
extern _Thread_local _mbstate_t _tls_mbsrtowcs_state;
#define _REENT_MBSRTOWCS_STATE(_ptr) (_tls_mbsrtowcs_state)
extern _Thread_local _mbstate_t _tls_mbtowc_state;
#define _REENT_MBTOWC_STATE(_ptr) (_tls_mbtowc_state)
extern _Thread_local struct _Bigint **_tls_mp_freelist;
#define _REENT_MP_FREELIST(_ptr) (_tls_mp_freelist)
extern _Thread_local struct _Bigint *_tls_mp_p5s;
#define _REENT_MP_P5S(_ptr) (_tls_mp_p5s)
extern _Thread_local struct _Bigint *_tls_mp_result;
#define _REENT_MP_RESULT(_ptr) (_tls_mp_result)
extern _Thread_local int _tls_mp_result_k;
#define _REENT_MP_RESULT_K(_ptr) (_tls_mp_result_k)
extern _Thread_local unsigned short _tls_rand48_add;
#define _REENT_RAND48_ADD(_ptr) (_tls_rand48_add)
extern _Thread_local unsigned short _tls_rand48_mult[3];
#define _REENT_RAND48_MULT(_ptr) (_tls_rand48_mult)
extern _Thread_local unsigned short _tls_rand48_seed[3];
#define _REENT_RAND48_SEED(_ptr) (_tls_rand48_seed)
extern _Thread_local unsigned long long _tls_rand_next;
#define _REENT_RAND_NEXT(_ptr) (_tls_rand_next)
extern _Thread_local void (**_tls_sig_func)(int);
#define _REENT_SIG_FUNC(_ptr) (_tls_sig_func)
extern _Thread_local char _tls_signal_buf[_REENT_SIGNAL_SIZE];
#define _REENT_SIGNAL_BUF(_ptr) (_tls_signal_buf)
extern _Thread_local int _tls_gamma_signgam;
#define _REENT_SIGNGAM(_ptr) (_tls_gamma_signgam)
extern _Thread_local __FILE *_tls_stdin;
#define _REENT_STDIN(_ptr) (_tls_stdin)
extern _Thread_local __FILE *_tls_stdout;
#define _REENT_STDOUT(_ptr) (_tls_stdout)
extern _Thread_local __FILE *_tls_stderr;
#define _REENT_STDERR(_ptr) (_tls_stderr)
extern _Thread_local char *_tls_strtok_last;
#define _REENT_STRTOK_LAST(_ptr) (_tls_strtok_last)
extern _Thread_local struct __tm _tls_localtime_buf;
#define _REENT_TM(_ptr) (&_tls_localtime_buf)
extern _Thread_local _mbstate_t _tls_wctomb_state;
#define _REENT_WCTOMB_STATE(_ptr) (_tls_wctomb_state)
extern _Thread_local _mbstate_t _tls_wcrtomb_state;
#define _REENT_WCRTOMB_STATE(_ptr) (_tls_wcrtomb_state)
extern _Thread_local _mbstate_t _tls_wcsrtombs_state;
#define _REENT_WCSRTOMBS_STATE(_ptr) (_tls_wcsrtombs_state)
#endif /* !_REENT_THREAD_LOCAL */
/* This value is used in stdlib/misc.c. reent/reent.c has to know it
as well to make sure the freelist is correctly free'd. Therefore
we define it here, rather than in stdlib/misc.c, as before. */

View File

@ -166,6 +166,10 @@ No supporting OS subroutines are required.
#include "../ctype/ctype_.h"
#include "../stdlib/local.h"
#ifdef _REENT_THREAD_LOCAL
_Thread_local struct __locale_t *_tls_locale;
#endif
#ifdef __CYGWIN__ /* Has to be kept available as exported symbol for
backward compatibility. Set it in setlocale, but
otherwise ignore it. Applications compiled after

View File

@ -1,5 +1,7 @@
#include <reent.h>
#ifndef _REENT_THREAD_LOCAL
/* Redeclare these symbols locally as weak so that the file containing
their definitions (along with a lot of other stuff) isn't sucked in
unless they are actually used by other compilation units. This is
@ -14,3 +16,5 @@ struct _reent __ATTRIBUTE_IMPURE_DATA__ _impure_data = _REENT_INIT (_impure_data
extern struct _reent reent_data __attribute__ ((alias("_impure_data")));
#endif
struct _reent *__ATTRIBUTE_IMPURE_PTR__ _impure_ptr = &_impure_data;
#endif /* _REENT_THREAD_LOCAL */

View File

@ -30,7 +30,9 @@ int errno;
void
_reclaim_reent (struct _reent *ptr)
{
#ifndef _REENT_THREAD_LOCAL
if (ptr != _impure_ptr)
#endif
{
/* used by mprec routines. */
#ifdef _REENT_SMALL

View File

@ -88,6 +88,10 @@ int _dummy_simulated_signal;
#include <reent.h>
#include <_syslist.h>
#ifdef _REENT_THREAD_LOCAL
_Thread_local void (**_tls_sig_func)(int);
#endif
int
_init_signal_r (struct _reent *ptr)
{

View File

@ -32,6 +32,13 @@ __FILE __sf[3];
struct _glue __sglue = {NULL, 3, &__sf[0]};
#ifdef _REENT_THREAD_LOCAL
_Thread_local __FILE *_tls_stdin = &__sf[0];
_Thread_local __FILE *_tls_stdout = &__sf[1];
_Thread_local __FILE *_tls_stderr = &__sf[2];
_Thread_local void (*_tls_cleanup)(struct _reent *);
#endif
#ifdef _STDIO_BSD_SEMANTICS
/* BSD and Glibc systems only flush streams which have been written to
at exit time. Calling flush rather than close for speed, as on

View File

@ -82,6 +82,11 @@ The global pointer <<environ>> is also required.
#include <reent.h>
#include <errno.h>
#ifdef _REENT_THREAD_LOCAL
_Thread_local int _tls_inc;
_Thread_local char _tls_emergency;
#endif
/* Try to open the file specified, if it can't be opened then try
another one. Return nonzero if successful, otherwise zero. */

View File

@ -32,6 +32,11 @@
#include <string.h>
#include "mprec.h"
#ifdef _REENT_THREAD_LOCAL
_Thread_local struct _Bigint *_tls_mp_result;
_Thread_local int _tls_mp_result_k;
#endif
static int
quorem (_Bigint * b, _Bigint * S)
{

View File

@ -57,6 +57,11 @@ Supporting OS subroutines required: <<close>>, <<fstat>>, <<isatty>>,
#include "mprec.h"
#include "local.h"
#ifdef _REENT_THREAD_LOCAL
_Thread_local char *_tls_cvtbuf;
_Thread_local int _tls_cvtlen;
#endif
static void
print_f (struct _reent *ptr,
char *buf,

View File

@ -24,6 +24,10 @@
#include <stdlib.h>
#include <reent.h>
#ifdef _REENT_THREAD_LOCAL
_Thread_local char _tls_l64a_buf[8];
#endif
static const char R64_ARRAY[] = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
char *

View File

@ -13,6 +13,14 @@
#include "rand48.h"
#ifdef _REENT_THREAD_LOCAL
_Thread_local unsigned short _tls_rand48_seed[3] = {_RAND48_SEED_0, _RAND48_SEED_1,
_RAND48_SEED_2};
_Thread_local unsigned short _tls_rand48_mult[3] = {_RAND48_MULT_0, _RAND48_MULT_1,
_RAND48_MULT_2};
_Thread_local unsigned short _tls_rand48_add = _RAND48_ADD;
#endif
void
_lcong48_r (struct _reent *r,
unsigned short p[7])

View File

@ -42,6 +42,10 @@ effects vary with the locale.
#include <wchar.h>
#include "local.h"
#ifdef _REENT_THREAD_LOCAL
_Thread_local _mbstate_t _tls_mblen_state;
#endif
int
mblen (const char *s,
size_t n)

View File

@ -5,6 +5,10 @@
#include <stdio.h>
#include <errno.h>
#ifdef _REENT_THREAD_LOCAL
_Thread_local _mbstate_t _tls_mbrlen_state;
#endif
size_t
mbrlen(const char *__restrict s, size_t n, mbstate_t *__restrict ps)
{

View File

@ -7,6 +7,10 @@
#include <string.h>
#include "local.h"
#ifdef _REENT_THREAD_LOCAL
_Thread_local _mbstate_t _tls_mbrtowc_state;
#endif
size_t
_mbrtowc_r (struct _reent *ptr,
wchar_t *pwc,

View File

@ -70,6 +70,10 @@ PORTABILITY
#include <stdio.h>
#include <errno.h>
#ifdef _REENT_THREAD_LOCAL
_Thread_local _mbstate_t _tls_mbsrtowcs_state;
#endif
size_t
_mbsnrtowcs_r (struct _reent *r,
wchar_t *dst,

View File

@ -49,6 +49,10 @@ effects vary with the locale.
#include <wchar.h>
#include "local.h"
#ifdef _REENT_THREAD_LOCAL
_Thread_local _mbstate_t _tls_mbtowc_state;
#endif
int
mbtowc (wchar_t *__restrict pwc,
const char *__restrict s,

View File

@ -86,6 +86,11 @@
#include <reent.h>
#include "mprec.h"
#ifdef _REENT_THREAD_LOCAL
_Thread_local struct _Bigint *_tls_mp_p5s;
_Thread_local struct _Bigint **_tls_mp_freelist;
#endif
/* This is defined in sys/reent.h as (sizeof (size_t) << 3) now, as in NetBSD.
The old value of 15 was wrong and made newlib vulnerable against buffer
overrun attacks (CVE-2009-0689), same as other implementations of gdtoa

View File

@ -58,6 +58,10 @@ on two different systems.
#include <stdlib.h>
#include <reent.h>
#ifdef _REENT_THREAD_LOCAL
_Thread_local unsigned long long _tls_rand_next = 1;
#endif
void
srand (unsigned int seed)
{

View File

@ -6,6 +6,10 @@
#include <errno.h>
#include "local.h"
#ifdef _REENT_THREAD_LOCAL
_Thread_local _mbstate_t _tls_wcrtomb_state;
#endif
size_t
_wcrtomb_r (struct _reent *ptr,
char *s,

View File

@ -72,6 +72,10 @@ PORTABILITY
#include "local.h"
#include "../locale/setlocale.h"
#ifdef _REENT_THREAD_LOCAL
_Thread_local _mbstate_t _tls_wcsrtombs_state;
#endif
size_t
_wcsnrtombs_l (struct _reent *r, char *dst, const wchar_t **src, size_t nwc,
size_t len, mbstate_t *ps, struct __locale_t *loc)

View File

@ -45,6 +45,10 @@ effects vary with the locale.
#include <errno.h>
#include "local.h"
#ifdef _REENT_THREAD_LOCAL
_Thread_local _mbstate_t _tls_wctomb_state;
#endif
int
wctomb (char *s,
wchar_t wchar)

View File

@ -52,6 +52,10 @@ QUICKREF
#include <stdlib.h>
#include <reent.h>
#ifdef _REENT_THREAD_LOCAL
_Thread_local char _tls_signal_buf[_REENT_SIGNAL_SIZE];
#endif
char *
strsignal (int signal)
{

View File

@ -74,6 +74,10 @@ QUICKREF
#include <_ansi.h>
#include <reent.h>
#ifdef _REENT_THREAD_LOCAL
_Thread_local char *_tls_strtok_last;
#endif
#ifndef _REENT_ONLY
extern char *__strtok_r (char *, const char *, char **, int);

View File

@ -45,6 +45,10 @@ ANSI C requires <<asctime>>.
#include <_ansi.h>
#include <reent.h>
#ifdef _REENT_THREAD_LOCAL
_Thread_local char _tls_asctime_buf[_REENT_ASCTIME_SIZE];
#endif
#ifndef _REENT_ONLY
char *

View File

@ -47,6 +47,10 @@ ANSI C requires <<gmtime>>.
#define _GMT_OFFSET 0
#ifdef _REENT_THREAD_LOCAL
_Thread_local struct __tm _tls_localtime_buf;
#endif
#ifndef _REENT_ONLY
struct tm *

View File

@ -22,6 +22,10 @@
#include <reent.h>
#include <errno.h>
#ifdef _REENT_THREAD_LOCAL
_Thread_local int _tls_gamma_signgam;
#endif
#ifndef _DOUBLE_IS_32BITS
#ifdef __STDC__

View File

@ -406,6 +406,10 @@
restricted storage. */
#undef _WANT_REENT_SMALL
/* Define to enable thread-local storage objects as a replacment for struct
_reent members. */
#undef _WANT_REENT_THREAD_LOCAL
/* Register application finalization function using atexit. */
#undef _WANT_REGISTER_FINI