1 /* Copyright (c) 2004 Paul Brook <paul@codesourcery.com> */
2 /*
3 * Common routine to implement atexit-like functionality.
4 *
5 * This is also the key function to be configured as lite exit, a size-reduced
6 * implementation of exit that doesn't invoke clean-up functions such as _fini
7 * or global destructors.
8 *
9 * Default (without lite exit) call graph is like:
10 * _start -> atexit -> __register_exitproc
11 * _start -> __libc_init_array -> __cxa_atexit -> __register_exitproc
12 * on_exit -> __register_exitproc
13 * _start -> exit -> __call_exitprocs
14 *
15 * Here an -> means arrow tail invokes arrow head. All invocations here
16 * are non-weak reference in current newlib.
17 *
18 * Lite exit makes some of above calls as weak reference, so that size expansive
19 * functions __register_exitproc and __call_exitprocs may not be linked. These
20 * calls are:
21 * _start w-> atexit
22 * __cxa_atexit w-> __register_exitproc
23 * exit w-> __call_exitprocs
24 *
25 * Lite exit also makes sure that __call_exitprocs will be referenced as non-weak
26 * whenever __register_exitproc is referenced as non-weak.
27 *
28 * Thus with lite exit libs, a program not explicitly calling atexit or on_exit
29 * will escape from the burden of cleaning up code. A program with atexit or on_exit
30 * will work consistently to normal libs.
31 *
32 * Lite exit is enabled with --enable-lite-exit, and is controlled with macro
33 * _LITE_EXIT.
34 */
35
36 #include <stddef.h>
37 #include <stdlib.h>
38 #include <sys/lock.h>
39 #include "atexit.h"
40
41 /* Make this a weak reference to avoid pulling in malloc. */
42 #ifndef MALLOC_PROVIDED
43 void * malloc(size_t) _ATTRIBUTE((__weak__));
44 #endif
45
46 #ifdef _LITE_EXIT
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;
50 #endif
51
52 NEWLIB_THREAD_LOCAL_ATEXIT struct _atexit _atexit0;
53 NEWLIB_THREAD_LOCAL_ATEXIT struct _atexit *_atexit;
54
55 /*
56 * Register a function to be performed at exit or on shared library unload.
57 */
58
59 int
__register_exitproc(int type,void (* fn)(void),void * arg,void * d)60 __register_exitproc (int type,
61 void (*fn) (void),
62 void *arg,
63 void *d)
64 {
65 struct _on_exit_args * args;
66 register struct _atexit *p;
67
68 __LIBC_LOCK();
69
70 p = _atexit;
71 if (p == NULL)
72 {
73 _atexit = p = &_atexit0;
74 }
75 if (p->_ind >= _ATEXIT_SIZE)
76 {
77 #if !defined (_ATEXIT_DYNAMIC_ALLOC) || !defined (MALLOC_PROVIDED)
78 __LIBC_UNLOCK();
79 return -1;
80 #else
81 p = (struct _atexit *) malloc (sizeof *p);
82 if (p == NULL)
83 {
84 __LIBC_UNLOCK();
85 return -1;
86 }
87 p->_ind = 0;
88 p->_next = _atexit;
89 _atexit = p;
90 #endif
91 }
92
93 if (type != __et_atexit)
94 {
95 args = &p->_on_exit_args;
96 args->_fnargs[p->_ind] = arg;
97 args->_fntypes |= (1 << p->_ind);
98 args->_dso_handle[p->_ind] = d;
99 if (type == __et_cxa)
100 args->_is_cxa |= (1 << p->_ind);
101 }
102 p->_fns[p->_ind++] = fn;
103 __LIBC_UNLOCK();
104 return 0;
105 }
106