17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the
541efec22Sraf * Common Development and Distribution License (the "License").
641efec22Sraf * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
21e8031f0aSraf
227c478bd9Sstevel@tonic-gate /*
23a574db85Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
25*dcdfe824SRobert Mustacchi *
26*dcdfe824SRobert Mustacchi * Copyright 2016 Joyent, Inc.
277c478bd9Sstevel@tonic-gate */
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */
307c478bd9Sstevel@tonic-gate /* All Rights Reserved */
317c478bd9Sstevel@tonic-gate
327257d1b4Sraf #pragma weak _atexit = atexit
337257d1b4Sraf
347257d1b4Sraf #include "lint.h"
357c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
367c478bd9Sstevel@tonic-gate #include "libc_int.h"
377c478bd9Sstevel@tonic-gate #include "atexit.h"
387c478bd9Sstevel@tonic-gate #include "stdiom.h"
397c478bd9Sstevel@tonic-gate
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate * Note that memory is managed by lmalloc()/lfree().
427c478bd9Sstevel@tonic-gate *
437c478bd9Sstevel@tonic-gate * Among other reasons, this is occasioned by the insistence of our
447c478bd9Sstevel@tonic-gate * brothers sh(1) and csh(1) that they can do malloc, etc., better than
457c478bd9Sstevel@tonic-gate * libc can. Those programs define their own malloc routines, and
467c478bd9Sstevel@tonic-gate * initialize the underlying mechanism in main(). This means that calls
477c478bd9Sstevel@tonic-gate * to malloc occuring before main will crash. The loader calls atexit(3C)
487c478bd9Sstevel@tonic-gate * before calling main, so we'd better avoid malloc() when it does.
497c478bd9Sstevel@tonic-gate *
507c478bd9Sstevel@tonic-gate * Another reason for using lmalloc()/lfree() is that the atexit()
517c478bd9Sstevel@tonic-gate * list must transcend all link maps. See the Linker and Libraries
527c478bd9Sstevel@tonic-gate * Guide for information on alternate link maps.
537c478bd9Sstevel@tonic-gate *
547c478bd9Sstevel@tonic-gate * See "thr_uberdata.h" for the definitions of structures used here.
557c478bd9Sstevel@tonic-gate */
567c478bd9Sstevel@tonic-gate
575c069a6cSRichard Lowe static int in_range(void *, Lc_addr_range_t[], uint_t count);
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate extern caddr_t _getfp(void);
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate * exitfns_lock is declared to be a recursive mutex so that we
637c478bd9Sstevel@tonic-gate * can hold it while calling out to the registered functions.
647c478bd9Sstevel@tonic-gate * If they call back to us, we are self-consistent and everything
657c478bd9Sstevel@tonic-gate * works, even the case of calling exit() from functions called
667c478bd9Sstevel@tonic-gate * by _exithandle() (recursive exit()). All that is required is
677c478bd9Sstevel@tonic-gate * that the registered functions actually return (no longjmp()s).
687c478bd9Sstevel@tonic-gate *
697c478bd9Sstevel@tonic-gate * Because exitfns_lock is declared to be a recursive mutex, we
70a574db85Sraf * cannot use it with lmutex_lock()/lmutex_unlock() and we must
71a574db85Sraf * use mutex_lock()/mutex_unlock(). This means that atexit()
72a574db85Sraf * and exit() are not async-signal-safe. We make them fork1-safe
737c478bd9Sstevel@tonic-gate * via the atexit_locks()/atexit_unlocks() functions, called from
747c478bd9Sstevel@tonic-gate * libc_prepare_atfork()/libc_child_atfork()/libc_parent_atfork()
757c478bd9Sstevel@tonic-gate */
767c478bd9Sstevel@tonic-gate
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate * atexit_locks() and atexit_unlocks() are called on every link map.
797c478bd9Sstevel@tonic-gate * Do not use curthread->ul_uberdata->atexit_root for these.
807c478bd9Sstevel@tonic-gate */
817c478bd9Sstevel@tonic-gate void
atexit_locks()827c478bd9Sstevel@tonic-gate atexit_locks()
837c478bd9Sstevel@tonic-gate {
848cd45542Sraf (void) mutex_lock(&__uberdata.atexit_root.exitfns_lock);
85*dcdfe824SRobert Mustacchi (void) mutex_lock(&__uberdata.quickexit_root.exitfns_lock);
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate
887c478bd9Sstevel@tonic-gate void
atexit_unlocks()897c478bd9Sstevel@tonic-gate atexit_unlocks()
907c478bd9Sstevel@tonic-gate {
91*dcdfe824SRobert Mustacchi (void) mutex_unlock(&__uberdata.quickexit_root.exitfns_lock);
928cd45542Sraf (void) mutex_unlock(&__uberdata.atexit_root.exitfns_lock);
937c478bd9Sstevel@tonic-gate }
947c478bd9Sstevel@tonic-gate
955c069a6cSRichard Lowe
967c478bd9Sstevel@tonic-gate /*
975c069a6cSRichard Lowe * This is called via atexit() before the primordial thread is fully set up.
987c478bd9Sstevel@tonic-gate * Be careful about dereferencing self->ul_uberdata->atexit_root.
997c478bd9Sstevel@tonic-gate */
1007c478bd9Sstevel@tonic-gate int
__cxa_atexit(void (* hdlr)(void *),void * arg,void * dso)1015c069a6cSRichard Lowe __cxa_atexit(void (*hdlr)(void *), void *arg, void *dso)
1027c478bd9Sstevel@tonic-gate {
1037c478bd9Sstevel@tonic-gate ulwp_t *self;
1047c478bd9Sstevel@tonic-gate atexit_root_t *arp;
1057c478bd9Sstevel@tonic-gate _exthdlr_t *p;
1067c478bd9Sstevel@tonic-gate
1077c478bd9Sstevel@tonic-gate if ((p = lmalloc(sizeof (_exthdlr_t))) == NULL)
1087c478bd9Sstevel@tonic-gate return (-1);
1097c478bd9Sstevel@tonic-gate
1107c478bd9Sstevel@tonic-gate if ((self = __curthread()) == NULL)
1117c478bd9Sstevel@tonic-gate arp = &__uberdata.atexit_root;
1127c478bd9Sstevel@tonic-gate else {
1137c478bd9Sstevel@tonic-gate arp = &self->ul_uberdata->atexit_root;
1148cd45542Sraf (void) mutex_lock(&arp->exitfns_lock);
1157c478bd9Sstevel@tonic-gate }
1165c069a6cSRichard Lowe p->hdlr = hdlr;
1175c069a6cSRichard Lowe p->arg = arg;
1185c069a6cSRichard Lowe p->dso = dso;
1197c478bd9Sstevel@tonic-gate p->next = arp->head;
1207c478bd9Sstevel@tonic-gate arp->head = p;
1215c069a6cSRichard Lowe
1227c478bd9Sstevel@tonic-gate if (self != NULL)
1238cd45542Sraf (void) mutex_unlock(&arp->exitfns_lock);
1247c478bd9Sstevel@tonic-gate return (0);
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate
1275c069a6cSRichard Lowe int
atexit(void (* func)(void))1285c069a6cSRichard Lowe atexit(void (*func)(void))
1295c069a6cSRichard Lowe {
1305c069a6cSRichard Lowe return (__cxa_atexit((_exithdlr_func_t)func, NULL, NULL));
1315c069a6cSRichard Lowe }
1325c069a6cSRichard Lowe
1335c069a6cSRichard Lowe /*
1345c069a6cSRichard Lowe * Note that we may be entered recursively, as we'll call __cxa_finalize(0) at
1355c069a6cSRichard Lowe * exit, one of our handlers is ld.so.1`atexit_fini, and libraries may call
1365c069a6cSRichard Lowe * __cxa_finalize(__dso_handle) from their _fini.
1375c069a6cSRichard Lowe */
1385c069a6cSRichard Lowe void
__cxa_finalize(void * dso)1395c069a6cSRichard Lowe __cxa_finalize(void *dso)
1405c069a6cSRichard Lowe {
1415c069a6cSRichard Lowe atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
1425c069a6cSRichard Lowe _exthdlr_t *p, *o;
1435c069a6cSRichard Lowe int cancel_state;
1445c069a6cSRichard Lowe
1455c069a6cSRichard Lowe /* disable cancellation while running atexit handlers */
1465c069a6cSRichard Lowe (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
1475c069a6cSRichard Lowe (void) mutex_lock(&arp->exitfns_lock);
1485c069a6cSRichard Lowe
1495c069a6cSRichard Lowe o = NULL;
1505c069a6cSRichard Lowe p = arp->head;
1515c069a6cSRichard Lowe while (p != NULL) {
1525c069a6cSRichard Lowe if ((dso == NULL) || (p->dso == dso)) {
1535c069a6cSRichard Lowe if (o != NULL)
1545c069a6cSRichard Lowe o->next = p->next;
1555c069a6cSRichard Lowe else
1565c069a6cSRichard Lowe arp->head = p->next;
1575c069a6cSRichard Lowe
1585c069a6cSRichard Lowe p->hdlr(p->arg);
1595c069a6cSRichard Lowe lfree(p, sizeof (_exthdlr_t));
1605c069a6cSRichard Lowe o = NULL;
1615c069a6cSRichard Lowe p = arp->head;
1625c069a6cSRichard Lowe } else {
1635c069a6cSRichard Lowe o = p;
1645c069a6cSRichard Lowe p = p->next;
1655c069a6cSRichard Lowe }
1665c069a6cSRichard Lowe }
1675c069a6cSRichard Lowe
1685c069a6cSRichard Lowe (void) mutex_unlock(&arp->exitfns_lock);
1695c069a6cSRichard Lowe (void) pthread_setcancelstate(cancel_state, NULL);
1705c069a6cSRichard Lowe }
1715c069a6cSRichard Lowe
1727c478bd9Sstevel@tonic-gate void
_exithandle(void)1737c478bd9Sstevel@tonic-gate _exithandle(void)
1747c478bd9Sstevel@tonic-gate {
1757c478bd9Sstevel@tonic-gate atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
1767c478bd9Sstevel@tonic-gate
1777c478bd9Sstevel@tonic-gate arp->exit_frame_monitor = _getfp() + STACK_BIAS;
1785c069a6cSRichard Lowe __cxa_finalize(NULL);
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate * _get_exit_frame_monitor is called by the C++ runtimes.
1837c478bd9Sstevel@tonic-gate */
1847c478bd9Sstevel@tonic-gate void *
_get_exit_frame_monitor(void)1857c478bd9Sstevel@tonic-gate _get_exit_frame_monitor(void)
1867c478bd9Sstevel@tonic-gate {
1877c478bd9Sstevel@tonic-gate atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
1887c478bd9Sstevel@tonic-gate return (&arp->exit_frame_monitor);
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate /*
1927c478bd9Sstevel@tonic-gate * The following is a routine which the loader (ld.so.1) calls when it
1937c478bd9Sstevel@tonic-gate * processes a dlclose call on an object. It resets all signal handlers
1947c478bd9Sstevel@tonic-gate * which fall within the union of the ranges specified by the elements
1957c478bd9Sstevel@tonic-gate * of the array range to SIG_DFL.
1967c478bd9Sstevel@tonic-gate */
1977c478bd9Sstevel@tonic-gate static void
_preexec_sig_unload(Lc_addr_range_t range[],uint_t count)1987c478bd9Sstevel@tonic-gate _preexec_sig_unload(Lc_addr_range_t range[], uint_t count)
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate uberdata_t *udp = curthread->ul_uberdata;
2017c478bd9Sstevel@tonic-gate int sig;
20241efec22Sraf rwlock_t *rwlp;
2037c478bd9Sstevel@tonic-gate struct sigaction *sap;
2047c478bd9Sstevel@tonic-gate struct sigaction oact;
2057c478bd9Sstevel@tonic-gate void (*handler)();
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate for (sig = 1; sig < NSIG; sig++) {
2087c478bd9Sstevel@tonic-gate sap = (struct sigaction *)&udp->siguaction[sig].sig_uaction;
2097c478bd9Sstevel@tonic-gate again:
2107c478bd9Sstevel@tonic-gate handler = sap->sa_handler;
2117c478bd9Sstevel@tonic-gate if (handler != SIG_DFL && handler != SIG_IGN &&
2125c069a6cSRichard Lowe in_range((void *)handler, range, count)) {
21341efec22Sraf rwlp = &udp->siguaction[sig].sig_lock;
21441efec22Sraf lrw_wrlock(rwlp);
2157c478bd9Sstevel@tonic-gate if (handler != sap->sa_handler) {
21641efec22Sraf lrw_unlock(rwlp);
2177c478bd9Sstevel@tonic-gate goto again;
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate sap->sa_handler = SIG_DFL;
2207c478bd9Sstevel@tonic-gate sap->sa_flags = SA_SIGINFO;
2217c478bd9Sstevel@tonic-gate (void) sigemptyset(&sap->sa_mask);
2227c478bd9Sstevel@tonic-gate if (__sigaction(sig, NULL, &oact) == 0 &&
2237c478bd9Sstevel@tonic-gate oact.sa_handler != SIG_DFL &&
2247c478bd9Sstevel@tonic-gate oact.sa_handler != SIG_IGN)
2257c478bd9Sstevel@tonic-gate (void) __sigaction(sig, sap, NULL);
22641efec22Sraf lrw_unlock(rwlp);
2277c478bd9Sstevel@tonic-gate }
2287c478bd9Sstevel@tonic-gate }
2297c478bd9Sstevel@tonic-gate }
2307c478bd9Sstevel@tonic-gate
2317c478bd9Sstevel@tonic-gate /*
2327c478bd9Sstevel@tonic-gate * The following is a routine which the loader (ld.so.1) calls when it
2337c478bd9Sstevel@tonic-gate * processes a dlclose call on an object. It cancels all atfork() entries
2347c478bd9Sstevel@tonic-gate * whose prefork, parent postfork, or child postfork functions fall within
2357c478bd9Sstevel@tonic-gate * the union of the ranges specified by the elements of the array range.
2367c478bd9Sstevel@tonic-gate */
2377c478bd9Sstevel@tonic-gate static void
_preexec_atfork_unload(Lc_addr_range_t range[],uint_t count)2387c478bd9Sstevel@tonic-gate _preexec_atfork_unload(Lc_addr_range_t range[], uint_t count)
2397c478bd9Sstevel@tonic-gate {
2402e145884Sraf ulwp_t *self = curthread;
2412e145884Sraf uberdata_t *udp = self->ul_uberdata;
2427c478bd9Sstevel@tonic-gate atfork_t *atfork_q;
2437c478bd9Sstevel@tonic-gate atfork_t *atfp;
2447c478bd9Sstevel@tonic-gate atfork_t *next;
2457c478bd9Sstevel@tonic-gate void (*func)(void);
2467c478bd9Sstevel@tonic-gate int start_again;
2477c478bd9Sstevel@tonic-gate
2488cd45542Sraf (void) mutex_lock(&udp->atfork_lock);
2497c478bd9Sstevel@tonic-gate if ((atfork_q = udp->atforklist) != NULL) {
2507c478bd9Sstevel@tonic-gate atfp = atfork_q;
2517c478bd9Sstevel@tonic-gate do {
2527c478bd9Sstevel@tonic-gate next = atfp->forw;
2537c478bd9Sstevel@tonic-gate start_again = 0;
2547c478bd9Sstevel@tonic-gate
2557c478bd9Sstevel@tonic-gate if (((func = atfp->prepare) != NULL &&
2565c069a6cSRichard Lowe in_range((void *)func, range, count)) ||
2577c478bd9Sstevel@tonic-gate ((func = atfp->parent) != NULL &&
2585c069a6cSRichard Lowe in_range((void *)func, range, count)) ||
2597c478bd9Sstevel@tonic-gate ((func = atfp->child) != NULL &&
2605c069a6cSRichard Lowe in_range((void *)func, range, count))) {
2612e145884Sraf if (self->ul_fork) {
2627c478bd9Sstevel@tonic-gate /*
2637c478bd9Sstevel@tonic-gate * dlclose() called from a fork handler.
2647c478bd9Sstevel@tonic-gate * Deleting the entry would wreak havoc.
2657c478bd9Sstevel@tonic-gate * Just null out the function pointers
2667c478bd9Sstevel@tonic-gate * and leave the entry in place.
2677c478bd9Sstevel@tonic-gate */
2687c478bd9Sstevel@tonic-gate atfp->prepare = NULL;
2697c478bd9Sstevel@tonic-gate atfp->parent = NULL;
2707c478bd9Sstevel@tonic-gate atfp->child = NULL;
2717c478bd9Sstevel@tonic-gate continue;
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate if (atfp == atfork_q) {
2747c478bd9Sstevel@tonic-gate /* deleting the list head member */
2757c478bd9Sstevel@tonic-gate udp->atforklist = atfork_q = next;
2767c478bd9Sstevel@tonic-gate start_again = 1;
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate atfp->forw->back = atfp->back;
2797c478bd9Sstevel@tonic-gate atfp->back->forw = atfp->forw;
2807c478bd9Sstevel@tonic-gate lfree(atfp, sizeof (atfork_t));
2817c478bd9Sstevel@tonic-gate if (atfp == atfork_q) {
2827c478bd9Sstevel@tonic-gate /* we deleted the whole list */
2837c478bd9Sstevel@tonic-gate udp->atforklist = NULL;
2847c478bd9Sstevel@tonic-gate break;
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate } while ((atfp = next) != atfork_q || start_again);
2887c478bd9Sstevel@tonic-gate }
2898cd45542Sraf (void) mutex_unlock(&udp->atfork_lock);
2907c478bd9Sstevel@tonic-gate }
2917c478bd9Sstevel@tonic-gate
2927c478bd9Sstevel@tonic-gate /*
2937c478bd9Sstevel@tonic-gate * The following is a routine which the loader (ld.so.1) calls when it
2947c478bd9Sstevel@tonic-gate * processes a dlclose call on an object. It sets the destructor
2957c478bd9Sstevel@tonic-gate * function pointer to NULL for all keys whose destructors fall within
2967c478bd9Sstevel@tonic-gate * the union of the ranges specified by the elements of the array range.
2977c478bd9Sstevel@tonic-gate * We don't assign TSD_UNALLOCATED (the equivalent of pthread_key_destroy())
2987c478bd9Sstevel@tonic-gate * because the thread may use the key's TSD further on in fini processing.
2997c478bd9Sstevel@tonic-gate */
3007c478bd9Sstevel@tonic-gate static void
_preexec_tsd_unload(Lc_addr_range_t range[],uint_t count)3017c478bd9Sstevel@tonic-gate _preexec_tsd_unload(Lc_addr_range_t range[], uint_t count)
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate tsd_metadata_t *tsdm = &curthread->ul_uberdata->tsd_metadata;
3047c478bd9Sstevel@tonic-gate void (*func)(void *);
3057c478bd9Sstevel@tonic-gate int key;
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate lmutex_lock(&tsdm->tsdm_lock);
3087c478bd9Sstevel@tonic-gate for (key = 1; key < tsdm->tsdm_nused; key++) {
3097c478bd9Sstevel@tonic-gate if ((func = tsdm->tsdm_destro[key]) != NULL &&
3107c478bd9Sstevel@tonic-gate func != TSD_UNALLOCATED &&
3115c069a6cSRichard Lowe in_range((void *)func, range, count))
3127c478bd9Sstevel@tonic-gate tsdm->tsdm_destro[key] = NULL;
3137c478bd9Sstevel@tonic-gate }
3147c478bd9Sstevel@tonic-gate lmutex_unlock(&tsdm->tsdm_lock);
3157c478bd9Sstevel@tonic-gate }
3167c478bd9Sstevel@tonic-gate
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate * The following is a routine which the loader (ld.so.1) calls when it
3197c478bd9Sstevel@tonic-gate * processes dlclose calls on objects with atexit registrations. It
3207c478bd9Sstevel@tonic-gate * executes the exit handlers that fall within the union of the ranges
3217c478bd9Sstevel@tonic-gate * specified by the elements of the array range in the REVERSE ORDER of
3227c478bd9Sstevel@tonic-gate * their registration. Do not change this characteristic; it is REQUIRED
3237c478bd9Sstevel@tonic-gate * BEHAVIOR.
3247c478bd9Sstevel@tonic-gate */
3257c478bd9Sstevel@tonic-gate int
_preexec_exit_handlers(Lc_addr_range_t range[],uint_t count)3267c478bd9Sstevel@tonic-gate _preexec_exit_handlers(Lc_addr_range_t range[], uint_t count)
3277c478bd9Sstevel@tonic-gate {
3287c478bd9Sstevel@tonic-gate atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
3297c478bd9Sstevel@tonic-gate _exthdlr_t *o; /* previous node */
3307c478bd9Sstevel@tonic-gate _exthdlr_t *p; /* this node */
33158a67dd2SRoger A. Faulkner int cancel_state;
3327c478bd9Sstevel@tonic-gate
33358a67dd2SRoger A. Faulkner /* disable cancellation while running atexit handlers */
33458a67dd2SRoger A. Faulkner (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
3358cd45542Sraf (void) mutex_lock(&arp->exitfns_lock);
3367c478bd9Sstevel@tonic-gate o = NULL;
3377c478bd9Sstevel@tonic-gate p = arp->head;
3387c478bd9Sstevel@tonic-gate while (p != NULL) {
3395c069a6cSRichard Lowe /*
3405c069a6cSRichard Lowe * We call even CXA handlers of functions present in the
3415c069a6cSRichard Lowe * library being unloaded. The specification isn't
3425c069a6cSRichard Lowe * particularly clear on this, and this seems the most sane.
3435c069a6cSRichard Lowe * This is the behaviour of FreeBSD 9.1 (GNU libc leaves the
3445c069a6cSRichard Lowe * handler on the exit list, and crashes at exit time).
3455c069a6cSRichard Lowe *
3465c069a6cSRichard Lowe * This won't cause handlers to be called twice, because
3475c069a6cSRichard Lowe * anything called from a __cxa_finalize call from the
3485c069a6cSRichard Lowe * language runtime will have been removed from the list.
3495c069a6cSRichard Lowe */
3505c069a6cSRichard Lowe if (in_range((void *)p->hdlr, range, count)) {
3517c478bd9Sstevel@tonic-gate /* We need to execute this one */
3527c478bd9Sstevel@tonic-gate if (o != NULL)
3537c478bd9Sstevel@tonic-gate o->next = p->next;
3547c478bd9Sstevel@tonic-gate else
3557c478bd9Sstevel@tonic-gate arp->head = p->next;
3565c069a6cSRichard Lowe p->hdlr(p->arg);
3577c478bd9Sstevel@tonic-gate lfree(p, sizeof (_exthdlr_t));
3587c478bd9Sstevel@tonic-gate o = NULL;
3597c478bd9Sstevel@tonic-gate p = arp->head;
3607c478bd9Sstevel@tonic-gate } else {
3617c478bd9Sstevel@tonic-gate o = p;
3627c478bd9Sstevel@tonic-gate p = p->next;
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate }
3658cd45542Sraf (void) mutex_unlock(&arp->exitfns_lock);
36658a67dd2SRoger A. Faulkner (void) pthread_setcancelstate(cancel_state, NULL);
3677c478bd9Sstevel@tonic-gate
3687c478bd9Sstevel@tonic-gate _preexec_tsd_unload(range, count);
3697c478bd9Sstevel@tonic-gate _preexec_atfork_unload(range, count);
3707c478bd9Sstevel@tonic-gate _preexec_sig_unload(range, count);
3717c478bd9Sstevel@tonic-gate
3727c478bd9Sstevel@tonic-gate return (0);
3737c478bd9Sstevel@tonic-gate }
3747c478bd9Sstevel@tonic-gate
3757c478bd9Sstevel@tonic-gate static int
in_range(void * addr,Lc_addr_range_t ranges[],uint_t count)3765c069a6cSRichard Lowe in_range(void *addr, Lc_addr_range_t ranges[], uint_t count)
3777c478bd9Sstevel@tonic-gate {
3787c478bd9Sstevel@tonic-gate uint_t idx;
3797c478bd9Sstevel@tonic-gate
3807c478bd9Sstevel@tonic-gate for (idx = 0; idx < count; idx++) {
3815c069a6cSRichard Lowe if (addr >= ranges[idx].lb &&
3825c069a6cSRichard Lowe addr < ranges[idx].ub) {
3837c478bd9Sstevel@tonic-gate return (1);
3847c478bd9Sstevel@tonic-gate }
3857c478bd9Sstevel@tonic-gate }
3867c478bd9Sstevel@tonic-gate
3877c478bd9Sstevel@tonic-gate return (0);
3887c478bd9Sstevel@tonic-gate }
389*dcdfe824SRobert Mustacchi
390*dcdfe824SRobert Mustacchi int
at_quick_exit(void (* func)(void))391*dcdfe824SRobert Mustacchi at_quick_exit(void (*func)(void))
392*dcdfe824SRobert Mustacchi {
393*dcdfe824SRobert Mustacchi ulwp_t *self;
394*dcdfe824SRobert Mustacchi quickexit_root_t *arp;
395*dcdfe824SRobert Mustacchi _qexthdlr_t *p;
396*dcdfe824SRobert Mustacchi
397*dcdfe824SRobert Mustacchi if ((p = lmalloc(sizeof (_qexthdlr_t))) == NULL)
398*dcdfe824SRobert Mustacchi return (-1);
399*dcdfe824SRobert Mustacchi
400*dcdfe824SRobert Mustacchi if ((self = __curthread()) == NULL) {
401*dcdfe824SRobert Mustacchi arp = &__uberdata.quickexit_root;
402*dcdfe824SRobert Mustacchi } else {
403*dcdfe824SRobert Mustacchi arp = &self->ul_uberdata->quickexit_root;
404*dcdfe824SRobert Mustacchi (void) mutex_lock(&arp->exitfns_lock);
405*dcdfe824SRobert Mustacchi }
406*dcdfe824SRobert Mustacchi p->hdlr = func;
407*dcdfe824SRobert Mustacchi p->next = arp->head;
408*dcdfe824SRobert Mustacchi arp->head = p;
409*dcdfe824SRobert Mustacchi
410*dcdfe824SRobert Mustacchi if (self != NULL)
411*dcdfe824SRobert Mustacchi (void) mutex_unlock(&arp->exitfns_lock);
412*dcdfe824SRobert Mustacchi return (0);
413*dcdfe824SRobert Mustacchi
414*dcdfe824SRobert Mustacchi }
415*dcdfe824SRobert Mustacchi
416*dcdfe824SRobert Mustacchi void
quick_exit(int status)417*dcdfe824SRobert Mustacchi quick_exit(int status)
418*dcdfe824SRobert Mustacchi {
419*dcdfe824SRobert Mustacchi quickexit_root_t *qrp = &curthread->ul_uberdata->quickexit_root;
420*dcdfe824SRobert Mustacchi _qexthdlr_t *p;
421*dcdfe824SRobert Mustacchi int cancel_state;
422*dcdfe824SRobert Mustacchi
423*dcdfe824SRobert Mustacchi (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state);
424*dcdfe824SRobert Mustacchi (void) mutex_lock(&qrp->exitfns_lock);
425*dcdfe824SRobert Mustacchi
426*dcdfe824SRobert Mustacchi p = qrp->head;
427*dcdfe824SRobert Mustacchi while (p != NULL) {
428*dcdfe824SRobert Mustacchi qrp->head = p->next;
429*dcdfe824SRobert Mustacchi p->hdlr();
430*dcdfe824SRobert Mustacchi lfree(p, sizeof (_qexthdlr_t));
431*dcdfe824SRobert Mustacchi p = qrp->head;
432*dcdfe824SRobert Mustacchi }
433*dcdfe824SRobert Mustacchi
434*dcdfe824SRobert Mustacchi (void) mutex_unlock(&qrp->exitfns_lock);
435*dcdfe824SRobert Mustacchi (void) pthread_setcancelstate(cancel_state, NULL);
436*dcdfe824SRobert Mustacchi _Exit(status);
437*dcdfe824SRobert Mustacchi }
438