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