1 /*
2 * COmmon routine to call call registered atexit-like routines.
3 */
4
5
6 #include <stdlib.h>
7 #include <sys/lock.h>
8 #include "atexit.h"
9
10 /* Make this a weak reference to avoid pulling in free. */
11 #ifndef MALLOC_PROVIDED
12 void free(void *) _ATTRIBUTE((__weak__));
13 #endif
14
15 #ifndef __SINGLE_THREAD__
16 __LOCK_INIT_RECURSIVE(, __atexit_recursive_mutex);
17 #endif
18
19 #ifdef _WANT_REGISTER_FINI
20
21 /* If "__libc_fini" is defined, finalizers (either
22 "__libc_fini_array", or "_fini", as appropriate) will be run after
23 all user-specified atexit handlers. For example, you can define
24 "__libc_fini" to "_fini" in your linker script if you want the C
25 library, rather than startup code, to register finalizers. If you
26 do that, then your startup code need not contain references to
27 "atexit" or "exit". As a result, only applications that reference
28 "exit" explicitly will pull in finalization code.
29
30 The choice of whether to register finalizers from libc or from
31 startup code is deferred to link-time, rather than being a
32 configure-time option, so that the same C library binary can be
33 used with multiple BSPs, some of which register finalizers from
34 startup code, while others defer to the C library. */
35 extern char __libc_fini __attribute__((weak));
36
37 /* Register the application finalization function with atexit. These
38 finalizers should run last. Therefore, we want to call atexit as
39 soon as possible. */
40 static void
41 register_fini(void) __attribute__((constructor (0)));
42
43 static void
register_fini(void)44 register_fini(void)
45 {
46 if (&__libc_fini) {
47 #ifdef HAVE_INITFINI_ARRAY
48 extern void __libc_fini_array (void);
49 atexit (__libc_fini_array);
50 #else
51 extern void _fini (void);
52 atexit (_fini);
53 #endif
54 }
55 }
56
57 #endif /* _WANT_REGISTER_FINI */
58
59 /*
60 * Call registered exit handlers. If D is null then all handlers are called,
61 * otherwise only the handlers from that DSO are called.
62 */
63
64 void
__call_exitprocs(int code,void * d)65 __call_exitprocs (int code, void *d)
66 {
67 register struct _atexit *p;
68 struct _atexit **lastp;
69 register struct _on_exit_args * args;
70 register int n;
71 int i;
72 void (*fn) (void);
73
74
75 #ifndef __SINGLE_THREAD__
76 __lock_acquire_recursive(__atexit_recursive_mutex);
77 #endif
78
79 restart:
80
81 p = _atexit;
82 lastp = &_atexit;
83 while (p)
84 {
85 args = &p->_on_exit_args;
86 for (n = p->_ind - 1; n >= 0; n--)
87 {
88 int ind;
89
90 i = 1 << n;
91
92 /* Skip functions not from this dso. */
93 if (d && (!args || args->_dso_handle[n] != d))
94 continue;
95
96 /* Remove the function now to protect against the
97 function calling exit recursively. */
98 fn = p->_fns[n];
99 if (n == p->_ind - 1)
100 p->_ind--;
101 else
102 p->_fns[n] = NULL;
103
104 /* Skip functions that have already been called. */
105 if (!fn)
106 continue;
107
108 ind = p->_ind;
109
110 /* Call the function. */
111 if (!args || (args->_fntypes & i) == 0)
112 fn ();
113 else if ((args->_is_cxa & i) == 0)
114 (*((void (*)(int, void *)) fn))(code, args->_fnargs[n]);
115 else
116 (*((void (*)(void *)) fn))(args->_fnargs[n]);
117
118 /* The function we called call atexit and registered another
119 function (or functions). Call these new functions before
120 continuing with the already registered functions. */
121 if (ind != p->_ind || *lastp != p)
122 goto restart;
123 }
124
125 #if !defined (_ATEXIT_DYNAMIC_ALLOC) || !defined (MALLOC_PROVIDED)
126 break;
127 #else
128 /* Move to the next block. Free empty blocks except the last one,
129 which is part of _GLOBAL_REENT. */
130 if (p->_ind == 0 && p->_next)
131 {
132 /* Remove empty block from the list. */
133 *lastp = p->_next;
134 free (p);
135 p = *lastp;
136 }
137 else
138 {
139 lastp = &p->_next;
140 p = p->_next;
141 }
142 #endif
143 }
144 #ifndef __SINGLE_THREAD__
145 __lock_release_recursive(__atexit_recursive_mutex);
146 #endif
147
148 }
149