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