Subversion Repositories Kolibri OS

Rev

Rev 4874 | Details | Compare with Previous | Last modification | View Log | RSS feed

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