Print this page
3849 implement __cxa_atexit/__cxa_finalize
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libc/port/gen/atexit.c
+++ new/usr/src/lib/libc/port/gen/atexit.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /* Copyright (c) 1988 AT&T */
28 28 /* All Rights Reserved */
29 29
30 30 #pragma weak _atexit = atexit
31 31
32 32 #include "lint.h"
33 33 #include "thr_uberdata.h"
34 34 #include "libc_int.h"
35 35 #include "atexit.h"
36 36 #include "stdiom.h"
37 37
38 38 /*
39 39 * Note that memory is managed by lmalloc()/lfree().
40 40 *
41 41 * Among other reasons, this is occasioned by the insistence of our
42 42 * brothers sh(1) and csh(1) that they can do malloc, etc., better than
43 43 * libc can. Those programs define their own malloc routines, and
44 44 * initialize the underlying mechanism in main(). This means that calls
↓ open down ↓ |
44 lines elided |
↑ open up ↑ |
45 45 * to malloc occuring before main will crash. The loader calls atexit(3C)
46 46 * before calling main, so we'd better avoid malloc() when it does.
47 47 *
48 48 * Another reason for using lmalloc()/lfree() is that the atexit()
49 49 * list must transcend all link maps. See the Linker and Libraries
50 50 * Guide for information on alternate link maps.
51 51 *
52 52 * See "thr_uberdata.h" for the definitions of structures used here.
53 53 */
54 54
55 -static int in_range(_exithdlr_func_t, Lc_addr_range_t[], uint_t count);
55 +static int in_range(void *, Lc_addr_range_t[], uint_t count);
56 56
57 57 extern caddr_t _getfp(void);
58 58
59 59 /*
60 60 * exitfns_lock is declared to be a recursive mutex so that we
61 61 * can hold it while calling out to the registered functions.
62 62 * If they call back to us, we are self-consistent and everything
63 63 * works, even the case of calling exit() from functions called
64 64 * by _exithandle() (recursive exit()). All that is required is
65 65 * that the registered functions actually return (no longjmp()s).
66 66 *
67 67 * Because exitfns_lock is declared to be a recursive mutex, we
68 68 * cannot use it with lmutex_lock()/lmutex_unlock() and we must
69 69 * use mutex_lock()/mutex_unlock(). This means that atexit()
70 70 * and exit() are not async-signal-safe. We make them fork1-safe
71 71 * via the atexit_locks()/atexit_unlocks() functions, called from
72 72 * libc_prepare_atfork()/libc_child_atfork()/libc_parent_atfork()
73 73 */
74 74
75 75 /*
76 76 * atexit_locks() and atexit_unlocks() are called on every link map.
77 77 * Do not use curthread->ul_uberdata->atexit_root for these.
78 78 */
79 79 void
80 80 atexit_locks()
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
81 81 {
82 82 (void) mutex_lock(&__uberdata.atexit_root.exitfns_lock);
83 83 }
84 84
85 85 void
86 86 atexit_unlocks()
87 87 {
88 88 (void) mutex_unlock(&__uberdata.atexit_root.exitfns_lock);
89 89 }
90 90
91 +
91 92 /*
92 93 * atexit() is called before the primordial thread is fully set up.
93 94 * Be careful about dereferencing self->ul_uberdata->atexit_root.
94 95 */
95 96 int
96 -atexit(void (*func)(void))
97 +__cxa_atexit(void (*hdlr)(void *), void *arg, void *dso)
97 98 {
98 99 ulwp_t *self;
99 100 atexit_root_t *arp;
100 101 _exthdlr_t *p;
101 102
102 103 if ((p = lmalloc(sizeof (_exthdlr_t))) == NULL)
103 104 return (-1);
104 105
105 106 if ((self = __curthread()) == NULL)
106 107 arp = &__uberdata.atexit_root;
107 108 else {
108 109 arp = &self->ul_uberdata->atexit_root;
109 110 (void) mutex_lock(&arp->exitfns_lock);
110 111 }
111 - p->hdlr = func;
112 + p->hdlr = hdlr;
113 + p->arg = arg;
114 + p->dso = dso;
112 115 p->next = arp->head;
113 116 arp->head = p;
117 +
114 118 if (self != NULL)
115 119 (void) mutex_unlock(&arp->exitfns_lock);
116 120 return (0);
117 121 }
118 122
123 +int
124 +atexit(void (*func)(void))
125 +{
126 + return (__cxa_atexit((_exithdlr_func_t)func, NULL, NULL));
127 +}
128 +
129 +/*
130 + * Note that we may be entered recursively, as we'll call __cxa_finalize(0) at
131 + * exit, one of our handlers is ld.so.1`atexit_fini, and libraries may call
132 + * __cxa_finalize(__dso_handle) from their _fini.
133 + */
119 134 void
120 -_exithandle(void)
135 +__cxa_finalize(void *dso)
121 136 {
122 137 atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
123 - _exthdlr_t *p;
138 + _exthdlr_t *p, *o;
124 139 int cancel_state;
125 140
126 141 /* disable cancellation while running atexit handlers */
127 142 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
128 143 (void) mutex_lock(&arp->exitfns_lock);
129 - arp->exit_frame_monitor = _getfp() + STACK_BIAS;
144 +
145 + o = NULL;
130 146 p = arp->head;
131 147 while (p != NULL) {
132 - arp->head = p->next;
133 - p->hdlr();
134 - lfree(p, sizeof (_exthdlr_t));
135 - p = arp->head;
148 + if ((dso == NULL) || (p->dso == dso)) {
149 + if (o != NULL)
150 + o->next = p->next;
151 + else
152 + arp->head = p->next;
153 +
154 + p->hdlr(p->arg);
155 + lfree(p, sizeof (_exthdlr_t));
156 + o = NULL;
157 + p = arp->head;
158 + } else {
159 + o = p;
160 + p = p->next;
161 + }
136 162 }
163 +
137 164 (void) mutex_unlock(&arp->exitfns_lock);
138 165 (void) pthread_setcancelstate(cancel_state, NULL);
139 166 }
140 167
168 +void
169 +_exithandle(void)
170 +{
171 + atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
172 +
173 + arp->exit_frame_monitor = _getfp() + STACK_BIAS;
174 + __cxa_finalize(NULL);
175 +}
176 +
141 177 /*
142 178 * _get_exit_frame_monitor is called by the C++ runtimes.
143 179 */
144 180 void *
145 181 _get_exit_frame_monitor(void)
146 182 {
147 183 atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
148 184 return (&arp->exit_frame_monitor);
149 185 }
150 186
151 187 /*
152 188 * The following is a routine which the loader (ld.so.1) calls when it
153 189 * processes a dlclose call on an object. It resets all signal handlers
154 190 * which fall within the union of the ranges specified by the elements
155 191 * of the array range to SIG_DFL.
156 192 */
157 193 static void
158 194 _preexec_sig_unload(Lc_addr_range_t range[], uint_t count)
159 195 {
160 196 uberdata_t *udp = curthread->ul_uberdata;
161 197 int sig;
↓ open down ↓ |
11 lines elided |
↑ open up ↑ |
162 198 rwlock_t *rwlp;
163 199 struct sigaction *sap;
164 200 struct sigaction oact;
165 201 void (*handler)();
166 202
167 203 for (sig = 1; sig < NSIG; sig++) {
168 204 sap = (struct sigaction *)&udp->siguaction[sig].sig_uaction;
169 205 again:
170 206 handler = sap->sa_handler;
171 207 if (handler != SIG_DFL && handler != SIG_IGN &&
172 - in_range(handler, range, count)) {
208 + in_range((void *)handler, range, count)) {
173 209 rwlp = &udp->siguaction[sig].sig_lock;
174 210 lrw_wrlock(rwlp);
175 211 if (handler != sap->sa_handler) {
176 212 lrw_unlock(rwlp);
177 213 goto again;
178 214 }
179 215 sap->sa_handler = SIG_DFL;
180 216 sap->sa_flags = SA_SIGINFO;
181 217 (void) sigemptyset(&sap->sa_mask);
182 218 if (__sigaction(sig, NULL, &oact) == 0 &&
183 219 oact.sa_handler != SIG_DFL &&
184 220 oact.sa_handler != SIG_IGN)
185 221 (void) __sigaction(sig, sap, NULL);
186 222 lrw_unlock(rwlp);
187 223 }
188 224 }
189 225 }
190 226
191 227 /*
192 228 * The following is a routine which the loader (ld.so.1) calls when it
193 229 * processes a dlclose call on an object. It cancels all atfork() entries
194 230 * whose prefork, parent postfork, or child postfork functions fall within
195 231 * the union of the ranges specified by the elements of the array range.
196 232 */
197 233 static void
198 234 _preexec_atfork_unload(Lc_addr_range_t range[], uint_t count)
199 235 {
200 236 ulwp_t *self = curthread;
201 237 uberdata_t *udp = self->ul_uberdata;
202 238 atfork_t *atfork_q;
203 239 atfork_t *atfp;
204 240 atfork_t *next;
205 241 void (*func)(void);
↓ open down ↓ |
23 lines elided |
↑ open up ↑ |
206 242 int start_again;
207 243
208 244 (void) mutex_lock(&udp->atfork_lock);
209 245 if ((atfork_q = udp->atforklist) != NULL) {
210 246 atfp = atfork_q;
211 247 do {
212 248 next = atfp->forw;
213 249 start_again = 0;
214 250
215 251 if (((func = atfp->prepare) != NULL &&
216 - in_range(func, range, count)) ||
252 + in_range((void *)func, range, count)) ||
217 253 ((func = atfp->parent) != NULL &&
218 - in_range(func, range, count)) ||
254 + in_range((void *)func, range, count)) ||
219 255 ((func = atfp->child) != NULL &&
220 - in_range(func, range, count))) {
256 + in_range((void *)func, range, count))) {
221 257 if (self->ul_fork) {
222 258 /*
223 259 * dlclose() called from a fork handler.
224 260 * Deleting the entry would wreak havoc.
225 261 * Just null out the function pointers
226 262 * and leave the entry in place.
227 263 */
228 264 atfp->prepare = NULL;
229 265 atfp->parent = NULL;
230 266 atfp->child = NULL;
231 267 continue;
232 268 }
233 269 if (atfp == atfork_q) {
234 270 /* deleting the list head member */
235 271 udp->atforklist = atfork_q = next;
236 272 start_again = 1;
237 273 }
238 274 atfp->forw->back = atfp->back;
239 275 atfp->back->forw = atfp->forw;
240 276 lfree(atfp, sizeof (atfork_t));
241 277 if (atfp == atfork_q) {
242 278 /* we deleted the whole list */
243 279 udp->atforklist = NULL;
244 280 break;
245 281 }
246 282 }
247 283 } while ((atfp = next) != atfork_q || start_again);
248 284 }
249 285 (void) mutex_unlock(&udp->atfork_lock);
250 286 }
251 287
252 288 /*
253 289 * The following is a routine which the loader (ld.so.1) calls when it
254 290 * processes a dlclose call on an object. It sets the destructor
255 291 * function pointer to NULL for all keys whose destructors fall within
256 292 * the union of the ranges specified by the elements of the array range.
257 293 * We don't assign TSD_UNALLOCATED (the equivalent of pthread_key_destroy())
258 294 * because the thread may use the key's TSD further on in fini processing.
259 295 */
260 296 static void
↓ open down ↓ |
30 lines elided |
↑ open up ↑ |
261 297 _preexec_tsd_unload(Lc_addr_range_t range[], uint_t count)
262 298 {
263 299 tsd_metadata_t *tsdm = &curthread->ul_uberdata->tsd_metadata;
264 300 void (*func)(void *);
265 301 int key;
266 302
267 303 lmutex_lock(&tsdm->tsdm_lock);
268 304 for (key = 1; key < tsdm->tsdm_nused; key++) {
269 305 if ((func = tsdm->tsdm_destro[key]) != NULL &&
270 306 func != TSD_UNALLOCATED &&
271 - in_range((_exithdlr_func_t)func, range, count))
307 + in_range((void *)func, range, count))
272 308 tsdm->tsdm_destro[key] = NULL;
273 309 }
274 310 lmutex_unlock(&tsdm->tsdm_lock);
275 311 }
276 312
277 313 /*
278 314 * The following is a routine which the loader (ld.so.1) calls when it
279 315 * processes dlclose calls on objects with atexit registrations. It
280 316 * executes the exit handlers that fall within the union of the ranges
281 317 * specified by the elements of the array range in the REVERSE ORDER of
282 318 * their registration. Do not change this characteristic; it is REQUIRED
283 319 * BEHAVIOR.
284 320 */
285 321 int
286 322 _preexec_exit_handlers(Lc_addr_range_t range[], uint_t count)
287 323 {
288 324 atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
289 325 _exthdlr_t *o; /* previous node */
290 326 _exthdlr_t *p; /* this node */
291 327 int cancel_state;
292 328
293 329 /* disable cancellation while running atexit handlers */
294 330 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
295 331 (void) mutex_lock(&arp->exitfns_lock);
296 332 o = NULL;
297 333 p = arp->head;
298 334 while (p != NULL) {
299 - if (in_range(p->hdlr, range, count)) {
335 + /*
336 + * We call even CXA handlers of functions present in the
337 + * library being unloaded. The specification isn't
338 + * particularly clear on this, and this seems the most sane.
339 + * This is the behaviour of FreeBSD 9.1 (GNU libc leaves the
340 + * handler on the exit list, and crashes at exit time).
341 + *
342 + * This won't cause handlers to be called twice, because
343 + * anything called from a __cxa_finalize call from the
344 + * language runtime will have been removed from the list.
345 + */
346 + if (in_range((void *)p->hdlr, range, count)) {
300 347 /* We need to execute this one */
301 348 if (o != NULL)
302 349 o->next = p->next;
303 350 else
304 351 arp->head = p->next;
305 - p->hdlr();
352 + p->hdlr(p->arg);
306 353 lfree(p, sizeof (_exthdlr_t));
307 354 o = NULL;
308 355 p = arp->head;
309 356 } else {
310 357 o = p;
311 358 p = p->next;
312 359 }
313 360 }
314 361 (void) mutex_unlock(&arp->exitfns_lock);
315 362 (void) pthread_setcancelstate(cancel_state, NULL);
316 363
317 364 _preexec_tsd_unload(range, count);
318 365 _preexec_atfork_unload(range, count);
319 366 _preexec_sig_unload(range, count);
320 367
321 368 return (0);
322 369 }
323 370
324 371 static int
325 -in_range(_exithdlr_func_t addr, Lc_addr_range_t ranges[], uint_t count)
372 +in_range(void *addr, Lc_addr_range_t ranges[], uint_t count)
326 373 {
327 374 uint_t idx;
328 375
329 376 for (idx = 0; idx < count; idx++) {
330 - if ((void *)addr >= ranges[idx].lb &&
331 - (void *)addr < ranges[idx].ub) {
377 + if (addr >= ranges[idx].lb &&
378 + addr < ranges[idx].ub) {
332 379 return (1);
333 380 }
334 381 }
335 382
336 383 return (0);
337 384 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX