source: trunk/libs/newlib/src/newlib/libc/stdlib/__call_atexit.c @ 471

Last change on this file since 471 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 3.9 KB
Line 
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.  */
12void free(void *) _ATTRIBUTE((__weak__));
13
14#ifndef __SINGLE_THREAD__
15__LOCK_INIT_RECURSIVE(, __atexit_recursive_mutex);
16#endif
17
18#ifdef _REENT_GLOBAL_ATEXIT
19struct _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.  */
38extern 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.  */
43static void 
44register_fini(void) __attribute__((constructor (0)));
45
46static void 
47register_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
67void 
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}
Note: See TracBrowser for help on using the repository browser.