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