]> git.saurik.com Git - apple/libc.git/blame - stdlib/atexit-fbsd.c
Libc-498.1.5.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
54#include "libc_private.h"
55
56#define ATEXIT_FN_EMPTY 0
57#define ATEXIT_FN_STD 1
58#define ATEXIT_FN_CXA 2
59
60static pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER;
61
62#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x)
63#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x)
64
65struct atexit {
66 struct atexit *next; /* next in list */
67 int ind; /* next index in this table */
68 struct atexit_fn {
69 int fn_type; /* ATEXIT_? from above */
70 union {
71 void (*std_func)(void);
72 void (*cxa_func)(void *);
73 } fn_ptr; /* function pointer */
74 void *fn_arg; /* argument for CXA callback */
75 void *fn_dso; /* shared module handle */
76 } fns[ATEXIT_SIZE]; /* the table itself */
77};
78
79static struct atexit *__atexit; /* points to head of LIFO stack */
80static int new_registration;
81
82/*
83 * Register the function described by 'fptr' to be called at application
84 * exit or owning shared object unload time. This is a helper function
85 * for atexit and __cxa_atexit.
86 */
87static int
88atexit_register(struct atexit_fn *fptr)
89{
90 static struct atexit __atexit0; /* one guaranteed table */
91 struct atexit *p;
92
93 _MUTEX_LOCK(&atexit_mutex);
94 if ((p = __atexit) == NULL)
95 __atexit = p = &__atexit0;
96 else while (p->ind >= ATEXIT_SIZE) {
97 struct atexit *old__atexit;
98 old__atexit = __atexit;
99 _MUTEX_UNLOCK(&atexit_mutex);
100 if ((p = (struct atexit *)malloc(sizeof(*p))) == NULL)
101 return (-1);
102 _MUTEX_LOCK(&atexit_mutex);
103 if (old__atexit != __atexit) {
104 /* Lost race, retry operation */
105 _MUTEX_UNLOCK(&atexit_mutex);
106 free(p);
107 _MUTEX_LOCK(&atexit_mutex);
108 p = __atexit;
109 continue;
110 }
111 p->ind = 0;
112 p->next = __atexit;
113 __atexit = p;
114 }
115 p->fns[p->ind++] = *fptr;
116 new_registration = 1;
117 _MUTEX_UNLOCK(&atexit_mutex);
118 return 0;
119}
120
121/*
122 * Register a function to be performed at exit.
123 */
124int
125atexit(void (*func)(void))
126{
127 struct atexit_fn fn;
b5d655f7 128 struct dl_info info;
224c7076
A
129 int error;
130
131 fn.fn_type = ATEXIT_FN_STD;
132 fn.fn_ptr.std_func = func;;
133 fn.fn_arg = NULL;
134#if defined(__DYNAMIC__)
b5d655f7
A
135 if ( dladdr(func, &info) )
136 fn.fn_dso = info.dli_fbase;
137 else
138 fn.fn_dso = NULL;
224c7076
A
139#else /* ! defined(__DYNAMIC__) */
140 fn.fn_dso = NULL;
141#endif /* defined(__DYNAMIC__) */
142
143 error = atexit_register(&fn);
144 return (error);
145}
146
147/*
148 * Register a function to be performed at exit or when an shared object
149 * with given dso handle is unloaded dynamically.
150 */
151int
152__cxa_atexit(void (*func)(void *), void *arg, void *dso)
153{
154 struct atexit_fn fn;
155 int error;
156
157 fn.fn_type = ATEXIT_FN_CXA;
158 fn.fn_ptr.cxa_func = func;;
159 fn.fn_arg = arg;
160 fn.fn_dso = dso;
161
162 error = atexit_register(&fn);
163 return (error);
164}
165
166/*
167 * Call all handlers registered with __cxa_atexit for the shared
168 * object owning 'dso'. Note: if 'dso' is NULL, then all remaining
169 * handlers are called.
170 */
171void
172__cxa_finalize(const void *dso)
173{
174 struct atexit *p;
175 struct atexit_fn fn;
176 int n;
177
178 _MUTEX_LOCK(&atexit_mutex);
179restart:
180 for (p = __atexit; p; p = p->next) {
181 for (n = p->ind; --n >= 0;) {
182 if (p->fns[n].fn_type == ATEXIT_FN_EMPTY)
183 continue; /* already been called */
184 if (dso != NULL && dso != p->fns[n].fn_dso)
185 continue; /* wrong DSO */
186 fn = p->fns[n];
187 /*
188 Mark entry to indicate that this particular handler
189 has already been called.
190 */
191 p->fns[n].fn_type = ATEXIT_FN_EMPTY;
192 new_registration = 0;
193 _MUTEX_UNLOCK(&atexit_mutex);
194
195 /* Call the function of correct type. */
196 if (fn.fn_type == ATEXIT_FN_CXA)
197 fn.fn_ptr.cxa_func(fn.fn_arg);
198 else if (fn.fn_type == ATEXIT_FN_STD)
199 fn.fn_ptr.std_func();
200 _MUTEX_LOCK(&atexit_mutex);
201 if (new_registration)
202 goto restart;
203 }
204 }
205 _MUTEX_UNLOCK(&atexit_mutex);
206}