Welcome to mirror list, hosted at ThFree Co, Russian Federation.

__call_atexit.c « stdlib « libc « newlib - cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 1e6e710449358920fa50bd991bc7576c63ab5f2a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/*
 * COmmon routine to call call registered atexit-like routines.
 */


#include <stdlib.h>
#include <reent.h>
#include <sys/lock.h>
#include "atexit.h"

/* Make this a weak reference to avoid pulling in free.  */
void free(void *) _ATTRIBUTE((__weak__));

__LOCK_INIT_RECURSIVE(, __atexit_lock);

#ifdef _REENT_GLOBAL_ATEXIT
struct _atexit *_global_atexit = _NULL;
#endif

#ifdef _WANT_REGISTER_FINI

/* If "__libc_fini" is defined, finalizers (either
   "__libc_fini_array", or "_fini", as appropriate) will be run after
   all user-specified atexit handlers.  For example, you can define
   "__libc_fini" to "_fini" in your linker script if you want the C
   library, rather than startup code, to register finalizers.  If you
   do that, then your startup code need not contain references to
   "atexit" or "exit".  As a result, only applications that reference
   "exit" explicitly will pull in finalization code.

   The choice of whether to register finalizers from libc or from
   startup code is deferred to link-time, rather than being a
   configure-time option, so that the same C library binary can be
   used with multiple BSPs, some of which register finalizers from
   startup code, while others defer to the C library.  */
extern char __libc_fini __attribute__((weak));

/* Register the application finalization function with atexit.  These
   finalizers should run last.  Therefore, we want to call atexit as
   soon as possible.  */
static void 
register_fini(void) __attribute__((constructor (0)));

static void 
register_fini(void)
{
  if (&__libc_fini) {
#ifdef HAVE_INITFINI_ARRAY
    extern void __libc_fini_array (void);
    atexit (__libc_fini_array);
#else
    extern void _fini (void);
    atexit (_fini);
#endif
  }
}

#endif /* _WANT_REGISTER_FINI  */

/*
 * Call registered exit handlers.  If D is null then all handlers are called,
 * otherwise only the handlers from that DSO are called.
 */

void 
_DEFUN (__call_exitprocs, (code, d),
	int code _AND _PTR d)
{
  register struct _atexit *p;
  struct _atexit **lastp;
  register struct _on_exit_args * args;
  register int n;
  int i;
  void (*fn) (void);


#ifndef __SINGLE_THREAD__
  __lock_acquire_recursive(__atexit_lock);
#endif

 restart:

  p = _GLOBAL_ATEXIT;
  lastp = &_GLOBAL_ATEXIT;
  while (p)
    {
#ifdef _REENT_SMALL
      args = p->_on_exit_args_ptr;
#else
      args = &p->_on_exit_args;
#endif
      for (n = p->_ind - 1; n >= 0; n--)
	{
	  int ind;

	  i = 1 << n;

	  /* Skip functions not from this dso.  */
	  if (d && (!args || args->_dso_handle[n] != d))
	    continue;

	  /* Remove the function now to protect against the
	     function calling exit recursively.  */
	  fn = p->_fns[n];
	  if (n == p->_ind - 1)
	    p->_ind--;
	  else
	    p->_fns[n] = NULL;

	  /* Skip functions that have already been called.  */
	  if (!fn)
	    continue;

	  ind = p->_ind;

	  /* Call the function.  */
	  if (!args || (args->_fntypes & i) == 0)
	    fn ();
	  else if ((args->_is_cxa & i) == 0)
	    (*((void (*)(int, _PTR)) fn))(code, args->_fnargs[n]);
	  else
	    (*((void (*)(_PTR)) fn))(args->_fnargs[n]);

	  /* The function we called call atexit and registered another
	     function (or functions).  Call these new functions before
	     continuing with the already registered functions.  */
	  if (ind != p->_ind || *lastp != p)
	    goto restart;
	}

#ifndef _ATEXIT_DYNAMIC_ALLOC
      break;
#else
      /* Don't dynamically free the atexit array if free is not
	 available.  */
      if (!free)
	break;

      /* Move to the next block.  Free empty blocks except the last one,
	 which is part of _GLOBAL_REENT.  */
      if (p->_ind == 0 && p->_next)
	{
	  /* Remove empty block from the list.  */
	  *lastp = p->_next;
#ifdef _REENT_SMALL
	  if (args)
	    free (args);
#endif
	  free (p);
	  p = *lastp;
	}
      else
	{
	  lastp = &p->_next;
	  p = p->_next;
	}
#endif
    }
#ifndef __SINGLE_THREAD__
  __lock_release_recursive(__atexit_lock);
#endif

}