This is the mail archive of the newlib@sourceware.org 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]
Other format: [Raw text]

Re: RFA: reducing size of _atexit structure for _REENT_SMALL


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
}
}


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