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: PATCH: Disable dynamic allocation in atexit


Mark,

The patch is fine, but it's got me thinking I want to do a bit more. I have Nick Clifton's problem from a week ago to contend with. I am not happy with his patch as the code becomes incredibly ugly.

What I am thinking of doing is rewriting atexit and not having separate logic for _REENT_SMALL. The code will simply use the static list first and then allocate, if enabled. By default, _REENT_SMALL will have a small number of static entries (e.g. 3) and will by default support dynamic allocation of remaining entries (e.g. 3 at a time). The code for atexit, etc.. becomes more simplified and the platforms can tune their settings accordingly by setting the initial atexit list size.

The one question I am pondering is whether to make static-only-32-entry, the default for non-_REENT_SMALL platforms. Normally I preach backwards-compatibility, but I can't think of any applications off-hand that should require more than 32 entries. This makes the empty program compact by default which I think is a good thing.

Enablement/disablement must be accessible in configure.host so platforms can set a default accordingly.

Comments?

-- Jeff J.

Mark Mitchell wrote:
I noticed recently that "int main() {}" was a 9K program for an ARM
Thumb-2 configuration.  Since some target hardware in this space is
extremely memory constrained (e.g., 8K ROM), I looked a little bit at
the issues.  With the patches in my tree, I got that 9K down to about
800 bytes.  Lest you then ask "So, why use newlib at all?", string
routines, basic math routines, etc., are all relatively small.

By far the biggest issue was that we're pulling in malloc, and the
primary reason for that (outside of some ARM-specific issues that I
will post as follow-on patches) is that crt0 registers fini via
atexit, and atexit calls malloc, and malloc is big.  This patch
provides a configure option to limit atexit to the 32 routines
required by ISO C and provided via static allocation in newlib.

Since these systems generally don't exit, it might be even better just
to dispense with registration of finalizers entirely, possibly based
on some kind of automatic detection.  It might also be better for
_exit to directly call a "system finalizer" (e.g., _fini), rather than
relying on atexit (we *know* that _fini is the last finalizer to
call), which would also avoid pulling in atexit.  However, we still
need the attached patch so that routines register with atexit by the
user do not pull in malloc/free.  So, I think this is unambiguosly
useful, on its own, even if we decide to get more clever later.

OK to commit?

--
Mark Mitchell
CodeSourcery
mark@codesourcery.com
(650) 331-3385 x713

2006-03-17 Mark Mitchell <mark@codesourcery.com>

* acconfig.h (_ATEXIT_DYNAMIC_ALLOC): Undef.
* configure.in (--disable-newlib-atexit-dynamic-alloc): New
option. * configure: Regenerated.
* newlib.hin: Regenerated.
* libc/stdlib/__atexit.c (__register_exitproc): Don't call malloc
if _ATEXIT_DYNAMIC_ALLOC is undefined.
* libc/stdlib/__call_atexit.c (__call_exitprocs): Don't call free
if _ATEXIT_DYNAMIC_ALLOC is undefined.


Index: acconfig.h
===================================================================
RCS file: /cvs/src/src/newlib/acconfig.h,v
retrieving revision 1.1
diff -c -5 -p -r1.1 acconfig.h
*** acconfig.h 20 Jan 2006 22:42:45 -0000 1.1
--- acconfig.h 18 Mar 2006 01:20:00 -0000
***************
*** 32,41 ****
--- 32,45 ----
/* Define if the linker supports .preinit_array/.init_array/.fini_array
* sections. */
#undef HAVE_INITFINI_ARRAY
+ /* True if atexit() may dynamically allocate space for cleanup
+ functions. */
+ #undef _ATEXIT_DYNAMIC_ALLOC
+ /* Define if the compiler supports aliasing an array to an address. */
#undef _HAVE_ARRAY_ALIASING
@BOTTOM@
/*
* Iconv encodings enabled ("to" direction)
Index: configure.in
===================================================================
RCS file: /cvs/src/src/newlib/configure.in,v
retrieving revision 1.28
diff -c -5 -p -r1.28 configure.in
*** configure.in 31 Aug 2005 20:39:40 -0000 1.28
--- configure.in 18 Mar 2006 01:20:00 -0000
*************** AC_ARG_ENABLE(newlib-iconv-external-ccs,
*** 83,92 ****
--- 83,103 ----
no) newlib_iconv_external_ccs=no ;;
*) AC_MSG_ERROR(bad value ${enableval} for newlib-iconv-external-ccs option) ;;
esac
fi], [newlib_iconv_external_ccs=${newlib_iconv_external_ccs}])dnl
+ dnl Support --disable-newlib-atexit-dynamic-alloc
+ AC_ARG_ENABLE(newlib-atexit-dynamic-alloc,
+ [ --disable-newlib-atexit-alloc disable dynamic allocation of atexit entries],
+ [if test "${newlib_atexit_dynamic_alloc+set}" != set; then
+ case "${enableval}" in
+ yes) newlib_atexit_dynamic_alloc=yes ;;
+ no) newlib_atexit_dynamic_alloc=no ;;
+ *) AC_MSG_ERROR(bad value ${enableval} for newlib-atexit-dynamic-alloc option) ;;
+ esac
+ fi], [newlib_atexit_dynamic_alloc=yes])dnl
+ NEWLIB_CONFIGURE(.)
dnl We have to enable libtool after NEWLIB_CONFIGURE because if we try and
dnl add it into NEWLIB_CONFIGURE, executable tests are made before the first
dnl line of the macro which fail because appropriate LDFLAGS are not set.
*************** fi
*** 230,239 ****
--- 241,254 ----
if test "${newlib_iconv_external_ccs}" = "yes"; then
AC_DEFINE_UNQUOTED(_ICONV_ENABLE_EXTERNAL_CCS)
fi
+ if test "${newlib_atexit_dynamic_alloc}" = "yes"; then
+ AC_DEFINE_UNQUOTED(_ATEXIT_DYNAMIC_ALLOC)
+ fi
+ AC_DEFINE_UNQUOTED(_NEWLIB_VERSION,"$VERSION")
if test "${multilib}" = "yes"; then
multilib_arg="--enable-multilib"
else
Index: libc/stdlib/__atexit.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdlib/__atexit.c,v
retrieving revision 1.3
diff -c -5 -p -r1.3 __atexit.c
*** libc/stdlib/__atexit.c 15 Sep 2004 20:50:07 -0000 1.3
--- libc/stdlib/__atexit.c 18 Mar 2006 01:20:00 -0000
*************** _DEFUN (__register_exitproc,
*** 33,42 ****
--- 33,45 ----
p = _GLOBAL_REENT->_atexit;
if (p == NULL)
_GLOBAL_REENT->_atexit = p = &_GLOBAL_REENT->_atexit0;
if (p->_ind >= _ATEXIT_SIZE)
{
+ #ifndef _ATEXIT_DYNAMIC_ALLOC
+ return -1;
+ #else
p = (struct _atexit *) malloc (sizeof *p);
if (p == NULL)
{
#ifndef __SINGLE_THREAD__
__lock_release(lock);
*************** _DEFUN (__register_exitproc,
*** 48,57 ****
--- 51,61 ----
_GLOBAL_REENT->_atexit = p;
#ifndef _REENT_SMALL
p->_on_exit_args._fntypes = 0;
p->_on_exit_args._is_cxa = 0;
#endif
+ #endif
}
if (type != __et_atexit)
{
#ifdef _REENT_SMALL
Index: libc/stdlib/__call_atexit.c
===================================================================
RCS file: /cvs/src/src/newlib/libc/stdlib/__call_atexit.c,v
retrieving revision 1.3
diff -c -5 -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 18 Mar 2006 01:20:00 -0000
*************** _DEFUN (__call_exitprocs, (code, d),
*** 59,68 ****
--- 59,71 ----
(*((void (*)(int, _PTR)) fn))(code, args->_fnargs[n]);
else
(*((void (*)(_PTR)) fn))(args->_fnargs[n]);
}
+ #ifndef _ATEXIT_DYNAMIC_ALLOC
+ break;
+ #else
/* 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. */
*************** _DEFUN (__call_exitprocs, (code, d),
*** 77,83 ****
--- 80,87 ----
else
{
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]