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