RFA: reducing size of _atexit structure for _REENT_SMALL
Jeff Johnston
jjohnstn@redhat.com
Wed Mar 15 04:40:00 GMT 2006
Nick,
The reason that the implementation is such is because ANSI C90
actually states for atexit(): "The implementation shall support the
registration of at least 32 functions". This isn't true if you only
support dynamically allocated storage.
Now that said, there is the question of how much a _REENT_SMALL
processor wishes to adhere to ANSI C. At the very least, I think this
should be governed by YAF (yet another flag). Comments?
-- Jeff J.
Nick Clifton wrote:
> Hi Jeff,
>
> Please could I have permission to check in the attached patch ?
>
> It changes the _atexit structure defined in libc/include/sys/reent.h
> so that the _fns[] array is replaced by a pointer, if the global
> define _REENT_SMALL is enabled. If any of the atexit functions are
> used then this pointer is initialised to point to an ATEXIT_SIZE
> length array, but otherwise it is left as NULL, thus saving 31 words
> in the _reent structure.
>
> I checked the patch by building two toolchains - an xstormy16-elf
> toolchain which used _REENT_SMALL and an xscale-elf toolchain which
> does not. With both toolchains successfully built and installed I
> compiled and ran a hello world program (with no exit functions) and
> this test program:
>
> #include <stdlib.h>
> #include <stdio.h>
>
> static void exit_func_1 (void)
> { printf ("exit_func_1 called via atexit\n"); }
>
> static void exit_func_2 (char * arg)
> { printf ("exit_func_2 called via __cxa_atexit with arg '%s'\n", arg); }
>
> static void exit_func_3 (int code, char * arg)
> { printf ("exit_func_3 called via on_exit with code %d and arg '%s'\n", code, arg); }
>
> int main (void)
> { printf ("main starting\n");
> atexit (exit_func_1);
> __cxa_atexit ((void (*)(void)) exit_func_2, "hi", NULL);
> on_exit ((void (*)(int,void *)) exit_func_3, "bye");
> return printf ("main ending\n");
> }
>
> For both toolchains the following output was produced:
>
> main starting
> main ending
> exit_func_3 called via on_exit with code 12 and arg 'bye'
> exit_func_2 called via __cxa_atexit with arg 'hi'
> exit_func_1 called via atexit
>
> Cheers
> Nick
>
> newlib/ChangeLog
> 2006-03-10 Nick Clifton <nickc@redhat.com>
>
> For _REENT_SMALL...
> * libc/include/sys/reent.h (struct _atexit): Replace _fns array
> with a pointer '_fns_ptr'.
> (REENT_INIT, _REENT_INIT_PTR): Adjust initializations
> appropriately.
> * libc/reent/reent.c (_reclaim_reent): Free the _fns_ptr if it has
> been allocated.
> (_wrapup_reent): Indirect via _fns_ptr.
> * libc/stdlib/__atexit.c (__register_exitproc): If _fns_ptr is
> NULL allocate space for an array of function pointers.
> * libc/stdlib/__call_atexit.c (__call_exitprocs): Indirect via
> _fns_ptr.
>
>
>
> ------------------------------------------------------------------------
>
> Index: libc/include/sys/reent.h
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/include/sys/reent.h,v
> retrieving revision 1.34
> diff -c -3 -p -r1.34 reent.h
> *** libc/include/sys/reent.h 8 Feb 2005 01:33:16 -0000 1.34
> --- libc/include/sys/reent.h 10 Mar 2006 10:21:52 -0000
> *************** struct _on_exit_args {
> *** 74,84 ****
> __ULong _is_cxa;
> };
>
> #ifdef _REENT_SMALL
> struct _atexit {
> struct _atexit *_next; /* next in list */
> int _ind; /* next index in this table */
> ! void (*_fns[_ATEXIT_SIZE])(void); /* the table itself */
> struct _on_exit_args * _on_exit_args_ptr;
> };
> #else
> --- 74,86 ----
> __ULong _is_cxa;
> };
>
> + typedef void (* _at_exit_void_fn_ptr)(void);
> +
> #ifdef _REENT_SMALL
> struct _atexit {
> struct _atexit *_next; /* next in list */
> int _ind; /* next index in this table */
> ! _at_exit_void_fn_ptr * _fns_ptr; /* pointer to a table of exit function pointers */
> struct _on_exit_args * _on_exit_args_ptr;
> };
> #else
> *************** struct _atexit {
> *** 86,92 ****
> struct _atexit *_next; /* next in list */
> int _ind; /* next index in this table */
> /* Some entries may already have been called, and will be NULL. */
> ! void (*_fns[_ATEXIT_SIZE])(void); /* the table itself */
> struct _on_exit_args _on_exit_args;
> };
> #endif
> --- 88,94 ----
> struct _atexit *_next; /* next in list */
> int _ind; /* next index in this table */
> /* Some entries may already have been called, and will be NULL. */
> ! _at_exit_void_fn_ptr _fns[_ATEXIT_SIZE];/* table of exit function pointers */
> struct _on_exit_args _on_exit_args;
> };
> #endif
> *************** struct _reent
> *** 407,413 ****
> _NULL, \
> _NULL, \
> _NULL, \
> ! {_NULL, 0, {_NULL}, _NULL}, \
> {_NULL, 0, _NULL}, \
> _NULL, \
> {_NULL, 0, 0, 0, 0, {_NULL, 0}, 0, _NULL}, \
> --- 409,415 ----
> _NULL, \
> _NULL, \
> _NULL, \
> ! {_NULL, 0, _NULL, _NULL}, \
> {_NULL, 0, _NULL}, \
> _NULL, \
> {_NULL, 0, 0, 0, 0, {_NULL, 0}, 0, _NULL}, \
> *************** struct _reent
> *** 437,443 ****
> var->_atexit = _NULL; \
> var->_atexit0._next = _NULL; \
> var->_atexit0._ind = 0; \
> ! var->_atexit0._fns[0] = _NULL; \
> var->_atexit0._on_exit_args_ptr = _NULL; \
> var->__sglue._next = _NULL; \
> var->__sglue._niobs = 0; \
> --- 439,445 ----
> var->_atexit = _NULL; \
> var->_atexit0._next = _NULL; \
> var->_atexit0._ind = 0; \
> ! var->_atexit0._fns_ptr = _NULL; \
> var->_atexit0._on_exit_args_ptr = _NULL; \
> var->__sglue._next = _NULL; \
> var->__sglue._niobs = 0; \
> Index: libc/reent/reent.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/reent/reent.c,v
> retrieving revision 1.8
> diff -c -3 -p -r1.8 reent.c
> *** libc/reent/reent.c 9 Sep 2004 19:46:54 -0000 1.8
> --- libc/reent/reent.c 10 Mar 2006 10:21:52 -0000
> *************** _DEFUN (_reclaim_reent, (ptr),
> *** 83,88 ****
> --- 83,90 ----
> _free_r (ptr, ptr->_asctime_buf);
> if (ptr->_atexit->_on_exit_args_ptr)
> _free_r (ptr, ptr->_atexit->_on_exit_args_ptr);
> + if (ptr->_atexit->_fns_ptr)
> + _free_r (ptr, ptr->_atexit->_fns_ptr);
> #else
> /* atexit stuff */
> if ((ptr->_atexit) && (ptr->_atexit != &ptr->_atexit0))
> *************** _DEFUN (_wrapup_reent, (ptr), struct _re
> *** 131,144 ****
> if (ptr == 0)
> ptr = _REENT;
>
> #ifdef _REENT_SMALL
> ! for (p = &ptr->_atexit, n = p->_ind; --n >= 0;)
> ! (*p->_fns[n]) ();
> #else
> ! for (p = ptr->_atexit; p; p = p->_next)
> for (n = p->_ind; --n >= 0;)
> (*p->_fns[n]) ();
> #endif
> if (ptr->__cleanup)
> (*ptr->__cleanup) (ptr);
> }
> --- 133,154 ----
> if (ptr == 0)
> ptr = _REENT;
>
> + p = ptr->_atexit;
> #ifdef _REENT_SMALL
> ! if (p != NULL)
> ! {
> ! _at_exit_void_fn_ptr * fns = p->_fns_ptr;
> !
> ! if (fns != NULL)
> ! for (n = p->_ind; --n >= 0;)
> ! fns[n] ();
> ! }
> #else
> ! for (; p; p = p->_next)
> for (n = p->_ind; --n >= 0;)
> (*p->_fns[n]) ();
> #endif
> +
> if (ptr->__cleanup)
> (*ptr->__cleanup) (ptr);
> }
> Index: libc/stdlib/__atexit.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdlib/__atexit.c,v
> retrieving revision 1.3
> diff -c -3 -p -r1.3 __atexit.c
> *** libc/stdlib/__atexit.c 15 Sep 2004 20:50:07 -0000 1.3
> --- libc/stdlib/__atexit.c 10 Mar 2006 10:21:52 -0000
> ***************
> *** 9,14 ****
> --- 9,27 ----
> #include "atexit.h"
>
>
> + #ifndef __SINGLE_THREAD__
> + #define FAIL \
> + do \
> + { \
> + __lock_release (lock); \
> + return -1; \
> + } \
> + while (0)
> + #else
> + #define FAIL \
> + return -1
> + #endif
> +
> /*
> * Register a function to be performed at exit or on shared library unload.
> */
> *************** _DEFUN (__register_exitproc,
> *** 35,52 ****
> _GLOBAL_REENT->_atexit = p = &_GLOBAL_REENT->_atexit0;
> if (p->_ind >= _ATEXIT_SIZE)
> {
> p = (struct _atexit *) malloc (sizeof *p);
> if (p == NULL)
> ! {
> ! #ifndef __SINGLE_THREAD__
> ! __lock_release(lock);
> ! #endif
> ! return -1;
> ! }
> p->_ind = 0;
> p->_next = _GLOBAL_REENT->_atexit;
> _GLOBAL_REENT->_atexit = p;
> - #ifndef _REENT_SMALL
> p->_on_exit_args._fntypes = 0;
> p->_on_exit_args._is_cxa = 0;
> #endif
> --- 48,63 ----
> _GLOBAL_REENT->_atexit = p = &_GLOBAL_REENT->_atexit0;
> if (p->_ind >= _ATEXIT_SIZE)
> {
> + #ifdef _REENT_SMALL
> + FAIL;
> + #else
> p = (struct _atexit *) malloc (sizeof *p);
> if (p == NULL)
> ! FAIL;
> !
> p->_ind = 0;
> p->_next = _GLOBAL_REENT->_atexit;
> _GLOBAL_REENT->_atexit = p;
> p->_on_exit_args._fntypes = 0;
> p->_on_exit_args._is_cxa = 0;
> #endif
> *************** _DEFUN (__register_exitproc,
> *** 60,71 ****
> {
> args = malloc (sizeof * p->_on_exit_args_ptr);
> if (args == NULL)
> ! {
> ! #ifndef __SINGLE_THREAD__
> ! __lock_release(lock);
> ! #endif
> ! return -1;
> ! }
> args->_fntypes = 0;
> args->_is_cxa = 0;
> p->_on_exit_args_ptr = args;
> --- 71,78 ----
> {
> args = malloc (sizeof * p->_on_exit_args_ptr);
> if (args == NULL)
> ! FAIL;
> !
> args->_fntypes = 0;
> args->_is_cxa = 0;
> p->_on_exit_args_ptr = args;
> *************** _DEFUN (__register_exitproc,
> *** 79,85 ****
> if (type == __et_cxa)
> args->_is_cxa |= (1 << p->_ind);
> }
> ! p->_fns[p->_ind++] = fn;
> #ifndef __SINGLE_THREAD__
> __lock_release(lock);
> #endif
> --- 86,110 ----
> if (type == __et_cxa)
> args->_is_cxa |= (1 << p->_ind);
> }
> !
> ! #ifdef _REENT_SMALL
> ! {
> ! _at_exit_void_fn_ptr * fns = p->_fns_ptr;
> !
> ! if (fns == NULL)
> ! {
> ! fns = p->_fns_ptr = malloc ((sizeof (* fns)) * _ATEXIT_SIZE);
> ! if (fns == NULL)
> ! FAIL;
> ! }
> ! fns[p->_ind] = fn;
> ! }
> ! #else
> ! p->_fns[p->_ind] = fn;
> ! #endif
> !
> ! p->_ind ++;
> !
> #ifndef __SINGLE_THREAD__
> __lock_release(lock);
> #endif
> Index: libc/stdlib/__call_atexit.c
> ===================================================================
> RCS file: /cvs/src/src/newlib/libc/stdlib/__call_atexit.c,v
> retrieving revision 1.3
> diff -c -3 -p -r1.3 __call_atexit.c
> *** libc/stdlib/__call_atexit.c 15 Sep 2004 20:50:07 -0000 1.3
> --- libc/stdlib/__call_atexit.c 10 Mar 2006 10:21:52 -0000
> *************** _DEFUN (__call_exitprocs, (code, d),
> *** 28,33 ****
> --- 28,38 ----
> while (p)
> {
> #ifdef _REENT_SMALL
> + _at_exit_void_fn_ptr * fns = p->_fns_ptr;
> +
> + if (fns == NULL)
> + break;
> +
> args = p->_on_exit_args_ptr;
> #else
> args = &p->_on_exit_args;
> *************** _DEFUN (__call_exitprocs, (code, d),
> *** 42,52 ****
>
> /* Remove the function now to protect against the
> function calling exit recursively. */
> fn = p->_fns[n];
> if (n == p->_ind - 1)
> p->_ind--;
> - else
> - p->_fns[n] = NULL;
>
> /* Skip functions that have already been called. */
> if (!fn)
> --- 47,61 ----
>
> /* Remove the function now to protect against the
> function calling exit recursively. */
> + #ifdef _REENT_SMALL
> + fn = fns[n];
> + fns[n] = NULL;
> + #else
> fn = p->_fns[n];
> + p->_fns[n] = NULL;
> + #endif
> if (n == p->_ind - 1)
> p->_ind--;
>
> /* Skip functions that have already been called. */
> if (!fn)
> *************** _DEFUN (__call_exitprocs, (code, d),
> *** 63,76 ****
>
> /* Move to the next block. Free empty blocks except the last one,
> which is part of _GLOBAL_REENT. */
> if (p->_ind == 0 && p->_next)
> {
> /* Remove empty block from the list. */
> *lastp = p->_next;
> - #ifdef _REENT_SMALL
> if (args)
> free (args);
> - #endif
> free (p);
> p = *lastp;
> }
> --- 72,86 ----
>
> /* Move to the next block. Free empty blocks except the last one,
> which is part of _GLOBAL_REENT. */
> + #ifdef _REENT_SMALL
> + p = NULL;
> + #else
> if (p->_ind == 0 && p->_next)
> {
> /* Remove empty block from the list. */
> *lastp = p->_next;
> if (args)
> free (args);
> free (p);
> p = *lastp;
> }
> *************** _DEFUN (__call_exitprocs, (code, d),
> *** 79,83 ****
> --- 89,94 ----
> lastp = &p->_next;
> p = p->_next;
> }
> + #endif
> }
> }
More information about the Newlib
mailing list