10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 56515Sraf * Common Development and Distribution License (the "License"). 66515Sraf * You may not use this file except in compliance with the License. 70Sstevel@tonic-gate * 80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 100Sstevel@tonic-gate * See the License for the specific language governing permissions 110Sstevel@tonic-gate * and limitations under the License. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 180Sstevel@tonic-gate * 190Sstevel@tonic-gate * CDDL HEADER END 200Sstevel@tonic-gate */ 216515Sraf 220Sstevel@tonic-gate /* 236515Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include "lint.h" 300Sstevel@tonic-gate #include "thr_uberdata.h" 310Sstevel@tonic-gate 320Sstevel@tonic-gate #define MIN_MOD_SLOTS 16 330Sstevel@tonic-gate 340Sstevel@tonic-gate /* 356515Sraf * Used to inform libc_init() that we are on the primary link map, 366515Sraf * and to cause certain functions (like malloc() and sbrk()) to fail 376515Sraf * (with ENOTSUP) when they are called on an alternate link map. 380Sstevel@tonic-gate */ 396515Sraf int primary_link_map = 0; 400Sstevel@tonic-gate 410Sstevel@tonic-gate #if defined(_LP64) 420Sstevel@tonic-gate #define ALIGN 16 430Sstevel@tonic-gate #else 440Sstevel@tonic-gate #define ALIGN 8 450Sstevel@tonic-gate #endif 460Sstevel@tonic-gate 470Sstevel@tonic-gate /* 480Sstevel@tonic-gate * Grow the TLS module information array as necessary to include the 490Sstevel@tonic-gate * specified module-id. tls_modinfo->tls_size must be a power of two. 500Sstevel@tonic-gate * Return a pointer to the (possibly reallocated) module information array. 510Sstevel@tonic-gate */ 520Sstevel@tonic-gate static TLS_modinfo * 530Sstevel@tonic-gate tls_modinfo_alloc(tls_metadata_t *tlsm, ulong_t moduleid) 540Sstevel@tonic-gate { 550Sstevel@tonic-gate tls_t *tls_modinfo = &tlsm->tls_modinfo; 560Sstevel@tonic-gate TLS_modinfo *modinfo; 570Sstevel@tonic-gate size_t mod_slots; 580Sstevel@tonic-gate 590Sstevel@tonic-gate if ((modinfo = tls_modinfo->tls_data) == NULL || 600Sstevel@tonic-gate tls_modinfo->tls_size <= moduleid) { 610Sstevel@tonic-gate if ((mod_slots = tls_modinfo->tls_size) == 0) 620Sstevel@tonic-gate mod_slots = MIN_MOD_SLOTS; 630Sstevel@tonic-gate while (mod_slots <= moduleid) 640Sstevel@tonic-gate mod_slots *= 2; 650Sstevel@tonic-gate modinfo = lmalloc(mod_slots * sizeof (TLS_modinfo)); 660Sstevel@tonic-gate if (tls_modinfo->tls_data != NULL) { 676515Sraf (void) memcpy(modinfo, tls_modinfo->tls_data, 686515Sraf tls_modinfo->tls_size * sizeof (TLS_modinfo)); 690Sstevel@tonic-gate lfree(tls_modinfo->tls_data, 706515Sraf tls_modinfo->tls_size * sizeof (TLS_modinfo)); 710Sstevel@tonic-gate } 720Sstevel@tonic-gate tls_modinfo->tls_data = modinfo; 730Sstevel@tonic-gate tls_modinfo->tls_size = mod_slots; 740Sstevel@tonic-gate } 750Sstevel@tonic-gate return (modinfo); 760Sstevel@tonic-gate } 770Sstevel@tonic-gate 780Sstevel@tonic-gate /* 790Sstevel@tonic-gate * This is called from the dynamic linker, before libc_init() is called, 800Sstevel@tonic-gate * to setup all of the TLS blocks that are available at process startup 810Sstevel@tonic-gate * and hence must be included as part of the static TLS block. 820Sstevel@tonic-gate * No locks are needed because we are single-threaded at this point. 830Sstevel@tonic-gate * We must be careful not to call any function that could possibly 840Sstevel@tonic-gate * invoke the dynamic linker. That is, we must only call functions 850Sstevel@tonic-gate * that are wholly private to libc. 860Sstevel@tonic-gate */ 870Sstevel@tonic-gate void 880Sstevel@tonic-gate __tls_static_mods(TLS_modinfo **tlslist, unsigned long statictlssize) 890Sstevel@tonic-gate { 900Sstevel@tonic-gate ulwp_t *oldself = __curthread(); 910Sstevel@tonic-gate tls_metadata_t *tlsm; 920Sstevel@tonic-gate TLS_modinfo **tlspp; 930Sstevel@tonic-gate TLS_modinfo *tlsp; 940Sstevel@tonic-gate TLS_modinfo *modinfo; 950Sstevel@tonic-gate caddr_t data; 960Sstevel@tonic-gate caddr_t data_end; 970Sstevel@tonic-gate int max_modid; 980Sstevel@tonic-gate 990Sstevel@tonic-gate primary_link_map = 1; /* inform libc_init */ 1000Sstevel@tonic-gate if (statictlssize == 0) 1010Sstevel@tonic-gate return; 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate /* 1040Sstevel@tonic-gate * Retrieve whatever dynamic TLS metadata was generated by code 1050Sstevel@tonic-gate * running on alternate link maps prior to now (we must be running 1060Sstevel@tonic-gate * on the primary link map now since __tls_static_mods() is only 1070Sstevel@tonic-gate * called on the primary link map). 1080Sstevel@tonic-gate */ 1090Sstevel@tonic-gate tlsm = &__uberdata.tls_metadata; 1100Sstevel@tonic-gate if (oldself != NULL) { 1116515Sraf (void) memcpy(tlsm, 1121111Sraf &oldself->ul_uberdata->tls_metadata, sizeof (*tlsm)); 1130Sstevel@tonic-gate ASSERT(tlsm->static_tls.tls_data == NULL); 1140Sstevel@tonic-gate } 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate /* 1170Sstevel@tonic-gate * We call lmalloc() to allocate the template even though libc_init() 1180Sstevel@tonic-gate * has not yet been called. lmalloc() must and does deal with this. 1190Sstevel@tonic-gate */ 1200Sstevel@tonic-gate ASSERT((statictlssize & (ALIGN - 1)) == 0); 1210Sstevel@tonic-gate tlsm->static_tls.tls_data = data = lmalloc(statictlssize); 1220Sstevel@tonic-gate data_end = data + statictlssize; 1230Sstevel@tonic-gate tlsm->static_tls.tls_size = statictlssize; 1240Sstevel@tonic-gate /* 1250Sstevel@tonic-gate * Initialize the static TLS template. 1260Sstevel@tonic-gate * We make no assumptions about the order in memory of the TLS 1270Sstevel@tonic-gate * modules we are processing, only that they fit within the 1280Sstevel@tonic-gate * total size we are given and that they are self-consistent. 1290Sstevel@tonic-gate * We do not assume any order for the moduleid's; we only assume 1300Sstevel@tonic-gate * that they are reasonably small integers. 1310Sstevel@tonic-gate */ 1320Sstevel@tonic-gate for (max_modid = 0, tlspp = tlslist; (tlsp = *tlspp) != NULL; tlspp++) { 1330Sstevel@tonic-gate ASSERT(tlsp->tm_flags & TM_FLG_STATICTLS); 1340Sstevel@tonic-gate ASSERT(tlsp->tm_stattlsoffset > 0); 1350Sstevel@tonic-gate ASSERT(tlsp->tm_stattlsoffset <= statictlssize); 1360Sstevel@tonic-gate ASSERT((tlsp->tm_stattlsoffset & (ALIGN - 1)) == 0); 1370Sstevel@tonic-gate ASSERT(tlsp->tm_filesz <= tlsp->tm_memsz); 1380Sstevel@tonic-gate ASSERT(tlsp->tm_memsz <= tlsp->tm_stattlsoffset); 1390Sstevel@tonic-gate if (tlsp->tm_filesz) 1406515Sraf (void) memcpy(data_end-tlsp->tm_stattlsoffset, 1416515Sraf tlsp->tm_tlsblock, tlsp->tm_filesz); 1420Sstevel@tonic-gate if (max_modid < tlsp->tm_modid) 1430Sstevel@tonic-gate max_modid = tlsp->tm_modid; 1440Sstevel@tonic-gate } 1450Sstevel@tonic-gate /* 1460Sstevel@tonic-gate * Record the static TLS_modinfo information. 1470Sstevel@tonic-gate */ 1480Sstevel@tonic-gate modinfo = tls_modinfo_alloc(tlsm, max_modid); 1490Sstevel@tonic-gate for (tlspp = tlslist; (tlsp = *tlspp) != NULL; tlspp++) 1506515Sraf (void) memcpy(&modinfo[tlsp->tm_modid], 1511111Sraf tlsp, sizeof (*tlsp)); 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate /* 1540Sstevel@tonic-gate * Copy the new tls_metadata back to the old, if any, 1550Sstevel@tonic-gate * since it will be copied up again in libc_init(). 1560Sstevel@tonic-gate */ 1570Sstevel@tonic-gate if (oldself != NULL) 1586515Sraf (void) memcpy(&oldself->ul_uberdata->tls_metadata, 1591111Sraf tlsm, sizeof (*tlsm)); 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate /* 1630Sstevel@tonic-gate * This is called from the dynamic linker for each module not included 1640Sstevel@tonic-gate * in the static TLS mod list, after the module has been loaded but 1650Sstevel@tonic-gate * before any of the module's init code has been executed. 1660Sstevel@tonic-gate */ 1670Sstevel@tonic-gate void 1680Sstevel@tonic-gate __tls_mod_add(TLS_modinfo *tlsp) 1690Sstevel@tonic-gate { 1700Sstevel@tonic-gate tls_metadata_t *tlsm = &curthread->ul_uberdata->tls_metadata; 1710Sstevel@tonic-gate ulong_t moduleid = tlsp->tm_modid; 1720Sstevel@tonic-gate TLS_modinfo *modinfo; 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 1750Sstevel@tonic-gate ASSERT(!(tlsp->tm_flags & TM_FLG_STATICTLS)); 1760Sstevel@tonic-gate ASSERT(tlsp->tm_filesz <= tlsp->tm_memsz); 1770Sstevel@tonic-gate modinfo = tls_modinfo_alloc(tlsm, moduleid); 1786515Sraf (void) memcpy(&modinfo[moduleid], tlsp, sizeof (*tlsp)); 1790Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 1800Sstevel@tonic-gate } 1810Sstevel@tonic-gate 1820Sstevel@tonic-gate /* 1830Sstevel@tonic-gate * Called for each module as it is unloaded from memory by dlclose(). 1840Sstevel@tonic-gate */ 1850Sstevel@tonic-gate void 1860Sstevel@tonic-gate __tls_mod_remove(TLS_modinfo *tlsp) 1870Sstevel@tonic-gate { 1880Sstevel@tonic-gate tls_metadata_t *tlsm = &curthread->ul_uberdata->tls_metadata; 1890Sstevel@tonic-gate ulong_t moduleid = tlsp->tm_modid; 1900Sstevel@tonic-gate TLS_modinfo *modinfo; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 1930Sstevel@tonic-gate ASSERT(tlsm->tls_modinfo.tls_data != NULL && 1940Sstevel@tonic-gate moduleid < tlsm->tls_modinfo.tls_size); 1950Sstevel@tonic-gate modinfo = tlsm->tls_modinfo.tls_data; 1966515Sraf (void) memset(&modinfo[moduleid], 0, sizeof (TLS_modinfo)); 1970Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 1980Sstevel@tonic-gate } 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate extern int _preexec_exit_handlers(); 2010Sstevel@tonic-gate extern void libc_init(); 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate const Lc_interface tls_rtldinfo[] = { 2040Sstevel@tonic-gate {CI_VERSION, (int(*)())CI_V_CURRENT}, 2050Sstevel@tonic-gate {CI_ATEXIT, (int(*)())_preexec_exit_handlers}, 2060Sstevel@tonic-gate {CI_TLS_MODADD, (int(*)())__tls_mod_add}, 2070Sstevel@tonic-gate {CI_TLS_MODREM, (int(*)())__tls_mod_remove}, 2080Sstevel@tonic-gate {CI_TLS_STATMOD, (int(*)())__tls_static_mods}, 2090Sstevel@tonic-gate {CI_THRINIT, (int(*)())libc_init}, 2100Sstevel@tonic-gate {CI_NULL, (int(*)())NULL} 2110Sstevel@tonic-gate }; 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate /* 2140Sstevel@tonic-gate * Return the address of a TLS variable for the current thread. 2150Sstevel@tonic-gate * Run the constructors for newly-allocated dynamic TLS. 2160Sstevel@tonic-gate */ 2170Sstevel@tonic-gate void * 2180Sstevel@tonic-gate slow_tls_get_addr(TLS_index *tls_index) 2190Sstevel@tonic-gate { 2200Sstevel@tonic-gate ulwp_t *self = curthread; 2210Sstevel@tonic-gate tls_metadata_t *tlsm = &self->ul_uberdata->tls_metadata; 2220Sstevel@tonic-gate TLS_modinfo *tlsp; 2230Sstevel@tonic-gate ulong_t moduleid; 2240Sstevel@tonic-gate tls_t *tlsent; 2250Sstevel@tonic-gate caddr_t base; 2260Sstevel@tonic-gate void (**initarray)(void); 2270Sstevel@tonic-gate ulong_t arraycnt = 0; 2280Sstevel@tonic-gate 2290Sstevel@tonic-gate /* 2300Sstevel@tonic-gate * Defer signals until we have finished calling 2310Sstevel@tonic-gate * all of the constructors. 2320Sstevel@tonic-gate */ 2330Sstevel@tonic-gate sigoff(self); 2340Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 2350Sstevel@tonic-gate if ((moduleid = tls_index->ti_moduleid) < self->ul_ntlsent) 2360Sstevel@tonic-gate tlsent = self->ul_tlsent; 2370Sstevel@tonic-gate else { 2380Sstevel@tonic-gate ASSERT(moduleid < tlsm->tls_modinfo.tls_size); 2390Sstevel@tonic-gate tlsent = lmalloc(tlsm->tls_modinfo.tls_size * sizeof (tls_t)); 2400Sstevel@tonic-gate if (self->ul_tlsent != NULL) { 2416515Sraf (void) memcpy(tlsent, self->ul_tlsent, 2426515Sraf self->ul_ntlsent * sizeof (tls_t)); 2430Sstevel@tonic-gate lfree(self->ul_tlsent, 2446515Sraf self->ul_ntlsent * sizeof (tls_t)); 2450Sstevel@tonic-gate } 2460Sstevel@tonic-gate self->ul_tlsent = tlsent; 2470Sstevel@tonic-gate self->ul_ntlsent = tlsm->tls_modinfo.tls_size; 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate tlsent += moduleid; 2500Sstevel@tonic-gate if ((base = tlsent->tls_data) == NULL) { 2510Sstevel@tonic-gate tlsp = (TLS_modinfo *)tlsm->tls_modinfo.tls_data + moduleid; 2520Sstevel@tonic-gate if (tlsp->tm_memsz == 0) { /* dlclose()d module? */ 2530Sstevel@tonic-gate base = NULL; 2540Sstevel@tonic-gate } else if (tlsp->tm_flags & TM_FLG_STATICTLS) { 2550Sstevel@tonic-gate /* static TLS is already allocated/initialized */ 2560Sstevel@tonic-gate base = (caddr_t)self - tlsp->tm_stattlsoffset; 2570Sstevel@tonic-gate tlsent->tls_data = base; 2580Sstevel@tonic-gate tlsent->tls_size = 0; /* don't lfree() this space */ 2590Sstevel@tonic-gate } else { 2600Sstevel@tonic-gate /* allocate/initialize the dynamic TLS */ 2610Sstevel@tonic-gate base = lmalloc(tlsp->tm_memsz); 2620Sstevel@tonic-gate if (tlsp->tm_filesz != 0) 2636515Sraf (void) memcpy(base, tlsp->tm_tlsblock, 2646515Sraf tlsp->tm_filesz); 2650Sstevel@tonic-gate tlsent->tls_data = base; 2660Sstevel@tonic-gate tlsent->tls_size = tlsp->tm_memsz; 2670Sstevel@tonic-gate /* remember the constructors */ 2680Sstevel@tonic-gate arraycnt = tlsp->tm_tlsinitarraycnt; 2690Sstevel@tonic-gate initarray = tlsp->tm_tlsinitarray; 2700Sstevel@tonic-gate } 2710Sstevel@tonic-gate } 2720Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate /* 2750Sstevel@tonic-gate * Call constructors, if any, in ascending order. 2760Sstevel@tonic-gate * We have to do this after dropping tls_lock because 2770Sstevel@tonic-gate * we have no idea what the constructors will do. 2780Sstevel@tonic-gate * At least we have signals deferred until they are done. 2790Sstevel@tonic-gate */ 2800Sstevel@tonic-gate if (arraycnt) { 2810Sstevel@tonic-gate do { 2820Sstevel@tonic-gate (**initarray++)(); 2830Sstevel@tonic-gate } while (--arraycnt != 0); 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2866515Sraf if (base == NULL) /* kludge to get x86/x64 to boot */ 2876515Sraf base = (caddr_t)self - 512; 2886515Sraf 2890Sstevel@tonic-gate sigon(self); 2900Sstevel@tonic-gate return (base + tls_index->ti_tlsoffset); 2910Sstevel@tonic-gate } 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate #ifdef TLS_GET_ADDR_IS_WRITTEN_IN_ASSEMBLER 2940Sstevel@tonic-gate /* 2950Sstevel@tonic-gate * For speed, we do not make reference to any static data in this function. 2960Sstevel@tonic-gate * If necessary to do so, we do a tail call to slow_tls_get_addr(). 2970Sstevel@tonic-gate */ 2980Sstevel@tonic-gate void * 2990Sstevel@tonic-gate __tls_get_addr(TLS_index *tls_index) 3000Sstevel@tonic-gate { 3010Sstevel@tonic-gate ulwp_t *self = curthread; 3020Sstevel@tonic-gate tls_t *tlsent = self->ul_tlsent; 3030Sstevel@tonic-gate ulong_t moduleid; 3040Sstevel@tonic-gate caddr_t base; 3050Sstevel@tonic-gate 3060Sstevel@tonic-gate if ((moduleid = tls_index->ti_moduleid) < self->ul_ntlsent && 3070Sstevel@tonic-gate (base = tlsent[moduleid].tls_data) != NULL) 3080Sstevel@tonic-gate return (base + tls_index->ti_tlsoffset); 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate return (slow_tls_get_addr(tls_index)); 3110Sstevel@tonic-gate } 3120Sstevel@tonic-gate #endif /* TLS_GET_ADDR_IS_WRITTEN_IN_ASSEMBLER */ 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate /* 315*6812Sraf * This is called by _thrp_setup() to initialize the thread's static TLS. 3160Sstevel@tonic-gate * Constructors for initially allocated static TLS are called here. 3170Sstevel@tonic-gate */ 3180Sstevel@tonic-gate void 3190Sstevel@tonic-gate tls_setup() 3200Sstevel@tonic-gate { 3210Sstevel@tonic-gate ulwp_t *self = curthread; 3220Sstevel@tonic-gate tls_metadata_t *tlsm = &self->ul_uberdata->tls_metadata; 3230Sstevel@tonic-gate TLS_modinfo *tlsp; 3240Sstevel@tonic-gate long moduleid; 3250Sstevel@tonic-gate ulong_t nmods; 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate if (tlsm->static_tls.tls_size == 0) /* no static TLS */ 3280Sstevel@tonic-gate return; 3290Sstevel@tonic-gate 3300Sstevel@tonic-gate /* static TLS initialization */ 3316515Sraf (void) memcpy((caddr_t)self - tlsm->static_tls.tls_size, 3326515Sraf tlsm->static_tls.tls_data, tlsm->static_tls.tls_size); 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate /* call TLS constructors for the static TLS just initialized */ 3350Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 3360Sstevel@tonic-gate nmods = tlsm->tls_modinfo.tls_size; 3370Sstevel@tonic-gate for (moduleid = 0; moduleid < nmods; moduleid++) { 3380Sstevel@tonic-gate /* 3390Sstevel@tonic-gate * Resume where we left off in the module array. 3400Sstevel@tonic-gate * tls_modinfo.tls_data may have changed since we 3410Sstevel@tonic-gate * dropped and reacquired tls_lock, but TLS modules 3420Sstevel@tonic-gate * retain their positions in the new array. 3430Sstevel@tonic-gate */ 3440Sstevel@tonic-gate tlsp = (TLS_modinfo *)tlsm->tls_modinfo.tls_data + moduleid; 3450Sstevel@tonic-gate /* 3460Sstevel@tonic-gate * Call constructors for this module if there are any 3470Sstevel@tonic-gate * to be called and if it is part of the static TLS. 3480Sstevel@tonic-gate */ 3490Sstevel@tonic-gate if (tlsp->tm_tlsinitarraycnt != 0 && 3500Sstevel@tonic-gate (tlsp->tm_flags & TM_FLG_STATICTLS)) { 3510Sstevel@tonic-gate ulong_t arraycnt = tlsp->tm_tlsinitarraycnt; 3520Sstevel@tonic-gate void (**initarray)(void) = tlsp->tm_tlsinitarray; 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate /* 3550Sstevel@tonic-gate * Call the constructors in ascending order. 3560Sstevel@tonic-gate * We must drop tls_lock while doing this because 3570Sstevel@tonic-gate * we have no idea what the constructors will do. 3580Sstevel@tonic-gate */ 3590Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 3600Sstevel@tonic-gate do { 3610Sstevel@tonic-gate (**initarray++)(); 3620Sstevel@tonic-gate } while (--arraycnt != 0); 3630Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 3640Sstevel@tonic-gate } 3650Sstevel@tonic-gate } 3660Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 3670Sstevel@tonic-gate } 3680Sstevel@tonic-gate 3690Sstevel@tonic-gate /* 3700Sstevel@tonic-gate * This is called by _thrp_exit() to deallocate the thread's TLS. 3710Sstevel@tonic-gate * Destructors for all allocated TLS are called here. 3720Sstevel@tonic-gate */ 3730Sstevel@tonic-gate void 3740Sstevel@tonic-gate tls_exit() 3750Sstevel@tonic-gate { 3760Sstevel@tonic-gate ulwp_t *self = curthread; 3770Sstevel@tonic-gate tls_metadata_t *tlsm = &self->ul_uberdata->tls_metadata; 3780Sstevel@tonic-gate tls_t *tlsent; 3790Sstevel@tonic-gate TLS_modinfo *tlsp; 3800Sstevel@tonic-gate long moduleid; 3810Sstevel@tonic-gate ulong_t nmods; 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate if (tlsm->static_tls.tls_size == 0 && self->ul_ntlsent == 0) 3840Sstevel@tonic-gate return; /* no TLS */ 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate /* 3870Sstevel@tonic-gate * Call TLS destructors for all TLS allocated for this thread. 3880Sstevel@tonic-gate */ 3890Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 3900Sstevel@tonic-gate nmods = tlsm->tls_modinfo.tls_size; 3910Sstevel@tonic-gate for (moduleid = nmods - 1; moduleid >= 0; --moduleid) { 3920Sstevel@tonic-gate /* 3930Sstevel@tonic-gate * Resume where we left off in the module array. 3940Sstevel@tonic-gate * tls_modinfo.tls_data may have changed since we 3950Sstevel@tonic-gate * dropped and reacquired tls_lock, but TLS modules 3960Sstevel@tonic-gate * retain their positions in the new array. 3970Sstevel@tonic-gate */ 3980Sstevel@tonic-gate tlsp = (TLS_modinfo *)tlsm->tls_modinfo.tls_data + moduleid; 3990Sstevel@tonic-gate /* 4000Sstevel@tonic-gate * Call destructors for this module if there are any 4010Sstevel@tonic-gate * to be called and if it is part of the static TLS or 4020Sstevel@tonic-gate * if the dynamic TLS for the module has been allocated. 4030Sstevel@tonic-gate */ 4040Sstevel@tonic-gate if (tlsp->tm_tlsfiniarraycnt != 0 && 4050Sstevel@tonic-gate ((tlsp->tm_flags & TM_FLG_STATICTLS) || 4060Sstevel@tonic-gate (moduleid < self->ul_ntlsent && 4070Sstevel@tonic-gate (tlsent = self->ul_tlsent) != NULL && 4080Sstevel@tonic-gate tlsent[moduleid].tls_data != NULL))) { 4090Sstevel@tonic-gate ulong_t arraycnt = tlsp->tm_tlsfiniarraycnt; 4100Sstevel@tonic-gate void (**finiarray)(void) = tlsp->tm_tlsfiniarray; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * Call the destructors in descending order. 4140Sstevel@tonic-gate * We must drop tls_lock while doing this because 4150Sstevel@tonic-gate * we have no idea what the destructors will do. 4160Sstevel@tonic-gate */ 4170Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 4180Sstevel@tonic-gate finiarray += arraycnt; 4190Sstevel@tonic-gate do { 4200Sstevel@tonic-gate (**--finiarray)(); 4210Sstevel@tonic-gate } while (--arraycnt != 0); 4220Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 4230Sstevel@tonic-gate } 4240Sstevel@tonic-gate } 4250Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate tls_free(self); 4280Sstevel@tonic-gate } 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate /* 4310Sstevel@tonic-gate * We only free the dynamically allocated TLS; the statically 4320Sstevel@tonic-gate * allocated TLS is reused when the ulwp_t is reallocated. 4330Sstevel@tonic-gate */ 4340Sstevel@tonic-gate void 4350Sstevel@tonic-gate tls_free(ulwp_t *ulwp) 4360Sstevel@tonic-gate { 4370Sstevel@tonic-gate ulong_t moduleid; 4380Sstevel@tonic-gate tls_t *tlsent; 4390Sstevel@tonic-gate size_t ntlsent; 4400Sstevel@tonic-gate void *base; 4410Sstevel@tonic-gate size_t size; 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate if ((tlsent = ulwp->ul_tlsent) == NULL || 4440Sstevel@tonic-gate (ntlsent = ulwp->ul_ntlsent) == 0) 4450Sstevel@tonic-gate return; 4460Sstevel@tonic-gate 4470Sstevel@tonic-gate for (moduleid = 0; moduleid < ntlsent; moduleid++, tlsent++) { 4480Sstevel@tonic-gate if ((base = tlsent->tls_data) != NULL && 4490Sstevel@tonic-gate (size = tlsent->tls_size) != 0) 4500Sstevel@tonic-gate lfree(base, size); 4510Sstevel@tonic-gate tlsent->tls_data = NULL; /* paranoia */ 4520Sstevel@tonic-gate tlsent->tls_size = 0; 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate lfree(ulwp->ul_tlsent, ntlsent * sizeof (tls_t)); 4550Sstevel@tonic-gate ulwp->ul_tlsent = NULL; 4560Sstevel@tonic-gate ulwp->ul_ntlsent = 0; 4570Sstevel@tonic-gate } 458