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