Rev 4921 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4921 | Rev 6099 | ||
---|---|---|---|
1 | /* |
1 | /* |
2 | * Common routine to implement atexit-like functionality. |
2 | * Common routine to implement atexit-like functionality. |
3 | * |
3 | * |
4 | * This is also the key function to be configured as lite exit, a size-reduced |
4 | * This is also the key function to be configured as lite exit, a size-reduced |
5 | * implementation of exit that doesn't invoke clean-up functions such as _fini |
5 | * implementation of exit that doesn't invoke clean-up functions such as _fini |
6 | * or global destructors. |
6 | * or global destructors. |
7 | * |
7 | * |
8 | * Default (without lite exit) call graph is like: |
8 | * Default (without lite exit) call graph is like: |
9 | * _start -> atexit -> __register_exitproc |
9 | * _start -> atexit -> __register_exitproc |
10 | * _start -> __libc_init_array -> __cxa_atexit -> __register_exitproc |
10 | * _start -> __libc_init_array -> __cxa_atexit -> __register_exitproc |
11 | * on_exit -> __register_exitproc |
11 | * on_exit -> __register_exitproc |
12 | * _start -> exit -> __call_exitprocs |
12 | * _start -> exit -> __call_exitprocs |
13 | * |
13 | * |
14 | * Here an -> means arrow tail invokes arrow head. All invocations here |
14 | * Here an -> means arrow tail invokes arrow head. All invocations here |
15 | * are non-weak reference in current newlib/libgloss. |
15 | * are non-weak reference in current newlib/libgloss. |
16 | * |
16 | * |
17 | * Lite exit makes some of above calls as weak reference, so that size expansive |
17 | * Lite exit makes some of above calls as weak reference, so that size expansive |
18 | * functions __register_exitproc and __call_exitprocs may not be linked. These |
18 | * functions __register_exitproc and __call_exitprocs may not be linked. These |
19 | * calls are: |
19 | * calls are: |
20 | * _start w-> atexit |
20 | * _start w-> atexit |
21 | * __cxa_atexit w-> __register_exitproc |
21 | * __cxa_atexit w-> __register_exitproc |
22 | * exit w-> __call_exitprocs |
22 | * exit w-> __call_exitprocs |
23 | * |
23 | * |
24 | * Lite exit also makes sure that __call_exitprocs will be referenced as non-weak |
24 | * Lite exit also makes sure that __call_exitprocs will be referenced as non-weak |
25 | * whenever __register_exitproc is referenced as non-weak. |
25 | * whenever __register_exitproc is referenced as non-weak. |
26 | * |
26 | * |
27 | * Thus with lite exit libs, a program not explicitly calling atexit or on_exit |
27 | * Thus with lite exit libs, a program not explicitly calling atexit or on_exit |
28 | * will escape from the burden of cleaning up code. A program with atexit or on_exit |
28 | * will escape from the burden of cleaning up code. A program with atexit or on_exit |
29 | * will work consistently to normal libs. |
29 | * will work consistently to normal libs. |
30 | * |
30 | * |
31 | * Lite exit is enabled with --enable-lite-exit, and is controlled with macro |
31 | * Lite exit is enabled with --enable-lite-exit, and is controlled with macro |
32 | * _LITE_EXIT. |
32 | * _LITE_EXIT. |
33 | */ |
33 | */ |
34 | 34 | ||
35 | #include |
35 | #include |
36 | #include |
36 | #include |
37 | #include |
37 | #include |
38 | #include |
38 | #include |
39 | #include "atexit.h" |
39 | #include "atexit.h" |
40 | 40 | ||
41 | /* Make this a weak reference to avoid pulling in malloc. */ |
41 | /* Make this a weak reference to avoid pulling in malloc. */ |
42 | void * malloc(size_t) _ATTRIBUTE((__weak__)); |
42 | void * malloc(size_t) _ATTRIBUTE((__weak__)); |
43 | 43 | ||
44 | #ifdef _LITE_EXIT |
44 | #ifdef _LITE_EXIT |
45 | /* As __call_exitprocs is weak reference in lite exit, make a |
45 | /* As __call_exitprocs is weak reference in lite exit, make a |
46 | non-weak reference to it here. */ |
46 | non-weak reference to it here. */ |
47 | const void * __atexit_dummy = &__call_exitprocs; |
47 | const void * __atexit_dummy = &__call_exitprocs; |
48 | #endif |
48 | #endif |
49 | 49 | ||
50 | #ifndef __SINGLE_THREAD__ |
50 | #ifndef __SINGLE_THREAD__ |
51 | extern _LOCK_RECURSIVE_T __atexit_lock; |
51 | extern _LOCK_RECURSIVE_T __atexit_lock; |
52 | #endif |
52 | #endif |
53 | 53 | ||
54 | #ifdef _REENT_GLOBAL_ATEXIT |
54 | #ifdef _REENT_GLOBAL_ATEXIT |
55 | static struct _atexit _global_atexit0 = _ATEXIT_INIT; |
55 | static struct _atexit _global_atexit0 = _ATEXIT_INIT; |
56 | # define _GLOBAL_ATEXIT0 (&_global_atexit0) |
56 | # define _GLOBAL_ATEXIT0 (&_global_atexit0) |
57 | #else |
57 | #else |
58 | # define _GLOBAL_ATEXIT0 (&_GLOBAL_REENT->_atexit0) |
58 | # define _GLOBAL_ATEXIT0 (&_GLOBAL_REENT->_atexit0) |
59 | #endif |
59 | #endif |
60 | 60 | ||
61 | /* |
61 | /* |
62 | * Register a function to be performed at exit or on shared library unload. |
62 | * Register a function to be performed at exit or on shared library unload. |
63 | */ |
63 | */ |
64 | 64 | ||
65 | int |
65 | int |
66 | _DEFUN (__register_exitproc, |
66 | _DEFUN (__register_exitproc, |
67 | (type, fn, arg, d), |
67 | (type, fn, arg, d), |
68 | int type _AND |
68 | int type _AND |
69 | void (*fn) (void) _AND |
69 | void (*fn) (void) _AND |
70 | void *arg _AND |
70 | void *arg _AND |
71 | void *d) |
71 | void *d) |
72 | { |
72 | { |
73 | struct _on_exit_args * args; |
73 | struct _on_exit_args * args; |
74 | register struct _atexit *p; |
74 | register struct _atexit *p; |
75 | 75 | ||
76 | #ifndef __SINGLE_THREAD__ |
76 | #ifndef __SINGLE_THREAD__ |
77 | __lock_acquire_recursive(__atexit_lock); |
77 | __lock_acquire_recursive(__atexit_lock); |
78 | #endif |
78 | #endif |
79 | 79 | ||
80 | p = _GLOBAL_ATEXIT; |
80 | p = _GLOBAL_ATEXIT; |
81 | if (p == NULL) |
81 | if (p == NULL) |
- | 82 | { |
|
82 | _GLOBAL_ATEXIT = p = _GLOBAL_ATEXIT0; |
83 | _GLOBAL_ATEXIT = p = _GLOBAL_ATEXIT0; |
- | 84 | #ifdef _REENT_SMALL |
|
- | 85 | extern struct _on_exit_args * const __on_exit_args _ATTRIBUTE ((weak)); |
|
- | 86 | if (&__on_exit_args != NULL) |
|
- | 87 | p->_on_exit_args_ptr = __on_exit_args; |
|
- | 88 | #endif /* def _REENT_SMALL */ |
|
- | 89 | } |
|
83 | if (p->_ind >= _ATEXIT_SIZE) |
90 | if (p->_ind >= _ATEXIT_SIZE) |
84 | { |
91 | { |
85 | #ifndef _ATEXIT_DYNAMIC_ALLOC |
92 | #ifndef _ATEXIT_DYNAMIC_ALLOC |
- | 93 | #ifndef __SINGLE_THREAD__ |
|
- | 94 | __lock_release_recursive(__atexit_lock); |
|
- | 95 | #endif |
|
86 | return -1; |
96 | return -1; |
87 | #else |
97 | #else |
88 | /* Don't dynamically allocate the atexit array if malloc is not |
98 | /* Don't dynamically allocate the atexit array if malloc is not |
89 | available. */ |
99 | available. */ |
90 | if (!malloc) |
100 | if (!malloc) |
- | 101 | { |
|
- | 102 | #ifndef __SINGLE_THREAD__ |
|
- | 103 | __lock_release_recursive(__atexit_lock); |
|
- | 104 | #endif |
|
91 | return -1; |
105 | return -1; |
- | 106 | } |
|
92 | 107 | ||
93 | p = (struct _atexit *) malloc (sizeof *p); |
108 | p = (struct _atexit *) malloc (sizeof *p); |
94 | if (p == NULL) |
109 | if (p == NULL) |
95 | { |
110 | { |
96 | #ifndef __SINGLE_THREAD__ |
111 | #ifndef __SINGLE_THREAD__ |
97 | __lock_release_recursive(__atexit_lock); |
112 | __lock_release_recursive(__atexit_lock); |
98 | #endif |
113 | #endif |
99 | return -1; |
114 | return -1; |
100 | } |
115 | } |
101 | p->_ind = 0; |
116 | p->_ind = 0; |
102 | p->_next = _GLOBAL_ATEXIT; |
117 | p->_next = _GLOBAL_ATEXIT; |
103 | _GLOBAL_ATEXIT = p; |
118 | _GLOBAL_ATEXIT = p; |
104 | #ifndef _REENT_SMALL |
119 | #ifndef _REENT_SMALL |
105 | p->_on_exit_args._fntypes = 0; |
120 | p->_on_exit_args._fntypes = 0; |
106 | p->_on_exit_args._is_cxa = 0; |
121 | p->_on_exit_args._is_cxa = 0; |
107 | #else |
122 | #else |
108 | p->_on_exit_args_ptr = NULL; |
123 | p->_on_exit_args_ptr = NULL; |
109 | #endif |
124 | #endif |
110 | #endif |
125 | #endif |
111 | } |
126 | } |
112 | 127 | ||
113 | if (type != __et_atexit) |
128 | if (type != __et_atexit) |
114 | { |
129 | { |
115 | #ifdef _REENT_SMALL |
130 | #ifdef _REENT_SMALL |
116 | args = p->_on_exit_args_ptr; |
131 | args = p->_on_exit_args_ptr; |
117 | if (args == NULL) |
132 | if (args == NULL) |
118 | { |
133 | { |
- | 134 | #ifndef _ATEXIT_DYNAMIC_ALLOC |
|
- | 135 | #ifndef __SINGLE_THREAD__ |
|
- | 136 | __lock_release_recursive(__atexit_lock); |
|
- | 137 | #endif |
|
- | 138 | return -1; |
|
- | 139 | #else |
|
119 | if (malloc) |
140 | if (malloc) |
120 | args = malloc (sizeof * p->_on_exit_args_ptr); |
141 | args = malloc (sizeof * p->_on_exit_args_ptr); |
121 | 142 | ||
122 | if (args == NULL) |
143 | if (args == NULL) |
123 | { |
144 | { |
124 | #ifndef __SINGLE_THREAD__ |
145 | #ifndef __SINGLE_THREAD__ |
125 | __lock_release(__atexit_lock); |
146 | __lock_release(__atexit_lock); |
126 | #endif |
147 | #endif |
127 | return -1; |
148 | return -1; |
128 | } |
149 | } |
129 | args->_fntypes = 0; |
150 | args->_fntypes = 0; |
130 | args->_is_cxa = 0; |
151 | args->_is_cxa = 0; |
131 | p->_on_exit_args_ptr = args; |
152 | p->_on_exit_args_ptr = args; |
- | 153 | #endif |
|
132 | } |
154 | } |
133 | #else |
155 | #else |
134 | args = &p->_on_exit_args; |
156 | args = &p->_on_exit_args; |
135 | #endif |
157 | #endif |
136 | args->_fnargs[p->_ind] = arg; |
158 | args->_fnargs[p->_ind] = arg; |
137 | args->_fntypes |= (1 << p->_ind); |
159 | args->_fntypes |= (1 << p->_ind); |
138 | args->_dso_handle[p->_ind] = d; |
160 | args->_dso_handle[p->_ind] = d; |
139 | if (type == __et_cxa) |
161 | if (type == __et_cxa) |
140 | args->_is_cxa |= (1 << p->_ind); |
162 | args->_is_cxa |= (1 << p->_ind); |
141 | } |
163 | } |
142 | p->_fns[p->_ind++] = fn; |
164 | p->_fns[p->_ind++] = fn; |
143 | #ifndef __SINGLE_THREAD__ |
165 | #ifndef __SINGLE_THREAD__ |
144 | __lock_release_recursive(__atexit_lock); |
166 | __lock_release_recursive(__atexit_lock); |
145 | #endif |
167 | #endif |
146 | return 0; |
168 | return 0; |
147 | }><>><> |
169 | }><>><> |