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 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 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 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 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 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 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 * 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 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 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 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 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 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 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 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