2 * Common routine to implement atexit-like functionality.
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.
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
14 * Here an -> means arrow tail invokes arrow head. All invocations here
15 * are non-weak reference in current newlib/libgloss.
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
21 * __cxa_atexit w-> __register_exitproc
22 * exit w-> __call_exitprocs
24 * Lite exit also makes sure that __call_exitprocs will be referenced as non-weak
25 * whenever __register_exitproc is referenced as non-weak.
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.
31 * Lite exit is enabled with --enable-lite-exit, and is controlled with macro
41 /* Make this a weak reference to avoid pulling in malloc. */
42 #ifndef MALLOC_PROVIDED
43 void * malloc(size_t) _ATTRIBUTE((__weak__
));
47 /* As __call_exitprocs is weak reference in lite exit, make a
48 non-weak reference to it here. */
49 const void * __atexit_dummy
= &__call_exitprocs
;
52 #ifndef __SINGLE_THREAD__
53 extern _LOCK_RECURSIVE_T __atexit_recursive_mutex
;
56 struct _atexit __atexit0
= _ATEXIT_INIT
;
59 * Register a function to be performed at exit or on shared library unload.
63 __register_exitproc (int type
,
68 struct _on_exit_args
* args
;
69 register struct _atexit
*p
;
71 #ifndef __SINGLE_THREAD__
72 __lock_acquire_recursive(__atexit_recursive_mutex
);
78 __atexit
= p
= &__atexit0
;
80 extern struct _on_exit_args
* const __on_exit_args
_ATTRIBUTE ((weak
));
81 if (&__on_exit_args
!= NULL
)
82 p
->_on_exit_args_ptr
= __on_exit_args
;
83 #endif /* def _REENT_SMALL */
85 if (p
->_ind
>= _ATEXIT_SIZE
)
87 #if !defined (_ATEXIT_DYNAMIC_ALLOC) || !defined (MALLOC_PROVIDED)
88 #ifndef __SINGLE_THREAD__
89 __lock_release_recursive(__atexit_recursive_mutex
);
93 p
= (struct _atexit
*) malloc (sizeof *p
);
96 #ifndef __SINGLE_THREAD__
97 __lock_release_recursive(__atexit_recursive_mutex
);
105 p
->_on_exit_args
._fntypes
= 0;
106 p
->_on_exit_args
._is_cxa
= 0;
108 p
->_on_exit_args_ptr
= NULL
;
113 if (type
!= __et_atexit
)
116 args
= p
->_on_exit_args_ptr
;
119 #ifndef _ATEXIT_DYNAMIC_ALLOC
120 #ifndef __SINGLE_THREAD__
121 __lock_release_recursive(__atexit_recursive_mutex
);
126 args
= malloc (sizeof * p
->_on_exit_args_ptr
);
130 #ifndef __SINGLE_THREAD__
131 __lock_release_recursive(__atexit_recursive_mutex
);
137 p
->_on_exit_args_ptr
= args
;
141 args
= &p
->_on_exit_args
;
143 args
->_fnargs
[p
->_ind
] = arg
;
144 args
->_fntypes
|= (1 << p
->_ind
);
145 args
->_dso_handle
[p
->_ind
] = d
;
146 if (type
== __et_cxa
)
147 args
->_is_cxa
|= (1 << p
->_ind
);
149 p
->_fns
[p
->_ind
++] = fn
;
150 #ifndef __SINGLE_THREAD__
151 __lock_release_recursive(__atexit_recursive_mutex
);