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

__atexit.c « stdlib « libc « newlib - cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: e59f04c2e440140348e69a10d13a31b9f4e558dd (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
/*
 *  Common routine to implement atexit-like functionality.
 *
 *  This is also the key function to be configured as lite exit, a size-reduced
 *  implementation of exit that doesn't invoke clean-up functions such as _fini
 *  or global destructors.
 *
 *  Default (without lite exit) call graph is like:
 *  _start -> atexit -> __register_exitproc
 *  _start -> __libc_init_array -> __cxa_atexit -> __register_exitproc
 *  on_exit -> __register_exitproc
 *  _start -> exit -> __call_exitprocs
 *
 *  Here an -> means arrow tail invokes arrow head. All invocations here
 *  are non-weak reference in current newlib/libgloss.
 *
 *  Lite exit makes some of above calls as weak reference, so that size expansive
 *  functions __register_exitproc and __call_exitprocs may not be linked. These
 *  calls are:
 *    _start w-> atexit
 *    __cxa_atexit w-> __register_exitproc
 *    exit w-> __call_exitprocs
 *
 *  Lite exit also makes sure that __call_exitprocs will be referenced as non-weak
 *  whenever __register_exitproc is referenced as non-weak.
 *
 *  Thus with lite exit libs, a program not explicitly calling atexit or on_exit
 *  will escape from the burden of cleaning up code. A program with atexit or on_exit
 *  will work consistently to normal libs.
 *
 *  Lite exit is enabled with --enable-lite-exit, and is controlled with macro
 *  _LITE_EXIT.
 */

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

/* Make this a weak reference to avoid pulling in malloc.  */
#ifndef MALLOC_PROVIDED
void * malloc(size_t) _ATTRIBUTE((__weak__));
#endif

#ifdef _LITE_EXIT
/* As __call_exitprocs is weak reference in lite exit, make a
   non-weak reference to it here.  */
const void * __atexit_dummy = &__call_exitprocs;
#endif

#ifndef __SINGLE_THREAD__
extern _LOCK_RECURSIVE_T __atexit_recursive_mutex;
#endif

struct _atexit __atexit0 = _ATEXIT_INIT;

/*
 * Register a function to be performed at exit or on shared library unload.
 */

int
__register_exitproc (int type,
	void (*fn) (void),
	void *arg,
	void *d)
{
  struct _on_exit_args * args;
  register struct _atexit *p;

#ifndef __SINGLE_THREAD__
  __lock_acquire_recursive(__atexit_recursive_mutex);
#endif

  p = __atexit;
  if (p == NULL)
    {
      __atexit = p = &__atexit0;
#ifdef _REENT_SMALL
      extern struct _on_exit_args * const __on_exit_args _ATTRIBUTE ((weak));
      if (&__on_exit_args != NULL)
	p->_on_exit_args_ptr = __on_exit_args;
#endif	/* def _REENT_SMALL */
    }
  if (p->_ind >= _ATEXIT_SIZE)
    {
#if !defined (_ATEXIT_DYNAMIC_ALLOC) || !defined (MALLOC_PROVIDED)
#ifndef __SINGLE_THREAD__
      __lock_release_recursive(__atexit_recursive_mutex);
#endif
      return -1;
#else
      p = (struct _atexit *) malloc (sizeof *p);
      if (p == NULL)
	{
#ifndef __SINGLE_THREAD__
	  __lock_release_recursive(__atexit_recursive_mutex);
#endif
	  return -1;
	}
      p->_ind = 0;
      p->_next = __atexit;
      __atexit = p;
#ifndef _REENT_SMALL
      p->_on_exit_args._fntypes = 0;
      p->_on_exit_args._is_cxa = 0;
#else
      p->_on_exit_args_ptr = NULL;
#endif
#endif
    }

  if (type != __et_atexit)
    {
#ifdef _REENT_SMALL
      args = p->_on_exit_args_ptr;
      if (args == NULL)
	{
#ifndef _ATEXIT_DYNAMIC_ALLOC
#ifndef __SINGLE_THREAD__
	  __lock_release_recursive(__atexit_recursive_mutex);
#endif
	  return -1;
#else
	  if (malloc)
	    args = malloc (sizeof * p->_on_exit_args_ptr);

	  if (args == NULL)
	    {
#ifndef __SINGLE_THREAD__
	      __lock_release_recursive(__atexit_recursive_mutex);
#endif
	      return -1;
	    }
	  args->_fntypes = 0;
	  args->_is_cxa = 0;
	  p->_on_exit_args_ptr = args;
#endif
	}
#else
      args = &p->_on_exit_args;
#endif
      args->_fnargs[p->_ind] = arg;
      args->_fntypes |= (1 << p->_ind);
      args->_dso_handle[p->_ind] = d;
      if (type == __et_cxa)
	args->_is_cxa |= (1 << p->_ind);
    }
  p->_fns[p->_ind++] = fn;
#ifndef __SINGLE_THREAD__
  __lock_release_recursive(__atexit_recursive_mutex);
#endif
  return 0;
}