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