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 | * 4. Neither the name of the University nor the names of its contributors␊ |
17 | * may be used to endorse or promote products derived from this software␊ |
18 | * without specific prior written permission.␊ |
19 | *␊ |
20 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND␊ |
21 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE␊ |
22 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE␊ |
23 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE␊ |
24 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL␊ |
25 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS␊ |
26 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)␊ |
27 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT␊ |
28 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY␊ |
29 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF␊ |
30 | * SUCH DAMAGE.␊ |
31 | */␊ |
32 | ␊ |
33 | #if defined(LIBC_SCCS) && !defined(lint)␊ |
34 | static char sccsid[] = "@(#)atexit.c␉8.2 (Berkeley) 7/3/94";␊ |
35 | #endif /* LIBC_SCCS and not lint */␊ |
36 | #include <sys/cdefs.h>␊ |
37 | __FBSDID("$FreeBSD: src/lib/libc/stdlib/atexit.c,v 1.8 2007/01/09 00:28:09 imp Exp $");␊ |
38 | ␊ |
39 | #include "namespace.h"␊ |
40 | #include <stddef.h>␊ |
41 | #include <stdlib.h>␊ |
42 | #include <unistd.h>␊ |
43 | #include "atexit.h"␊ |
44 | #include "un-namespace.h"␊ |
45 | ␊ |
46 | #define␉ATEXIT_FN_EMPTY␉0␊ |
47 | #define␉ATEXIT_FN_STD␉1␊ |
48 | #define␉ATEXIT_FN_CXA␉2␊ |
49 | ␊ |
50 | struct atexit {␊ |
51 | ␉struct atexit *next;␉␉␉/* next in list */␊ |
52 | ␉int ind;␉␉␉␉/* next index in this table */␊ |
53 | ␉struct atexit_fn {␊ |
54 | ␉␉int fn_type;␉␉␉/* ATEXIT_? from above */␊ |
55 | ␉␉union {␊ |
56 | ␉␉␉void (*std_func)(void);␊ |
57 | ␉␉␉void (*cxa_func)(void *);␊ |
58 | ␉␉} fn_ptr;␉␉␉/* function pointer */␊ |
59 | ␉␉void *fn_arg;␉␉␉/* argument for CXA callback */␊ |
60 | ␉␉void *fn_dso;␉␉␉/* shared module handle */␊ |
61 | ␉} fns[ATEXIT_SIZE];␉␉␉/* the table itself */␊ |
62 | };␊ |
63 | ␊ |
64 | static struct atexit *__atexit;␉␉/* points to head of LIFO stack */␊ |
65 | static int new_registration;␊ |
66 | ␊ |
67 | /*␊ |
68 | * Register the function described by 'fptr' to be called at application␊ |
69 | * exit or owning shared object unload time. This is a helper function␊ |
70 | * for atexit and __cxa_atexit.␊ |
71 | */␊ |
72 | static int␊ |
73 | atexit_register(struct atexit_fn *fptr)␊ |
74 | {␊ |
75 | ␉static struct atexit __atexit0;␉/* one guaranteed table */␊ |
76 | ␉struct atexit *p;␊ |
77 | ␊ |
78 | ␉if ((p = __atexit) == NULL)␊ |
79 | ␉␉__atexit = p = &__atexit0;␊ |
80 | ␉else while (p->ind >= ATEXIT_SIZE) {␊ |
81 | ␉␉struct atexit *old__atexit;␊ |
82 | ␉␉old__atexit = __atexit;␊ |
83 | ␉␉if ((p = (struct atexit *)malloc(sizeof(*p))) == NULL)␊ |
84 | ␉␉␉return (-1);␊ |
85 | ␉␉if (old__atexit != __atexit) {␊ |
86 | ␉␉␉/* Lost race, retry operation */␊ |
87 | ␉␉␉free(p);␊ |
88 | ␉␉␉p = __atexit;␊ |
89 | ␉␉␉continue;␊ |
90 | ␉␉}␊ |
91 | ␉␉p->ind = 0;␊ |
92 | ␉␉p->next = __atexit;␊ |
93 | ␉␉__atexit = p;␊ |
94 | ␉}␊ |
95 | ␉p->fns[p->ind++] = *fptr;␊ |
96 | ␉new_registration = 1;␊ |
97 | ␉return 0;␊ |
98 | }␊ |
99 | ␊ |
100 | /*␊ |
101 | * Register a function to be performed at exit.␊ |
102 | */␊ |
103 | int␊ |
104 | atexit(void (*func)(void))␊ |
105 | {␊ |
106 | ␉struct atexit_fn fn;␊ |
107 | ␉//struct dl_info info; ??␊ |
108 | ␉int error;␊ |
109 | ␊ |
110 | ␉fn.fn_type = ATEXIT_FN_STD;␊ |
111 | ␉fn.fn_ptr.std_func = func;␊ |
112 | ␉fn.fn_arg = NULL;␊ |
113 | ␉fn.fn_dso = NULL;␊ |
114 | ␊ |
115 | ␉error = atexit_register(&fn);␉␊ |
116 | ␉return (error);␊ |
117 | }␊ |
118 | ␊ |
119 | /*␊ |
120 | * Register a function to be performed at exit or when an shared object␊ |
121 | * with given dso handle is unloaded dynamically.␊ |
122 | */␊ |
123 | int␊ |
124 | __cxa_atexit(void (*func)(void *), void *arg, void *dso)␊ |
125 | {␊ |
126 | ␉struct atexit_fn fn;␊ |
127 | ␉int error;␊ |
128 | ␊ |
129 | ␉fn.fn_type = ATEXIT_FN_CXA;␊ |
130 | ␉fn.fn_ptr.cxa_func = func;;␊ |
131 | ␉fn.fn_arg = arg;␊ |
132 | ␉fn.fn_dso = dso;␊ |
133 | ␊ |
134 | ␉error = atexit_register(&fn);␉␊ |
135 | ␉return (error);␊ |
136 | }␊ |
137 | ␊ |
138 | /*␊ |
139 | * Call all handlers registered with __cxa_atexit for the shared␊ |
140 | * object owning 'dso'. Note: if 'dso' is NULL, then all remaining␊ |
141 | * handlers are called.␊ |
142 | */␊ |
143 | void␊ |
144 | __cxa_finalize(const void *dso)␊ |
145 | {␊ |
146 | ␉struct atexit *p;␊ |
147 | ␉struct atexit_fn fn;␊ |
148 | ␉int n;␊ |
149 | ␊ |
150 | restart:␊ |
151 | ␉for (p = __atexit; p; p = p->next) {␊ |
152 | ␉␉for (n = p->ind; --n >= 0;) {␊ |
153 | ␉␉␉if (p->fns[n].fn_type == ATEXIT_FN_EMPTY)␊ |
154 | ␉␉␉␉continue; /* already been called */␊ |
155 | ␉␉␉if (dso != NULL && dso != p->fns[n].fn_dso)␊ |
156 | ␉␉␉␉continue; /* wrong DSO */␊ |
157 | ␉␉␉fn = p->fns[n];␊ |
158 | ␉␉␉/*␊ |
159 | ␉␉␉ Mark entry to indicate that this particular handler␊ |
160 | ␉␉␉ has already been called.␊ |
161 | ␉␉␉*/␊ |
162 | ␉␉␉p->fns[n].fn_type = ATEXIT_FN_EMPTY;␊ |
163 | ␉␉␉new_registration = 0;␊ |
164 | ␉␉␊ |
165 | ␉␉␉/* Call the function of correct type. */␊ |
166 | ␉␉␉if (fn.fn_type == ATEXIT_FN_CXA)␊ |
167 | ␉␉␉␉fn.fn_ptr.cxa_func(fn.fn_arg);␊ |
168 | ␉␉␉else if (fn.fn_type == ATEXIT_FN_STD)␊ |
169 | ␉␉␉␉fn.fn_ptr.std_func();␊ |
170 | ␉␉␉if (new_registration)␊ |
171 | ␉␉␉ goto restart;␊ |
172 | ␉␉}␊ |
173 | ␉}␊ |
174 | }␊ |
175 | |