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