]> git.saurik.com Git - apple/libc.git/blob - stdlib/atexit-fbsd.c
Libc-594.9.1.tar.gz
[apple/libc.git] / stdlib / atexit-fbsd.c
1 /*-
2 * Copyright (c) 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid[] = "@(#)atexit.c 8.2 (Berkeley) 7/3/94";
39 #endif /* LIBC_SCCS and not lint */
40 #include <sys/cdefs.h>
41 __FBSDID("$FreeBSD: src/lib/libc/stdlib/atexit.c,v 1.7 2003/12/19 17:11:20 kan Exp $");
42
43 #include "namespace.h"
44 #include <stddef.h>
45 #include <stdlib.h>
46 #include <unistd.h>
47 #include <pthread.h>
48 #if defined(__DYNAMIC__)
49 #include <dlfcn.h>
50 #endif /* defined(__DYNAMIC__) */
51 #include "atexit.h"
52 #include "un-namespace.h"
53
54 #ifdef __BLOCKS__
55 #include <Block.h>
56 #endif /* __BLOCKS__ */
57 #include "libc_private.h"
58
59 #define ATEXIT_FN_EMPTY 0
60 #define ATEXIT_FN_STD 1
61 #define ATEXIT_FN_CXA 2
62 #ifdef __BLOCKS__
63 #define ATEXIT_FN_BLK 3
64 #endif /* __BLOCKS__ */
65
66 static pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER;
67
68 #define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x)
69 #define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x)
70
71 struct atexit {
72 struct atexit *next; /* next in list */
73 int ind; /* next index in this table */
74 struct atexit_fn {
75 int fn_type; /* ATEXIT_? from above */
76 union {
77 void (*std_func)(void);
78 void (*cxa_func)(void *);
79 #ifdef __BLOCKS__
80 void (^block)(void);
81 #endif /* __BLOCKS__ */
82 } fn_ptr; /* function pointer */
83 void *fn_arg; /* argument for CXA callback */
84 void *fn_dso; /* shared module handle */
85 } fns[ATEXIT_SIZE]; /* the table itself */
86 };
87
88 static struct atexit *__atexit; /* points to head of LIFO stack */
89 static int new_registration;
90
91 /*
92 * Register the function described by 'fptr' to be called at application
93 * exit or owning shared object unload time. This is a helper function
94 * for atexit and __cxa_atexit.
95 */
96 static int
97 atexit_register(struct atexit_fn *fptr)
98 {
99 static struct atexit __atexit0; /* one guaranteed table */
100 struct atexit *p;
101
102 _MUTEX_LOCK(&atexit_mutex);
103 if ((p = __atexit) == NULL)
104 __atexit = p = &__atexit0;
105 else while (p->ind >= ATEXIT_SIZE) {
106 struct atexit *old__atexit;
107 old__atexit = __atexit;
108 _MUTEX_UNLOCK(&atexit_mutex);
109 if ((p = (struct atexit *)malloc(sizeof(*p))) == NULL)
110 return (-1);
111 _MUTEX_LOCK(&atexit_mutex);
112 if (old__atexit != __atexit) {
113 /* Lost race, retry operation */
114 _MUTEX_UNLOCK(&atexit_mutex);
115 free(p);
116 _MUTEX_LOCK(&atexit_mutex);
117 p = __atexit;
118 continue;
119 }
120 p->ind = 0;
121 p->next = __atexit;
122 __atexit = p;
123 }
124 p->fns[p->ind++] = *fptr;
125 new_registration = 1;
126 _MUTEX_UNLOCK(&atexit_mutex);
127 return 0;
128 }
129
130 /*
131 * Register a function to be performed at exit.
132 */
133 int
134 atexit(void (*func)(void))
135 {
136 struct atexit_fn fn;
137 struct dl_info info;
138 int error;
139
140 fn.fn_type = ATEXIT_FN_STD;
141 fn.fn_ptr.std_func = func;
142 fn.fn_arg = NULL;
143 #if defined(__DYNAMIC__)
144 if ( dladdr(func, &info) )
145 fn.fn_dso = info.dli_fbase;
146 else
147 fn.fn_dso = NULL;
148 #else /* ! defined(__DYNAMIC__) */
149 fn.fn_dso = NULL;
150 #endif /* defined(__DYNAMIC__) */
151
152 error = atexit_register(&fn);
153 return (error);
154 }
155
156 #ifdef __BLOCKS__
157 int
158 atexit_b(void (^block)(void))
159 {
160 struct atexit_fn fn;
161 struct dl_info info;
162 int error;
163
164 fn.fn_type = ATEXIT_FN_BLK;
165 fn.fn_ptr.block = Block_copy(block);
166 fn.fn_arg = NULL;
167 #if defined(__DYNAMIC__)
168 if ( dladdr(block, &info) )
169 fn.fn_dso = info.dli_fbase;
170 else
171 fn.fn_dso = NULL;
172 #else /* ! defined(__DYNAMIC__) */
173 fn.fn_dso = NULL;
174 #endif /* defined(__DYNAMIC__) */
175
176 error = atexit_register(&fn);
177 return (error);
178 }
179 #endif /* __BLOCKS__ */
180
181 /*
182 * Register a function to be performed at exit or when an shared object
183 * with given dso handle is unloaded dynamically.
184 */
185 int
186 __cxa_atexit(void (*func)(void *), void *arg, void *dso)
187 {
188 struct atexit_fn fn;
189 int error;
190
191 fn.fn_type = ATEXIT_FN_CXA;
192 fn.fn_ptr.cxa_func = func;;
193 fn.fn_arg = arg;
194 fn.fn_dso = dso;
195
196 error = atexit_register(&fn);
197 return (error);
198 }
199
200 /*
201 * Call all handlers registered with __cxa_atexit for the shared
202 * object owning 'dso'. Note: if 'dso' is NULL, then all remaining
203 * handlers are called.
204 */
205 void
206 __cxa_finalize(const void *dso)
207 {
208 struct atexit *p;
209 struct atexit_fn fn;
210 int n;
211
212 _MUTEX_LOCK(&atexit_mutex);
213 restart:
214 for (p = __atexit; p; p = p->next) {
215 for (n = p->ind; --n >= 0;) {
216 if (p->fns[n].fn_type == ATEXIT_FN_EMPTY)
217 continue; /* already been called */
218 if (dso != NULL && dso != p->fns[n].fn_dso)
219 continue; /* wrong DSO */
220 fn = p->fns[n];
221 /*
222 Mark entry to indicate that this particular handler
223 has already been called.
224 */
225 p->fns[n].fn_type = ATEXIT_FN_EMPTY;
226 new_registration = 0;
227 _MUTEX_UNLOCK(&atexit_mutex);
228
229 /* Call the function of correct type. */
230 if (fn.fn_type == ATEXIT_FN_CXA)
231 fn.fn_ptr.cxa_func(fn.fn_arg);
232 else if (fn.fn_type == ATEXIT_FN_STD)
233 fn.fn_ptr.std_func();
234 #ifdef __BLOCKS__
235 else if (fn.fn_type == ATEXIT_FN_BLK)
236 fn.fn_ptr.block();
237 #endif /* __BLOCKS__ */
238 _MUTEX_LOCK(&atexit_mutex);
239 if (new_registration)
240 goto restart;
241 }
242 }
243 _MUTEX_UNLOCK(&atexit_mutex);
244 }