source: trunk/libs/newlib/src/newlib/libc/stdlib/__atexit.c @ 577

Last change on this file since 577 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 4.2 KB
Line 
1/*
2 *  Common routine to implement atexit-like functionality.
3 *
4 *  This is also the key function to be configured as lite exit, a size-reduced
5 *  implementation of exit that doesn't invoke clean-up functions such as _fini
6 *  or global destructors.
7 *
8 *  Default (without lite exit) call graph is like:
9 *  _start -> atexit -> __register_exitproc
10 *  _start -> __libc_init_array -> __cxa_atexit -> __register_exitproc
11 *  on_exit -> __register_exitproc
12 *  _start -> exit -> __call_exitprocs
13 *
14 *  Here an -> means arrow tail invokes arrow head. All invocations here
15 *  are non-weak reference in current newlib/libgloss.
16 *
17 *  Lite exit makes some of above calls as weak reference, so that size expansive
18 *  functions __register_exitproc and __call_exitprocs may not be linked. These
19 *  calls are:
20 *    _start w-> atexit
21 *    __cxa_atexit w-> __register_exitproc
22 *    exit w-> __call_exitprocs
23 *
24 *  Lite exit also makes sure that __call_exitprocs will be referenced as non-weak
25 *  whenever __register_exitproc is referenced as non-weak.
26 *
27 *  Thus with lite exit libs, a program not explicitly calling atexit or on_exit
28 *  will escape from the burden of cleaning up code. A program with atexit or on_exit
29 *  will work consistently to normal libs.
30 *
31 *  Lite exit is enabled with --enable-lite-exit, and is controlled with macro
32 *  _LITE_EXIT.
33 */
34
35#include <stddef.h>
36#include <stdlib.h>
37#include <reent.h>
38#include <sys/lock.h>
39#include "atexit.h"
40
41/* Make this a weak reference to avoid pulling in malloc.  */
42void * malloc(size_t) _ATTRIBUTE((__weak__));
43
44#ifdef _LITE_EXIT
45/* As __call_exitprocs is weak reference in lite exit, make a
46   non-weak reference to it here.  */
47const void * __atexit_dummy = &__call_exitprocs;
48#endif
49
50#ifndef __SINGLE_THREAD__
51extern _LOCK_RECURSIVE_T __atexit_recursive_mutex;
52#endif
53
54#ifdef _REENT_GLOBAL_ATEXIT
55static struct _atexit _global_atexit0 = _ATEXIT_INIT;
56# define _GLOBAL_ATEXIT0 (&_global_atexit0)
57#else
58# define _GLOBAL_ATEXIT0 (&_GLOBAL_REENT->_atexit0)
59#endif
60
61/*
62 * Register a function to be performed at exit or on shared library unload.
63 */
64
65int
66__register_exitproc (int type,
67        void (*fn) (void),
68        void *arg,
69        void *d)
70{
71  struct _on_exit_args * args;
72  register struct _atexit *p;
73
74#ifndef __SINGLE_THREAD__
75  __lock_acquire_recursive(__atexit_recursive_mutex);
76#endif
77
78  p = _GLOBAL_ATEXIT;
79  if (p == NULL)
80    {
81      _GLOBAL_ATEXIT = p = _GLOBAL_ATEXIT0;
82#ifdef _REENT_SMALL
83      extern struct _on_exit_args * const __on_exit_args _ATTRIBUTE ((weak));
84      if (&__on_exit_args != NULL)
85        p->_on_exit_args_ptr = __on_exit_args;
86#endif  /* def _REENT_SMALL */
87    }
88  if (p->_ind >= _ATEXIT_SIZE)
89    {
90#ifndef _ATEXIT_DYNAMIC_ALLOC
91#ifndef __SINGLE_THREAD__
92      __lock_release_recursive(__atexit_recursive_mutex);
93#endif
94      return -1;
95#else
96      /* Don't dynamically allocate the atexit array if malloc is not
97         available.  */
98      if (!malloc)
99        {
100#ifndef __SINGLE_THREAD__
101          __lock_release_recursive(__atexit_recursive_mutex);
102#endif
103          return -1;
104        }
105
106      p = (struct _atexit *) malloc (sizeof *p);
107      if (p == NULL)
108        {
109#ifndef __SINGLE_THREAD__
110          __lock_release_recursive(__atexit_recursive_mutex);
111#endif
112          return -1;
113        }
114      p->_ind = 0;
115      p->_next = _GLOBAL_ATEXIT;
116      _GLOBAL_ATEXIT = p;
117#ifndef _REENT_SMALL
118      p->_on_exit_args._fntypes = 0;
119      p->_on_exit_args._is_cxa = 0;
120#else
121      p->_on_exit_args_ptr = NULL;
122#endif
123#endif
124    }
125
126  if (type != __et_atexit)
127    {
128#ifdef _REENT_SMALL
129      args = p->_on_exit_args_ptr;
130      if (args == NULL)
131        {
132#ifndef _ATEXIT_DYNAMIC_ALLOC
133#ifndef __SINGLE_THREAD__
134          __lock_release_recursive(__atexit_recursive_mutex);
135#endif
136          return -1;
137#else
138          if (malloc)
139            args = malloc (sizeof * p->_on_exit_args_ptr);
140
141          if (args == NULL)
142            {
143#ifndef __SINGLE_THREAD__
144              __lock_release(__atexit_recursive_mutex);
145#endif
146              return -1;
147            }
148          args->_fntypes = 0;
149          args->_is_cxa = 0;
150          p->_on_exit_args_ptr = args;
151#endif
152        }
153#else
154      args = &p->_on_exit_args;
155#endif
156      args->_fnargs[p->_ind] = arg;
157      args->_fntypes |= (1 << p->_ind);
158      args->_dso_handle[p->_ind] = d;
159      if (type == __et_cxa)
160        args->_is_cxa |= (1 << p->_ind);
161    }
162  p->_fns[p->_ind++] = fn;
163#ifndef __SINGLE_THREAD__
164  __lock_release_recursive(__atexit_recursive_mutex);
165#endif
166  return 0;
167}
Note: See TracBrowser for help on using the repository browser.