OSDN Git Service

2006-03-15 Geoffrey Keating <geoffk@apple.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / darwin-crt3.c
1 /* __cxa_atexit backwards-compatibility support for Darwin.
2    Copyright (C) 2006 Free Software Foundation, Inc.
3
4 This file is part of GCC.
5
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
9 version.
10
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
18 executable.)
19
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
23 for more details.
24
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
28 02110-1301, USA.  */
29
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
32    do not apply.  */
33
34 #include "tconfig.h"
35 #include "tsystem.h"
36
37 #include <dlfcn.h>
38 #include <stdbool.h>
39 #include <stdlib.h>
40
41 /* This file works around two different problems.
42
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
47    you didn't have one.
48
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.  */
54
55 typedef int (*cxa_atexit_p)(void (*func) (void*), void* arg, void* dso);
56
57 #ifdef __ppc__
58 void __cxa_finalize (void* dso) __attribute__((weak));
59 #else
60 void __cxa_finalize (void* dso);
61 #endif
62
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.  */
65
66 static bool new_atexit_routines;
67
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.  */
71
72 static void
73 first_atexit_handler(void* dso)
74 {
75   /* Keep running __cxa_finalize until no new atexit routines are
76      registered.  
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;
81     __cxa_finalize (dso);
82   };
83 }
84
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
92    to locking.  */
93
94 static int
95 cxa_atexit_wrapper (void (*func) (void*), void* arg, void* dso)
96 {
97   static volatile cxa_atexit_p real_cxa_atexit;
98   cxa_atexit_p auto_cxa_atexit = real_cxa_atexit;
99   if (! auto_cxa_atexit)
100     {
101       void* handle = dlopen ("/usr/lib/libSystem.B.dylib", RTLD_NOLOAD);
102       if (! handle)
103         return -1;
104       
105       auto_cxa_atexit = (cxa_atexit_p)dlsym (handle, "__cxa_atexit");
106       if (! auto_cxa_atexit)
107         return -1;
108     }
109   /* At this point, auto_cxa_atexit contains the address of
110      the system __cxa_atexit.  */
111   if (! real_cxa_atexit)
112     {
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);
116       if (result != 0)
117         return result;
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
122          installed.  */
123       real_cxa_atexit = auto_cxa_atexit;
124     }
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
129      unloaded.  */
130   new_atexit_routines = true;
131   /* Call the original __cxa_atexit for this function.  */
132   return (*auto_cxa_atexit)(func, arg, dso);
133 }
134 \f
135 #ifdef __ppc__
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.  */
139
140 /* This structure holds a routine to call.  */
141 struct atexit_routine
142 {
143   struct atexit_routine * next;
144   void (*func)(void *);
145   void * arg;
146 };
147
148 static struct atexit_routine * volatile atexit_routines_list;
149
150 /* If __cxa_atexit doesn't exist at all in the system library, this
151    routine is used; it completely emulates __cxa_atexit.  
152
153    This routine has to be thread-safe, but fortunately this just means
154    that it has to do atomic list insertion.  */
155
156 static int
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)))
161 {
162   struct atexit_routine * s = malloc (sizeof (struct atexit_routine));
163   struct atexit_routine * next, * old_next;
164   if (!s)
165     return -1;
166   s->func = func;
167   s->arg = arg;
168   next = atexit_routines_list;
169   do {
170     s->next = old_next = next;
171     next = __sync_val_compare_and_swap (&atexit_routines_list, old_next, s);
172   } while (next != old_next);
173   return 0;
174 }
175
176 /* The routines added in cxa_atexit_substitute get run here, in a destructor.
177    This routine doesn't have to be thread-safe.  */
178
179 static void cxa_dtor (void) __attribute__((destructor));
180 static void
181 cxa_dtor (void)
182 {
183   while (atexit_routines_list)
184     {
185       struct atexit_routine * working_list = atexit_routines_list;
186       atexit_routines_list = NULL;
187       while (working_list)
188         {
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);
193         }
194     }
195 }
196 #endif
197
198 int __cxa_atexit (void (*func) (void*), void* arg, 
199                   void* dso) __attribute__((visibility("hidden")));
200 int
201 __cxa_atexit (void (*func) (void*), void* arg, void* dso)
202 {
203 #ifdef __ppc__
204   if (! __cxa_finalize)
205     return cxa_atexit_substitute (func, arg, dso);
206 #endif
207   return cxa_atexit_wrapper (func, arg, dso);
208 }