1 /* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
2 * This file is part of the Linux-8086 C library and is distributed
3 * under the GNU Library General Public License.
4 */
5
6 #include <features.h>
7 #include <unistd.h>
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <errno.h>
11 #include <atomic.h>
12 #if defined __UCLIBC_HAS_THREADS__ && defined __UCLIBC_HAS_THREADS_NATIVE__
13 # include <fork.h>
14 #endif
15
16 #include <bits/uClibc_mutex.h>
17 __UCLIBC_MUTEX_EXTERN(__atexit_lock) attribute_hidden;
18
19
20
21 typedef void (*aefuncp)(void); /* atexit function pointer */
22 typedef void (*oefuncp)(int, void *); /* on_exit function pointer */
23 typedef void (*cxaefuncp)(void *); /* __cxa_atexit function pointer */
24 typedef enum {
25 ef_free,
26 ef_in_use,
27 ef_on_exit,
28 ef_cxa_atexit
29 } ef_type; /* exit function types */
30
31 /* this is in the L_exit object */
32 extern void (*__exit_cleanup)(int) attribute_hidden;
33
34 /* these are in the L___do_exit object */
35 extern int __exit_slots attribute_hidden;
36 extern int __exit_count attribute_hidden;
37 extern void __exit_handler(int) attribute_hidden;
38 struct exit_function {
39 /*
40 * 'type' should be of type of the 'enum ef_type' above but since we
41 * need this element in an atomic operation we have to use 'long int'.
42 */
43 long int type; /* enum ef_type */
44 union {
45 struct {
46 oefuncp func;
47 void *arg;
48 } on_exit;
49 struct {
50 cxaefuncp func;
51 void *arg;
52 void* dso_handle;
53 } cxa_atexit;
54 } funcs;
55 };
56 #ifdef __UCLIBC_DYNAMIC_ATEXIT__
57 extern struct exit_function *__exit_function_table attribute_hidden;
58 #else
59 extern struct exit_function __exit_function_table[__UCLIBC_MAX_ATEXIT] attribute_hidden;
60 #endif
61 extern struct exit_function *__new_exitfn(void) attribute_hidden;
62
63 /* this is in the L___cxa_atexit object */
64 extern int __cxa_atexit(cxaefuncp, void *arg, void *dso_handle);
65
66 #if defined(L_atexit)
67 extern void *__dso_handle __attribute__ ((__weak__));
68
69 /*
70 * register a function to be called at normal program termination
71 * (the registered function takes no arguments)
72 */
73 #ifdef L_atexit
atexit(aefuncp func)74 int attribute_hidden atexit(aefuncp func)
75 #endif
76 {
77 /*
78 * glibc casts aefuncp to cxaefuncp.
79 * This seems dodgy, but I guess calling a function with more
80 * parameters than it needs will work everywhere?
81 */
82 return __cxa_atexit((cxaefuncp)func, NULL,
83 &__dso_handle == NULL ? NULL : __dso_handle);
84 }
85 #endif
86
87 #ifdef L_on_exit
88 /*
89 * register a function to be called at normal program termination
90 * the registered function takes two arguments:
91 * status - the exit status that was passed to the exit() function
92 * arg - generic argument
93 */
on_exit(oefuncp func,void * arg)94 int on_exit(oefuncp func, void *arg)
95 {
96 struct exit_function *efp;
97
98 if (func == NULL) {
99 return 0;
100 }
101
102 efp = __new_exitfn();
103 if (efp == NULL) {
104 return -1;
105 }
106
107 efp->funcs.on_exit.func = func;
108 efp->funcs.on_exit.arg = arg;
109 /* assign last for thread safety, since we're now unlocked */
110 efp->type = ef_on_exit;
111
112 return 0;
113 }
114 #endif
115
116 #ifdef L___cxa_atexit
libc_hidden_proto(__cxa_atexit)117 libc_hidden_proto(__cxa_atexit)
118 int __cxa_atexit(cxaefuncp func, void *arg, void *dso_handle)
119 {
120 struct exit_function *efp;
121
122 if (func == NULL) {
123 return 0;
124 }
125
126 efp = __new_exitfn();
127 if (efp == NULL) {
128 return -1;
129 }
130
131 efp->funcs.cxa_atexit.func = func;
132 efp->funcs.cxa_atexit.arg = arg;
133 efp->funcs.cxa_atexit.dso_handle = dso_handle;
134 /* assign last for thread safety, since we're now unlocked */
135 efp->type = ef_cxa_atexit;
136
137 return 0;
138 }
139 libc_hidden_def(__cxa_atexit)
140 #endif
141
142 #ifdef L___cxa_finalize
143 /*
144 * If D is non-NULL, call all functions registered with `__cxa_atexit'
145 * with the same dso handle. Otherwise, if D is NULL, call all of the
146 * registered handlers.
147 */
148 void __cxa_finalize(void *dso_handle);
__cxa_finalize(void * dso_handle)149 void __cxa_finalize(void *dso_handle)
150 {
151 struct exit_function *efp;
152 int exit_count_snapshot = __exit_count;
153
154 /* In reverse order */
155 while (exit_count_snapshot) {
156 efp = &__exit_function_table[--exit_count_snapshot];
157
158 /*
159 * We check dso_handle match before we verify the type of the union entry.
160 * However, the atomic_exchange will validate that we were really "allowed"
161 * to read dso_handle...
162 */
163 if ((dso_handle == NULL || dso_handle == efp->funcs.cxa_atexit.dso_handle)
164 /* We don't want to run this cleanup more than once. */
165 && !atomic_compare_and_exchange_bool_acq(&efp->type, ef_free, ef_cxa_atexit)
166 ) {
167 /* glibc passes status (0) too, but that's not in the prototype */
168 (*efp->funcs.cxa_atexit.func)(efp->funcs.cxa_atexit.arg);
169 }
170 }
171
172 /*
173 * Remove the registered fork handlers. We do not have to
174 * unregister anything if the program is going to terminate anyway.
175 */
176 #ifdef UNREGISTER_ATFORK
177 if (dso_handle != NULL) {
178 UNREGISTER_ATFORK(dso_handle);
179 }
180 #endif
181 }
182 #endif
183
184 #ifdef L___exit_handler
185 int __exit_count = 0; /* Number of registered exit functions */
186 #ifdef __UCLIBC_DYNAMIC_ATEXIT__
187 struct exit_function *__exit_function_table = NULL;
188 int __exit_slots = 0; /* Size of __exit_function_table */
189 #else
190 struct exit_function __exit_function_table[__UCLIBC_MAX_ATEXIT];
191 #endif
192
193 /*
194 * Find and return a new exit_function pointer, for atexit,
195 * onexit and __cxa_atexit to initialize
196 */
__new_exitfn(void)197 struct exit_function attribute_hidden *__new_exitfn(void)
198 {
199 struct exit_function *efp;
200
201 __UCLIBC_MUTEX_LOCK(__atexit_lock);
202
203 /*
204 * Reuse free slots at the end of the list.
205 * This avoids eating memory when dlopen and dlclose modules multiple times.
206 */
207 while (__exit_count > 0) {
208 if (__exit_function_table[__exit_count-1].type == ef_free) {
209 --__exit_count;
210 } else break;
211 }
212
213 #ifdef __UCLIBC_DYNAMIC_ATEXIT__
214 /* If we are out of function table slots, make some more */
215 if (__exit_slots < __exit_count+1) {
216 efp = realloc(__exit_function_table,
217 (__exit_slots+20)*sizeof(struct exit_function));
218 if (efp == NULL) {
219 /* __set_errno(ENOMEM); */
220 goto DONE;
221 }
222 __exit_function_table = efp;
223 __exit_slots += 20;
224 }
225 #else
226 if (__exit_count >= __UCLIBC_MAX_ATEXIT) {
227 __set_errno(ENOMEM);
228 efp = NULL;
229 goto DONE;
230 }
231 #endif
232
233 __exit_cleanup = __exit_handler; /* enable cleanup */
234 efp = &__exit_function_table[__exit_count++];
235 efp->type = ef_in_use;
236
237 DONE:
238 __UCLIBC_MUTEX_UNLOCK(__atexit_lock);
239 return efp;
240 }
241
242 /*
243 * Handle the work of executing the registered exit functions
244 * This is called while we are locked, so no additional locking
245 * is needed...
246 */
__exit_handler(int status)247 void __exit_handler(int status)
248 {
249 struct exit_function *efp;
250
251 /* In reverse order */
252 while (__exit_count) {
253 efp = &__exit_function_table[--__exit_count];
254 switch (efp->type) {
255 case ef_on_exit:
256 if (efp->funcs.on_exit.func) {
257 (efp->funcs.on_exit.func)(status, efp->funcs.on_exit.arg);
258 }
259 break;
260 case ef_cxa_atexit:
261 if (efp->funcs.cxa_atexit.func) {
262 /* glibc passes status too, but that's not in the prototype */
263 (efp->funcs.cxa_atexit.func)(efp->funcs.cxa_atexit.arg);
264 }
265 break;
266 }
267 }
268 #ifdef __UCLIBC_DYNAMIC_ATEXIT__
269 /* Free up memory used by the __exit_function_table structure */
270 free(__exit_function_table);
271 #endif
272 }
273 #endif
274
275 #ifdef L_exit
276 /* Defeat compiler optimization which assumes function addresses are never NULL */
not_null_ptr(const void * p)277 static __always_inline int not_null_ptr(const void *p)
278 {
279 const void *q;
280 __asm__ (""
281 : "=r" (q) /* output */
282 : "0" (p) /* input */
283 );
284 return q != 0;
285 }
286
287 extern void weak_function _stdio_term(void) attribute_hidden;
288 attribute_hidden void (*__exit_cleanup)(int) = 0;
289 __UCLIBC_MUTEX_INIT(__atexit_lock, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
290
291 extern void __uClibc_fini(void) attribute_hidden;
292
293 /*
294 * Normal program termination
295 */
exit(int rv)296 void exit(int rv)
297 {
298 /* Perform exit-specific cleanup (atexit and on_exit) */
299 __UCLIBC_MUTEX_LOCK(__atexit_lock);
300 if (not_null_ptr(__exit_cleanup)) {
301 __exit_cleanup(rv);
302 }
303 __UCLIBC_MUTEX_UNLOCK(__atexit_lock);
304
305 __uClibc_fini();
306
307 /* If we are using stdio, try to shut it down. At the very least,
308 * this will attempt to commit all buffered writes. It may also
309 * unbuffer all writable files, or close them outright.
310 * Check the stdio routines for details. */
311 if (not_null_ptr(_stdio_term))
312 _stdio_term();
313
314 _exit(rv);
315 }
316 libc_hidden_def(exit)
317 #endif
318