Home | History | Annotate | Download | only in gen
      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