1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include "lint.h" 30*0Sstevel@tonic-gate #include "thr_uberdata.h" 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #define MIN_MOD_SLOTS 16 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate /* 35*0Sstevel@tonic-gate * To inform libc_init that we are on the primary link map. 36*0Sstevel@tonic-gate */ 37*0Sstevel@tonic-gate int primary_link_map; 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate #if defined(_LP64) 40*0Sstevel@tonic-gate #define ALIGN 16 41*0Sstevel@tonic-gate #else 42*0Sstevel@tonic-gate #define ALIGN 8 43*0Sstevel@tonic-gate #endif 44*0Sstevel@tonic-gate 45*0Sstevel@tonic-gate /* 46*0Sstevel@tonic-gate * Grow the TLS module information array as necessary to include the 47*0Sstevel@tonic-gate * specified module-id. tls_modinfo->tls_size must be a power of two. 48*0Sstevel@tonic-gate * Return a pointer to the (possibly reallocated) module information array. 49*0Sstevel@tonic-gate */ 50*0Sstevel@tonic-gate static TLS_modinfo * 51*0Sstevel@tonic-gate tls_modinfo_alloc(tls_metadata_t *tlsm, ulong_t moduleid) 52*0Sstevel@tonic-gate { 53*0Sstevel@tonic-gate tls_t *tls_modinfo = &tlsm->tls_modinfo; 54*0Sstevel@tonic-gate TLS_modinfo *modinfo; 55*0Sstevel@tonic-gate size_t mod_slots; 56*0Sstevel@tonic-gate 57*0Sstevel@tonic-gate if ((modinfo = tls_modinfo->tls_data) == NULL || 58*0Sstevel@tonic-gate tls_modinfo->tls_size <= moduleid) { 59*0Sstevel@tonic-gate if ((mod_slots = tls_modinfo->tls_size) == 0) 60*0Sstevel@tonic-gate mod_slots = MIN_MOD_SLOTS; 61*0Sstevel@tonic-gate while (mod_slots <= moduleid) 62*0Sstevel@tonic-gate mod_slots *= 2; 63*0Sstevel@tonic-gate modinfo = lmalloc(mod_slots * sizeof (TLS_modinfo)); 64*0Sstevel@tonic-gate if (tls_modinfo->tls_data != NULL) { 65*0Sstevel@tonic-gate (void) _private_memcpy(modinfo, tls_modinfo->tls_data, 66*0Sstevel@tonic-gate tls_modinfo->tls_size * sizeof (TLS_modinfo)); 67*0Sstevel@tonic-gate lfree(tls_modinfo->tls_data, 68*0Sstevel@tonic-gate tls_modinfo->tls_size * sizeof (TLS_modinfo)); 69*0Sstevel@tonic-gate } 70*0Sstevel@tonic-gate tls_modinfo->tls_data = modinfo; 71*0Sstevel@tonic-gate tls_modinfo->tls_size = mod_slots; 72*0Sstevel@tonic-gate } 73*0Sstevel@tonic-gate return (modinfo); 74*0Sstevel@tonic-gate } 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* 77*0Sstevel@tonic-gate * This is called from the dynamic linker, before libc_init() is called, 78*0Sstevel@tonic-gate * to setup all of the TLS blocks that are available at process startup 79*0Sstevel@tonic-gate * and hence must be included as part of the static TLS block. 80*0Sstevel@tonic-gate * No locks are needed because we are single-threaded at this point. 81*0Sstevel@tonic-gate * We must be careful not to call any function that could possibly 82*0Sstevel@tonic-gate * invoke the dynamic linker. That is, we must only call functions 83*0Sstevel@tonic-gate * that are wholly private to libc. 84*0Sstevel@tonic-gate */ 85*0Sstevel@tonic-gate void 86*0Sstevel@tonic-gate __tls_static_mods(TLS_modinfo **tlslist, unsigned long statictlssize) 87*0Sstevel@tonic-gate { 88*0Sstevel@tonic-gate ulwp_t *oldself = __curthread(); 89*0Sstevel@tonic-gate tls_metadata_t *tlsm; 90*0Sstevel@tonic-gate TLS_modinfo **tlspp; 91*0Sstevel@tonic-gate TLS_modinfo *tlsp; 92*0Sstevel@tonic-gate TLS_modinfo *modinfo; 93*0Sstevel@tonic-gate caddr_t data; 94*0Sstevel@tonic-gate caddr_t data_end; 95*0Sstevel@tonic-gate int max_modid; 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate primary_link_map = 1; /* inform libc_init */ 98*0Sstevel@tonic-gate if (statictlssize == 0) 99*0Sstevel@tonic-gate return; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate /* 102*0Sstevel@tonic-gate * Retrieve whatever dynamic TLS metadata was generated by code 103*0Sstevel@tonic-gate * running on alternate link maps prior to now (we must be running 104*0Sstevel@tonic-gate * on the primary link map now since __tls_static_mods() is only 105*0Sstevel@tonic-gate * called on the primary link map). 106*0Sstevel@tonic-gate */ 107*0Sstevel@tonic-gate tlsm = &__uberdata.tls_metadata; 108*0Sstevel@tonic-gate if (oldself != NULL) { 109*0Sstevel@tonic-gate *tlsm = oldself->ul_uberdata->tls_metadata; 110*0Sstevel@tonic-gate ASSERT(tlsm->static_tls.tls_data == NULL); 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate /* 114*0Sstevel@tonic-gate * We call lmalloc() to allocate the template even though libc_init() 115*0Sstevel@tonic-gate * has not yet been called. lmalloc() must and does deal with this. 116*0Sstevel@tonic-gate */ 117*0Sstevel@tonic-gate ASSERT((statictlssize & (ALIGN - 1)) == 0); 118*0Sstevel@tonic-gate tlsm->static_tls.tls_data = data = lmalloc(statictlssize); 119*0Sstevel@tonic-gate data_end = data + statictlssize; 120*0Sstevel@tonic-gate tlsm->static_tls.tls_size = statictlssize; 121*0Sstevel@tonic-gate /* 122*0Sstevel@tonic-gate * Initialize the static TLS template. 123*0Sstevel@tonic-gate * We make no assumptions about the order in memory of the TLS 124*0Sstevel@tonic-gate * modules we are processing, only that they fit within the 125*0Sstevel@tonic-gate * total size we are given and that they are self-consistent. 126*0Sstevel@tonic-gate * We do not assume any order for the moduleid's; we only assume 127*0Sstevel@tonic-gate * that they are reasonably small integers. 128*0Sstevel@tonic-gate */ 129*0Sstevel@tonic-gate for (max_modid = 0, tlspp = tlslist; (tlsp = *tlspp) != NULL; tlspp++) { 130*0Sstevel@tonic-gate ASSERT(tlsp->tm_flags & TM_FLG_STATICTLS); 131*0Sstevel@tonic-gate ASSERT(tlsp->tm_stattlsoffset > 0); 132*0Sstevel@tonic-gate ASSERT(tlsp->tm_stattlsoffset <= statictlssize); 133*0Sstevel@tonic-gate ASSERT((tlsp->tm_stattlsoffset & (ALIGN - 1)) == 0); 134*0Sstevel@tonic-gate ASSERT(tlsp->tm_filesz <= tlsp->tm_memsz); 135*0Sstevel@tonic-gate ASSERT(tlsp->tm_memsz <= tlsp->tm_stattlsoffset); 136*0Sstevel@tonic-gate if (tlsp->tm_filesz) 137*0Sstevel@tonic-gate (void) _private_memcpy(data_end-tlsp->tm_stattlsoffset, 138*0Sstevel@tonic-gate tlsp->tm_tlsblock, tlsp->tm_filesz); 139*0Sstevel@tonic-gate if (max_modid < tlsp->tm_modid) 140*0Sstevel@tonic-gate max_modid = tlsp->tm_modid; 141*0Sstevel@tonic-gate } 142*0Sstevel@tonic-gate /* 143*0Sstevel@tonic-gate * Record the static TLS_modinfo information. 144*0Sstevel@tonic-gate */ 145*0Sstevel@tonic-gate modinfo = tls_modinfo_alloc(tlsm, max_modid); 146*0Sstevel@tonic-gate for (tlspp = tlslist; (tlsp = *tlspp) != NULL; tlspp++) 147*0Sstevel@tonic-gate modinfo[tlsp->tm_modid] = *tlsp; 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate /* 150*0Sstevel@tonic-gate * Copy the new tls_metadata back to the old, if any, 151*0Sstevel@tonic-gate * since it will be copied up again in libc_init(). 152*0Sstevel@tonic-gate */ 153*0Sstevel@tonic-gate if (oldself != NULL) 154*0Sstevel@tonic-gate oldself->ul_uberdata->tls_metadata = *tlsm; 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate /* 158*0Sstevel@tonic-gate * This is called from the dynamic linker for each module not included 159*0Sstevel@tonic-gate * in the static TLS mod list, after the module has been loaded but 160*0Sstevel@tonic-gate * before any of the module's init code has been executed. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate void 163*0Sstevel@tonic-gate __tls_mod_add(TLS_modinfo *tlsp) 164*0Sstevel@tonic-gate { 165*0Sstevel@tonic-gate tls_metadata_t *tlsm = &curthread->ul_uberdata->tls_metadata; 166*0Sstevel@tonic-gate ulong_t moduleid = tlsp->tm_modid; 167*0Sstevel@tonic-gate TLS_modinfo *modinfo; 168*0Sstevel@tonic-gate 169*0Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 170*0Sstevel@tonic-gate ASSERT(!(tlsp->tm_flags & TM_FLG_STATICTLS)); 171*0Sstevel@tonic-gate ASSERT(tlsp->tm_filesz <= tlsp->tm_memsz); 172*0Sstevel@tonic-gate modinfo = tls_modinfo_alloc(tlsm, moduleid); 173*0Sstevel@tonic-gate modinfo[moduleid] = *tlsp; 174*0Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 175*0Sstevel@tonic-gate } 176*0Sstevel@tonic-gate 177*0Sstevel@tonic-gate /* 178*0Sstevel@tonic-gate * Called for each module as it is unloaded from memory by dlclose(). 179*0Sstevel@tonic-gate */ 180*0Sstevel@tonic-gate void 181*0Sstevel@tonic-gate __tls_mod_remove(TLS_modinfo *tlsp) 182*0Sstevel@tonic-gate { 183*0Sstevel@tonic-gate tls_metadata_t *tlsm = &curthread->ul_uberdata->tls_metadata; 184*0Sstevel@tonic-gate ulong_t moduleid = tlsp->tm_modid; 185*0Sstevel@tonic-gate TLS_modinfo *modinfo; 186*0Sstevel@tonic-gate 187*0Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 188*0Sstevel@tonic-gate ASSERT(tlsm->tls_modinfo.tls_data != NULL && 189*0Sstevel@tonic-gate moduleid < tlsm->tls_modinfo.tls_size); 190*0Sstevel@tonic-gate modinfo = tlsm->tls_modinfo.tls_data; 191*0Sstevel@tonic-gate (void) _private_memset(&modinfo[moduleid], 0, sizeof (TLS_modinfo)); 192*0Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate extern int _preexec_exit_handlers(); 196*0Sstevel@tonic-gate extern void libc_init(); 197*0Sstevel@tonic-gate 198*0Sstevel@tonic-gate const Lc_interface tls_rtldinfo[] = { 199*0Sstevel@tonic-gate {CI_VERSION, (int(*)())CI_V_CURRENT}, 200*0Sstevel@tonic-gate {CI_ATEXIT, (int(*)())_preexec_exit_handlers}, 201*0Sstevel@tonic-gate {CI_TLS_MODADD, (int(*)())__tls_mod_add}, 202*0Sstevel@tonic-gate {CI_TLS_MODREM, (int(*)())__tls_mod_remove}, 203*0Sstevel@tonic-gate {CI_TLS_STATMOD, (int(*)())__tls_static_mods}, 204*0Sstevel@tonic-gate {CI_THRINIT, (int(*)())libc_init}, 205*0Sstevel@tonic-gate {CI_NULL, (int(*)())NULL} 206*0Sstevel@tonic-gate }; 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /* 209*0Sstevel@tonic-gate * Return the address of a TLS variable for the current thread. 210*0Sstevel@tonic-gate * Run the constructors for newly-allocated dynamic TLS. 211*0Sstevel@tonic-gate */ 212*0Sstevel@tonic-gate void * 213*0Sstevel@tonic-gate slow_tls_get_addr(TLS_index *tls_index) 214*0Sstevel@tonic-gate { 215*0Sstevel@tonic-gate ulwp_t *self = curthread; 216*0Sstevel@tonic-gate tls_metadata_t *tlsm = &self->ul_uberdata->tls_metadata; 217*0Sstevel@tonic-gate TLS_modinfo *tlsp; 218*0Sstevel@tonic-gate ulong_t moduleid; 219*0Sstevel@tonic-gate tls_t *tlsent; 220*0Sstevel@tonic-gate caddr_t base; 221*0Sstevel@tonic-gate void (**initarray)(void); 222*0Sstevel@tonic-gate ulong_t arraycnt = 0; 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate /* 225*0Sstevel@tonic-gate * Defer signals until we have finished calling 226*0Sstevel@tonic-gate * all of the constructors. 227*0Sstevel@tonic-gate */ 228*0Sstevel@tonic-gate sigoff(self); 229*0Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 230*0Sstevel@tonic-gate if ((moduleid = tls_index->ti_moduleid) < self->ul_ntlsent) 231*0Sstevel@tonic-gate tlsent = self->ul_tlsent; 232*0Sstevel@tonic-gate else { 233*0Sstevel@tonic-gate ASSERT(moduleid < tlsm->tls_modinfo.tls_size); 234*0Sstevel@tonic-gate tlsent = lmalloc(tlsm->tls_modinfo.tls_size * sizeof (tls_t)); 235*0Sstevel@tonic-gate if (self->ul_tlsent != NULL) { 236*0Sstevel@tonic-gate (void) _private_memcpy(tlsent, self->ul_tlsent, 237*0Sstevel@tonic-gate self->ul_ntlsent * sizeof (tls_t)); 238*0Sstevel@tonic-gate lfree(self->ul_tlsent, 239*0Sstevel@tonic-gate self->ul_ntlsent * sizeof (tls_t)); 240*0Sstevel@tonic-gate } 241*0Sstevel@tonic-gate self->ul_tlsent = tlsent; 242*0Sstevel@tonic-gate self->ul_ntlsent = tlsm->tls_modinfo.tls_size; 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate tlsent += moduleid; 245*0Sstevel@tonic-gate if ((base = tlsent->tls_data) == NULL) { 246*0Sstevel@tonic-gate tlsp = (TLS_modinfo *)tlsm->tls_modinfo.tls_data + moduleid; 247*0Sstevel@tonic-gate if (tlsp->tm_memsz == 0) { /* dlclose()d module? */ 248*0Sstevel@tonic-gate base = NULL; 249*0Sstevel@tonic-gate } else if (tlsp->tm_flags & TM_FLG_STATICTLS) { 250*0Sstevel@tonic-gate /* static TLS is already allocated/initialized */ 251*0Sstevel@tonic-gate base = (caddr_t)self - tlsp->tm_stattlsoffset; 252*0Sstevel@tonic-gate tlsent->tls_data = base; 253*0Sstevel@tonic-gate tlsent->tls_size = 0; /* don't lfree() this space */ 254*0Sstevel@tonic-gate } else { 255*0Sstevel@tonic-gate /* allocate/initialize the dynamic TLS */ 256*0Sstevel@tonic-gate base = lmalloc(tlsp->tm_memsz); 257*0Sstevel@tonic-gate if (tlsp->tm_filesz != 0) 258*0Sstevel@tonic-gate (void) _private_memcpy(base, tlsp->tm_tlsblock, 259*0Sstevel@tonic-gate tlsp->tm_filesz); 260*0Sstevel@tonic-gate tlsent->tls_data = base; 261*0Sstevel@tonic-gate tlsent->tls_size = tlsp->tm_memsz; 262*0Sstevel@tonic-gate /* remember the constructors */ 263*0Sstevel@tonic-gate arraycnt = tlsp->tm_tlsinitarraycnt; 264*0Sstevel@tonic-gate initarray = tlsp->tm_tlsinitarray; 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate } 267*0Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate /* 270*0Sstevel@tonic-gate * Call constructors, if any, in ascending order. 271*0Sstevel@tonic-gate * We have to do this after dropping tls_lock because 272*0Sstevel@tonic-gate * we have no idea what the constructors will do. 273*0Sstevel@tonic-gate * At least we have signals deferred until they are done. 274*0Sstevel@tonic-gate */ 275*0Sstevel@tonic-gate if (arraycnt) { 276*0Sstevel@tonic-gate do { 277*0Sstevel@tonic-gate (**initarray++)(); 278*0Sstevel@tonic-gate } while (--arraycnt != 0); 279*0Sstevel@tonic-gate } 280*0Sstevel@tonic-gate 281*0Sstevel@tonic-gate sigon(self); 282*0Sstevel@tonic-gate return (base + tls_index->ti_tlsoffset); 283*0Sstevel@tonic-gate } 284*0Sstevel@tonic-gate 285*0Sstevel@tonic-gate #ifdef TLS_GET_ADDR_IS_WRITTEN_IN_ASSEMBLER 286*0Sstevel@tonic-gate /* 287*0Sstevel@tonic-gate * For speed, we do not make reference to any static data in this function. 288*0Sstevel@tonic-gate * If necessary to do so, we do a tail call to slow_tls_get_addr(). 289*0Sstevel@tonic-gate */ 290*0Sstevel@tonic-gate void * 291*0Sstevel@tonic-gate __tls_get_addr(TLS_index *tls_index) 292*0Sstevel@tonic-gate { 293*0Sstevel@tonic-gate ulwp_t *self = curthread; 294*0Sstevel@tonic-gate tls_t *tlsent = self->ul_tlsent; 295*0Sstevel@tonic-gate ulong_t moduleid; 296*0Sstevel@tonic-gate caddr_t base; 297*0Sstevel@tonic-gate 298*0Sstevel@tonic-gate if ((moduleid = tls_index->ti_moduleid) < self->ul_ntlsent && 299*0Sstevel@tonic-gate (base = tlsent[moduleid].tls_data) != NULL) 300*0Sstevel@tonic-gate return (base + tls_index->ti_tlsoffset); 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate return (slow_tls_get_addr(tls_index)); 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate #endif /* TLS_GET_ADDR_IS_WRITTEN_IN_ASSEMBLER */ 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate /* 307*0Sstevel@tonic-gate * This is called by _thr_setup() to initialize the thread's static TLS. 308*0Sstevel@tonic-gate * Constructors for initially allocated static TLS are called here. 309*0Sstevel@tonic-gate */ 310*0Sstevel@tonic-gate void 311*0Sstevel@tonic-gate tls_setup() 312*0Sstevel@tonic-gate { 313*0Sstevel@tonic-gate ulwp_t *self = curthread; 314*0Sstevel@tonic-gate tls_metadata_t *tlsm = &self->ul_uberdata->tls_metadata; 315*0Sstevel@tonic-gate TLS_modinfo *tlsp; 316*0Sstevel@tonic-gate long moduleid; 317*0Sstevel@tonic-gate ulong_t nmods; 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate if (tlsm->static_tls.tls_size == 0) /* no static TLS */ 320*0Sstevel@tonic-gate return; 321*0Sstevel@tonic-gate 322*0Sstevel@tonic-gate /* static TLS initialization */ 323*0Sstevel@tonic-gate (void) _private_memcpy((caddr_t)self - tlsm->static_tls.tls_size, 324*0Sstevel@tonic-gate tlsm->static_tls.tls_data, tlsm->static_tls.tls_size); 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate /* call TLS constructors for the static TLS just initialized */ 327*0Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 328*0Sstevel@tonic-gate nmods = tlsm->tls_modinfo.tls_size; 329*0Sstevel@tonic-gate for (moduleid = 0; moduleid < nmods; moduleid++) { 330*0Sstevel@tonic-gate /* 331*0Sstevel@tonic-gate * Resume where we left off in the module array. 332*0Sstevel@tonic-gate * tls_modinfo.tls_data may have changed since we 333*0Sstevel@tonic-gate * dropped and reacquired tls_lock, but TLS modules 334*0Sstevel@tonic-gate * retain their positions in the new array. 335*0Sstevel@tonic-gate */ 336*0Sstevel@tonic-gate tlsp = (TLS_modinfo *)tlsm->tls_modinfo.tls_data + moduleid; 337*0Sstevel@tonic-gate /* 338*0Sstevel@tonic-gate * Call constructors for this module if there are any 339*0Sstevel@tonic-gate * to be called and if it is part of the static TLS. 340*0Sstevel@tonic-gate */ 341*0Sstevel@tonic-gate if (tlsp->tm_tlsinitarraycnt != 0 && 342*0Sstevel@tonic-gate (tlsp->tm_flags & TM_FLG_STATICTLS)) { 343*0Sstevel@tonic-gate ulong_t arraycnt = tlsp->tm_tlsinitarraycnt; 344*0Sstevel@tonic-gate void (**initarray)(void) = tlsp->tm_tlsinitarray; 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate /* 347*0Sstevel@tonic-gate * Call the constructors in ascending order. 348*0Sstevel@tonic-gate * We must drop tls_lock while doing this because 349*0Sstevel@tonic-gate * we have no idea what the constructors will do. 350*0Sstevel@tonic-gate */ 351*0Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 352*0Sstevel@tonic-gate do { 353*0Sstevel@tonic-gate (**initarray++)(); 354*0Sstevel@tonic-gate } while (--arraycnt != 0); 355*0Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 359*0Sstevel@tonic-gate } 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate /* 362*0Sstevel@tonic-gate * This is called by _thrp_exit() to deallocate the thread's TLS. 363*0Sstevel@tonic-gate * Destructors for all allocated TLS are called here. 364*0Sstevel@tonic-gate */ 365*0Sstevel@tonic-gate void 366*0Sstevel@tonic-gate tls_exit() 367*0Sstevel@tonic-gate { 368*0Sstevel@tonic-gate ulwp_t *self = curthread; 369*0Sstevel@tonic-gate tls_metadata_t *tlsm = &self->ul_uberdata->tls_metadata; 370*0Sstevel@tonic-gate tls_t *tlsent; 371*0Sstevel@tonic-gate TLS_modinfo *tlsp; 372*0Sstevel@tonic-gate long moduleid; 373*0Sstevel@tonic-gate ulong_t nmods; 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate if (tlsm->static_tls.tls_size == 0 && self->ul_ntlsent == 0) 376*0Sstevel@tonic-gate return; /* no TLS */ 377*0Sstevel@tonic-gate 378*0Sstevel@tonic-gate /* 379*0Sstevel@tonic-gate * Call TLS destructors for all TLS allocated for this thread. 380*0Sstevel@tonic-gate */ 381*0Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 382*0Sstevel@tonic-gate nmods = tlsm->tls_modinfo.tls_size; 383*0Sstevel@tonic-gate for (moduleid = nmods - 1; moduleid >= 0; --moduleid) { 384*0Sstevel@tonic-gate /* 385*0Sstevel@tonic-gate * Resume where we left off in the module array. 386*0Sstevel@tonic-gate * tls_modinfo.tls_data may have changed since we 387*0Sstevel@tonic-gate * dropped and reacquired tls_lock, but TLS modules 388*0Sstevel@tonic-gate * retain their positions in the new array. 389*0Sstevel@tonic-gate */ 390*0Sstevel@tonic-gate tlsp = (TLS_modinfo *)tlsm->tls_modinfo.tls_data + moduleid; 391*0Sstevel@tonic-gate /* 392*0Sstevel@tonic-gate * Call destructors for this module if there are any 393*0Sstevel@tonic-gate * to be called and if it is part of the static TLS or 394*0Sstevel@tonic-gate * if the dynamic TLS for the module has been allocated. 395*0Sstevel@tonic-gate */ 396*0Sstevel@tonic-gate if (tlsp->tm_tlsfiniarraycnt != 0 && 397*0Sstevel@tonic-gate ((tlsp->tm_flags & TM_FLG_STATICTLS) || 398*0Sstevel@tonic-gate (moduleid < self->ul_ntlsent && 399*0Sstevel@tonic-gate (tlsent = self->ul_tlsent) != NULL && 400*0Sstevel@tonic-gate tlsent[moduleid].tls_data != NULL))) { 401*0Sstevel@tonic-gate ulong_t arraycnt = tlsp->tm_tlsfiniarraycnt; 402*0Sstevel@tonic-gate void (**finiarray)(void) = tlsp->tm_tlsfiniarray; 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate /* 405*0Sstevel@tonic-gate * Call the destructors in descending order. 406*0Sstevel@tonic-gate * We must drop tls_lock while doing this because 407*0Sstevel@tonic-gate * we have no idea what the destructors will do. 408*0Sstevel@tonic-gate */ 409*0Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 410*0Sstevel@tonic-gate finiarray += arraycnt; 411*0Sstevel@tonic-gate do { 412*0Sstevel@tonic-gate (**--finiarray)(); 413*0Sstevel@tonic-gate } while (--arraycnt != 0); 414*0Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 415*0Sstevel@tonic-gate } 416*0Sstevel@tonic-gate } 417*0Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate tls_free(self); 420*0Sstevel@tonic-gate } 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate /* 423*0Sstevel@tonic-gate * We only free the dynamically allocated TLS; the statically 424*0Sstevel@tonic-gate * allocated TLS is reused when the ulwp_t is reallocated. 425*0Sstevel@tonic-gate */ 426*0Sstevel@tonic-gate void 427*0Sstevel@tonic-gate tls_free(ulwp_t *ulwp) 428*0Sstevel@tonic-gate { 429*0Sstevel@tonic-gate ulong_t moduleid; 430*0Sstevel@tonic-gate tls_t *tlsent; 431*0Sstevel@tonic-gate size_t ntlsent; 432*0Sstevel@tonic-gate void *base; 433*0Sstevel@tonic-gate size_t size; 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate if ((tlsent = ulwp->ul_tlsent) == NULL || 436*0Sstevel@tonic-gate (ntlsent = ulwp->ul_ntlsent) == 0) 437*0Sstevel@tonic-gate return; 438*0Sstevel@tonic-gate 439*0Sstevel@tonic-gate for (moduleid = 0; moduleid < ntlsent; moduleid++, tlsent++) { 440*0Sstevel@tonic-gate if ((base = tlsent->tls_data) != NULL && 441*0Sstevel@tonic-gate (size = tlsent->tls_size) != 0) 442*0Sstevel@tonic-gate lfree(base, size); 443*0Sstevel@tonic-gate tlsent->tls_data = NULL; /* paranoia */ 444*0Sstevel@tonic-gate tlsent->tls_size = 0; 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate lfree(ulwp->ul_tlsent, ntlsent * sizeof (tls_t)); 447*0Sstevel@tonic-gate ulwp->ul_tlsent = NULL; 448*0Sstevel@tonic-gate ulwp->ul_ntlsent = 0; 449*0Sstevel@tonic-gate } 450