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