1 /* __cxa_atexit backwards-compatibility support for Darwin.
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GCC.
6 GCC is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 2, or (at your option) any later
11 In addition to the permissions in the GNU General Public License, the
12 Free Software Foundation gives you unlimited permission to link the
13 compiled version of this file into combinations with other programs,
14 and to distribute those combinations without any restriction coming
15 from the use of this file. (The General Public License restrictions
16 do apply in other respects; for example, they cover modification of
17 the file, and distribution when not linked into a combine
20 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
25 You should have received a copy of the GNU General Public License
26 along with GCC; see the file COPYING. If not, write to the Free
27 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
30 /* It is incorrect to include config.h here, because this file is being
31 compiled for the target, and hence definitions concerning only the host
41 /* This file works around two different problems.
43 The first problem is that there is no __cxa_atexit on Mac OS versions
44 before 10.4. It fixes this by providing one, and having it called from
45 a destructor. This is not quite as good as having a real __cxa_atexit,
46 but it's good enough to imitate the behaviour that you'd get if
49 The second problem is that on 10.4 Mac OS versions, __cxa_finalize
50 doesn't work right: it doesn't run routines that were registered
51 while other atexit routines are running. This is worked around by
52 installing our own handler so that it runs last, and repeatedly
53 running __cxa_finalize until no new calls to __cxa_atexit are made. */
55 typedef int (*cxa_atexit_p)(void (*func) (void*), void* arg, void* dso);
58 void __cxa_finalize (void* dso) __attribute__((weak));
60 void __cxa_finalize (void* dso);
63 /* new_atexit_routines is set if __cxa_finalize exists in the system C
64 library and our copy of __cxa_atexit has been called. */
66 static bool new_atexit_routines;
68 /* first_atexit_handler is called after all other atexit routines
69 that were registered before __cxa_finalize is called.
70 It may be called more than once, but is not re-entered. */
73 first_atexit_handler(void* dso)
75 /* Keep running __cxa_finalize until no new atexit routines are
77 Note that this means __cxa_finalize will be called at least twice,
78 even if the first call didn't register any new routines. */
79 while (new_atexit_routines) {
80 new_atexit_routines = false;
85 /* This is our wrapper around __cxa_atexit that's called if __cxa_finalize
86 exists in the system library. All it does is, on its first call,
87 install first_atexit_handler; and on every call, set new_atexit_routines
88 and pass control to the system __cxa_atexit.
89 This proves to be somewhat more complicated than you might expect,
90 because it may be called in a multithreaded environment. Fortunately
91 it turns out to be possible to do what's needed without resorting
95 cxa_atexit_wrapper (void (*func) (void*), void* arg, void* dso)
97 static volatile cxa_atexit_p real_cxa_atexit;
98 cxa_atexit_p auto_cxa_atexit = real_cxa_atexit;
99 if (! auto_cxa_atexit)
101 void* handle = dlopen ("/usr/lib/libSystem.B.dylib", RTLD_NOLOAD);
105 auto_cxa_atexit = (cxa_atexit_p)dlsym (handle, "__cxa_atexit");
106 if (! auto_cxa_atexit)
109 /* At this point, auto_cxa_atexit contains the address of
110 the system __cxa_atexit. */
111 if (! real_cxa_atexit)
113 /* Install our handler above before any other handlers
114 for this image, so it will be called last. */
115 int result = (*auto_cxa_atexit)(first_atexit_handler, dso, dso);
118 /* Now set the global real_cxa_atexit to prevent further
119 installations of first_atexit_handler. Do this after
120 the installation so that if another thread sees it is set,
121 it can be sure that first_atexit_handler really has been
123 real_cxa_atexit = auto_cxa_atexit;
125 /* At this point, we know that first_atexit_handler has been
126 installed at least once, and real_cxa_atexit is not NULL. */
127 /* It's not necessary to mark new_atexit_routines as volatile, so long
128 as this write eventually happens before this shared object is
130 new_atexit_routines = true;
131 /* Call the original __cxa_atexit for this function. */
132 return (*auto_cxa_atexit)(func, arg, dso);
136 /* This code is used while running on 10.3.9, when __cxa_atexit doesn't
137 exist in the system library. 10.3.9 only supported regular PowerPC,
138 so this code isn't necessary on x86 or ppc64. */
140 /* This structure holds a routine to call. */
141 struct atexit_routine
143 struct atexit_routine * next;
144 void (*func)(void *);
148 static struct atexit_routine * volatile atexit_routines_list;
150 /* If __cxa_atexit doesn't exist at all in the system library, this
151 routine is used; it completely emulates __cxa_atexit.
153 This routine has to be thread-safe, but fortunately this just means
154 that it has to do atomic list insertion. */
157 cxa_atexit_substitute (void (*func) (void*), void* arg,
158 /* The 'dso' value will always be equal to this
159 object's __dso_handle. */
160 void* dso __attribute__((unused)))
162 struct atexit_routine * s = malloc (sizeof (struct atexit_routine));
163 struct atexit_routine * next, * old_next;
168 next = atexit_routines_list;
170 s->next = old_next = next;
171 next = __sync_val_compare_and_swap (&atexit_routines_list, old_next, s);
172 } while (next != old_next);
176 /* The routines added in cxa_atexit_substitute get run here, in a destructor.
177 This routine doesn't have to be thread-safe. */
179 static void cxa_dtor (void) __attribute__((destructor));
183 while (atexit_routines_list)
185 struct atexit_routine * working_list = atexit_routines_list;
186 atexit_routines_list = NULL;
189 struct atexit_routine * called_routine = working_list;
190 working_list->func (working_list->arg);
191 working_list = working_list->next;
192 free (called_routine);
198 int __cxa_atexit (void (*func) (void*), void* arg,
199 void* dso) __attribute__((visibility("hidden")));
201 __cxa_atexit (void (*func) (void*), void* arg, void* dso)
204 if (! __cxa_finalize)
205 return cxa_atexit_substitute (func, arg, dso);
207 return cxa_atexit_wrapper (func, arg, dso);