]> git.saurik.com Git - apple/libc.git/blame - stdlib/atexit-fbsd.c
Libc-583.tar.gz
[apple/libc.git] / stdlib / atexit-fbsd.c
CommitLineData
224c7076
A
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)
38static 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__)
b5d655f7 49#include <dlfcn.h>
224c7076
A
50#endif /* defined(__DYNAMIC__) */
51#include "atexit.h"
52#include "un-namespace.h"
53
34e8f829
A
54#ifdef __BLOCKS__
55#include <Block.h>
56#endif /* __BLOCKS__ */
224c7076
A
57#include "libc_private.h"
58
59#define ATEXIT_FN_EMPTY 0
60#define ATEXIT_FN_STD 1
61#define ATEXIT_FN_CXA 2
34e8f829
A
62#ifdef __BLOCKS__
63#define ATEXIT_FN_BLK 3
64#endif /* __BLOCKS__ */
224c7076
A
65
66static 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
71struct 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 *);
34e8f829
A
79#ifdef __BLOCKS__
80 void (^block)(void);
81#endif /* __BLOCKS__ */
224c7076
A
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
88static struct atexit *__atexit; /* points to head of LIFO stack */
89static 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 */
96static int
97atexit_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 */
133int
134atexit(void (*func)(void))
135{
136 struct atexit_fn fn;
b5d655f7 137 struct dl_info info;
224c7076
A
138 int error;
139
140 fn.fn_type = ATEXIT_FN_STD;
34e8f829 141 fn.fn_ptr.std_func = func;
224c7076
A
142 fn.fn_arg = NULL;
143#if defined(__DYNAMIC__)
b5d655f7
A
144 if ( dladdr(func, &info) )
145 fn.fn_dso = info.dli_fbase;
146 else
147 fn.fn_dso = NULL;
224c7076
A
148#else /* ! defined(__DYNAMIC__) */
149 fn.fn_dso = NULL;
150#endif /* defined(__DYNAMIC__) */
151
152 error = atexit_register(&fn);
153 return (error);
154}
155
34e8f829
A
156#ifdef __BLOCKS__
157int
158atexit_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
224c7076
A
181/*
182 * Register a function to be performed at exit or when an shared object
183 * with given dso handle is unloaded dynamically.
184 */
185int
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 */
205void
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);
213restart:
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();
34e8f829
A
234#ifdef __BLOCKS__
235 else if (fn.fn_type == ATEXIT_FN_BLK)
236 fn.fn_ptr.block();
237#endif /* __BLOCKS__ */
224c7076
A
238 _MUTEX_LOCK(&atexit_mutex);
239 if (new_registration)
240 goto restart;
241 }
242 }
243 _MUTEX_UNLOCK(&atexit_mutex);
244}