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