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 58cd45542Sraf * Common Development and Distribution License (the "License"). 68cd45542Sraf * 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 */ 218cd45542Sraf 227c478bd9Sstevel@tonic-gate /* 238cd45542Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #include "lint.h" 287c478bd9Sstevel@tonic-gate #include "thr_uberdata.h" 297c478bd9Sstevel@tonic-gate 30*da8597e3SRoger A. Faulkner #define MIN_MOD_SLOTS 8 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate /* 338cd45542Sraf * Used to inform libc_init() that we are on the primary link map, 348cd45542Sraf * and to cause certain functions (like malloc() and sbrk()) to fail 358cd45542Sraf * (with ENOTSUP) when they are called on an alternate link map. 367c478bd9Sstevel@tonic-gate */ 378cd45542Sraf int primary_link_map = 0; 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #if defined(_LP64) 407c478bd9Sstevel@tonic-gate #define ALIGN 16 417c478bd9Sstevel@tonic-gate #else 427c478bd9Sstevel@tonic-gate #define ALIGN 8 437c478bd9Sstevel@tonic-gate #endif 447c478bd9Sstevel@tonic-gate 457c478bd9Sstevel@tonic-gate /* 467c478bd9Sstevel@tonic-gate * Grow the TLS module information array as necessary to include the 477c478bd9Sstevel@tonic-gate * specified module-id. tls_modinfo->tls_size must be a power of two. 487c478bd9Sstevel@tonic-gate * Return a pointer to the (possibly reallocated) module information array. 497c478bd9Sstevel@tonic-gate */ 507c478bd9Sstevel@tonic-gate static TLS_modinfo * 517c478bd9Sstevel@tonic-gate tls_modinfo_alloc(tls_metadata_t *tlsm, ulong_t moduleid) 527c478bd9Sstevel@tonic-gate { 537c478bd9Sstevel@tonic-gate tls_t *tls_modinfo = &tlsm->tls_modinfo; 547c478bd9Sstevel@tonic-gate TLS_modinfo *modinfo; 557c478bd9Sstevel@tonic-gate size_t mod_slots; 567c478bd9Sstevel@tonic-gate 577c478bd9Sstevel@tonic-gate if ((modinfo = tls_modinfo->tls_data) == NULL || 587c478bd9Sstevel@tonic-gate tls_modinfo->tls_size <= moduleid) { 597c478bd9Sstevel@tonic-gate if ((mod_slots = tls_modinfo->tls_size) == 0) 607c478bd9Sstevel@tonic-gate mod_slots = MIN_MOD_SLOTS; 617c478bd9Sstevel@tonic-gate while (mod_slots <= moduleid) 627c478bd9Sstevel@tonic-gate mod_slots *= 2; 637c478bd9Sstevel@tonic-gate modinfo = lmalloc(mod_slots * sizeof (TLS_modinfo)); 647c478bd9Sstevel@tonic-gate if (tls_modinfo->tls_data != NULL) { 658cd45542Sraf (void) memcpy(modinfo, tls_modinfo->tls_data, 667c478bd9Sstevel@tonic-gate tls_modinfo->tls_size * sizeof (TLS_modinfo)); 677c478bd9Sstevel@tonic-gate lfree(tls_modinfo->tls_data, 687c478bd9Sstevel@tonic-gate tls_modinfo->tls_size * sizeof (TLS_modinfo)); 697c478bd9Sstevel@tonic-gate } 707c478bd9Sstevel@tonic-gate tls_modinfo->tls_data = modinfo; 717c478bd9Sstevel@tonic-gate tls_modinfo->tls_size = mod_slots; 727c478bd9Sstevel@tonic-gate } 737c478bd9Sstevel@tonic-gate return (modinfo); 747c478bd9Sstevel@tonic-gate } 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate /* 777c478bd9Sstevel@tonic-gate * This is called from the dynamic linker, before libc_init() is called, 787c478bd9Sstevel@tonic-gate * to setup all of the TLS blocks that are available at process startup 797c478bd9Sstevel@tonic-gate * and hence must be included as part of the static TLS block. 807c478bd9Sstevel@tonic-gate * No locks are needed because we are single-threaded at this point. 817c478bd9Sstevel@tonic-gate * We must be careful not to call any function that could possibly 827c478bd9Sstevel@tonic-gate * invoke the dynamic linker. That is, we must only call functions 837c478bd9Sstevel@tonic-gate * that are wholly private to libc. 847c478bd9Sstevel@tonic-gate */ 857c478bd9Sstevel@tonic-gate void 867c478bd9Sstevel@tonic-gate __tls_static_mods(TLS_modinfo **tlslist, unsigned long statictlssize) 877c478bd9Sstevel@tonic-gate { 887c478bd9Sstevel@tonic-gate ulwp_t *oldself = __curthread(); 897c478bd9Sstevel@tonic-gate tls_metadata_t *tlsm; 907c478bd9Sstevel@tonic-gate TLS_modinfo **tlspp; 917c478bd9Sstevel@tonic-gate TLS_modinfo *tlsp; 927c478bd9Sstevel@tonic-gate TLS_modinfo *modinfo; 937c478bd9Sstevel@tonic-gate caddr_t data; 947c478bd9Sstevel@tonic-gate caddr_t data_end; 957c478bd9Sstevel@tonic-gate int max_modid; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate primary_link_map = 1; /* inform libc_init */ 987c478bd9Sstevel@tonic-gate if (statictlssize == 0) 997c478bd9Sstevel@tonic-gate return; 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * Retrieve whatever dynamic TLS metadata was generated by code 1037c478bd9Sstevel@tonic-gate * running on alternate link maps prior to now (we must be running 1047c478bd9Sstevel@tonic-gate * on the primary link map now since __tls_static_mods() is only 1057c478bd9Sstevel@tonic-gate * called on the primary link map). 1067c478bd9Sstevel@tonic-gate */ 1077c478bd9Sstevel@tonic-gate tlsm = &__uberdata.tls_metadata; 1087c478bd9Sstevel@tonic-gate if (oldself != NULL) { 1098cd45542Sraf (void) memcpy(tlsm, 1100293487cSraf &oldself->ul_uberdata->tls_metadata, sizeof (*tlsm)); 1117c478bd9Sstevel@tonic-gate ASSERT(tlsm->static_tls.tls_data == NULL); 1127c478bd9Sstevel@tonic-gate } 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /* 1157c478bd9Sstevel@tonic-gate * We call lmalloc() to allocate the template even though libc_init() 1167c478bd9Sstevel@tonic-gate * has not yet been called. lmalloc() must and does deal with this. 1177c478bd9Sstevel@tonic-gate */ 1187c478bd9Sstevel@tonic-gate ASSERT((statictlssize & (ALIGN - 1)) == 0); 1197c478bd9Sstevel@tonic-gate tlsm->static_tls.tls_data = data = lmalloc(statictlssize); 1207c478bd9Sstevel@tonic-gate data_end = data + statictlssize; 1217c478bd9Sstevel@tonic-gate tlsm->static_tls.tls_size = statictlssize; 1227c478bd9Sstevel@tonic-gate /* 1237c478bd9Sstevel@tonic-gate * Initialize the static TLS template. 1247c478bd9Sstevel@tonic-gate * We make no assumptions about the order in memory of the TLS 1257c478bd9Sstevel@tonic-gate * modules we are processing, only that they fit within the 1267c478bd9Sstevel@tonic-gate * total size we are given and that they are self-consistent. 1277c478bd9Sstevel@tonic-gate * We do not assume any order for the moduleid's; we only assume 1287c478bd9Sstevel@tonic-gate * that they are reasonably small integers. 1297c478bd9Sstevel@tonic-gate */ 1307c478bd9Sstevel@tonic-gate for (max_modid = 0, tlspp = tlslist; (tlsp = *tlspp) != NULL; tlspp++) { 1317c478bd9Sstevel@tonic-gate ASSERT(tlsp->tm_flags & TM_FLG_STATICTLS); 1327c478bd9Sstevel@tonic-gate ASSERT(tlsp->tm_stattlsoffset > 0); 1337c478bd9Sstevel@tonic-gate ASSERT(tlsp->tm_stattlsoffset <= statictlssize); 1347c478bd9Sstevel@tonic-gate ASSERT((tlsp->tm_stattlsoffset & (ALIGN - 1)) == 0); 1357c478bd9Sstevel@tonic-gate ASSERT(tlsp->tm_filesz <= tlsp->tm_memsz); 1367c478bd9Sstevel@tonic-gate ASSERT(tlsp->tm_memsz <= tlsp->tm_stattlsoffset); 1377c478bd9Sstevel@tonic-gate if (tlsp->tm_filesz) 1388cd45542Sraf (void) memcpy(data_end-tlsp->tm_stattlsoffset, 1397c478bd9Sstevel@tonic-gate tlsp->tm_tlsblock, tlsp->tm_filesz); 1407c478bd9Sstevel@tonic-gate if (max_modid < tlsp->tm_modid) 1417c478bd9Sstevel@tonic-gate max_modid = tlsp->tm_modid; 1427c478bd9Sstevel@tonic-gate } 1437c478bd9Sstevel@tonic-gate /* 1447c478bd9Sstevel@tonic-gate * Record the static TLS_modinfo information. 1457c478bd9Sstevel@tonic-gate */ 1467c478bd9Sstevel@tonic-gate modinfo = tls_modinfo_alloc(tlsm, max_modid); 1477c478bd9Sstevel@tonic-gate for (tlspp = tlslist; (tlsp = *tlspp) != NULL; tlspp++) 1488cd45542Sraf (void) memcpy(&modinfo[tlsp->tm_modid], 1490293487cSraf tlsp, sizeof (*tlsp)); 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* 1527c478bd9Sstevel@tonic-gate * Copy the new tls_metadata back to the old, if any, 1537c478bd9Sstevel@tonic-gate * since it will be copied up again in libc_init(). 1547c478bd9Sstevel@tonic-gate */ 1557c478bd9Sstevel@tonic-gate if (oldself != NULL) 1568cd45542Sraf (void) memcpy(&oldself->ul_uberdata->tls_metadata, 1570293487cSraf tlsm, sizeof (*tlsm)); 1587c478bd9Sstevel@tonic-gate } 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* 1617c478bd9Sstevel@tonic-gate * This is called from the dynamic linker for each module not included 1627c478bd9Sstevel@tonic-gate * in the static TLS mod list, after the module has been loaded but 1637c478bd9Sstevel@tonic-gate * before any of the module's init code has been executed. 1647c478bd9Sstevel@tonic-gate */ 1657c478bd9Sstevel@tonic-gate void 1667c478bd9Sstevel@tonic-gate __tls_mod_add(TLS_modinfo *tlsp) 1677c478bd9Sstevel@tonic-gate { 1687c478bd9Sstevel@tonic-gate tls_metadata_t *tlsm = &curthread->ul_uberdata->tls_metadata; 1697c478bd9Sstevel@tonic-gate ulong_t moduleid = tlsp->tm_modid; 1707c478bd9Sstevel@tonic-gate TLS_modinfo *modinfo; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 1737c478bd9Sstevel@tonic-gate ASSERT(!(tlsp->tm_flags & TM_FLG_STATICTLS)); 1747c478bd9Sstevel@tonic-gate ASSERT(tlsp->tm_filesz <= tlsp->tm_memsz); 1757c478bd9Sstevel@tonic-gate modinfo = tls_modinfo_alloc(tlsm, moduleid); 1768cd45542Sraf (void) memcpy(&modinfo[moduleid], tlsp, sizeof (*tlsp)); 1777c478bd9Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 1787c478bd9Sstevel@tonic-gate } 1797c478bd9Sstevel@tonic-gate 1807c478bd9Sstevel@tonic-gate /* 1817c478bd9Sstevel@tonic-gate * Called for each module as it is unloaded from memory by dlclose(). 1827c478bd9Sstevel@tonic-gate */ 1837c478bd9Sstevel@tonic-gate void 1847c478bd9Sstevel@tonic-gate __tls_mod_remove(TLS_modinfo *tlsp) 1857c478bd9Sstevel@tonic-gate { 1867c478bd9Sstevel@tonic-gate tls_metadata_t *tlsm = &curthread->ul_uberdata->tls_metadata; 1877c478bd9Sstevel@tonic-gate ulong_t moduleid = tlsp->tm_modid; 1887c478bd9Sstevel@tonic-gate TLS_modinfo *modinfo; 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 1917c478bd9Sstevel@tonic-gate ASSERT(tlsm->tls_modinfo.tls_data != NULL && 1927c478bd9Sstevel@tonic-gate moduleid < tlsm->tls_modinfo.tls_size); 1937c478bd9Sstevel@tonic-gate modinfo = tlsm->tls_modinfo.tls_data; 1948cd45542Sraf (void) memset(&modinfo[moduleid], 0, sizeof (TLS_modinfo)); 1957c478bd9Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 1967c478bd9Sstevel@tonic-gate } 1977c478bd9Sstevel@tonic-gate 1987c478bd9Sstevel@tonic-gate extern int _preexec_exit_handlers(); 1997c478bd9Sstevel@tonic-gate extern void libc_init(); 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate const Lc_interface tls_rtldinfo[] = { 2027c478bd9Sstevel@tonic-gate {CI_VERSION, (int(*)())CI_V_CURRENT}, 2037c478bd9Sstevel@tonic-gate {CI_ATEXIT, (int(*)())_preexec_exit_handlers}, 2047c478bd9Sstevel@tonic-gate {CI_TLS_MODADD, (int(*)())__tls_mod_add}, 2057c478bd9Sstevel@tonic-gate {CI_TLS_MODREM, (int(*)())__tls_mod_remove}, 2067c478bd9Sstevel@tonic-gate {CI_TLS_STATMOD, (int(*)())__tls_static_mods}, 2077c478bd9Sstevel@tonic-gate {CI_THRINIT, (int(*)())libc_init}, 2087c478bd9Sstevel@tonic-gate {CI_NULL, (int(*)())NULL} 2097c478bd9Sstevel@tonic-gate }; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate /* 2127c478bd9Sstevel@tonic-gate * Return the address of a TLS variable for the current thread. 2137c478bd9Sstevel@tonic-gate * Run the constructors for newly-allocated dynamic TLS. 2147c478bd9Sstevel@tonic-gate */ 2157c478bd9Sstevel@tonic-gate void * 2167c478bd9Sstevel@tonic-gate slow_tls_get_addr(TLS_index *tls_index) 2177c478bd9Sstevel@tonic-gate { 2187c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 2197c478bd9Sstevel@tonic-gate tls_metadata_t *tlsm = &self->ul_uberdata->tls_metadata; 2207c478bd9Sstevel@tonic-gate TLS_modinfo *tlsp; 2217c478bd9Sstevel@tonic-gate ulong_t moduleid; 2227c478bd9Sstevel@tonic-gate tls_t *tlsent; 2237c478bd9Sstevel@tonic-gate caddr_t base; 2247c478bd9Sstevel@tonic-gate void (**initarray)(void); 2257c478bd9Sstevel@tonic-gate ulong_t arraycnt = 0; 2267c478bd9Sstevel@tonic-gate 2277c478bd9Sstevel@tonic-gate /* 2287c478bd9Sstevel@tonic-gate * Defer signals until we have finished calling 2297c478bd9Sstevel@tonic-gate * all of the constructors. 2307c478bd9Sstevel@tonic-gate */ 2317c478bd9Sstevel@tonic-gate sigoff(self); 2327c478bd9Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 2337c478bd9Sstevel@tonic-gate if ((moduleid = tls_index->ti_moduleid) < self->ul_ntlsent) 2347c478bd9Sstevel@tonic-gate tlsent = self->ul_tlsent; 2357c478bd9Sstevel@tonic-gate else { 2367c478bd9Sstevel@tonic-gate ASSERT(moduleid < tlsm->tls_modinfo.tls_size); 2377c478bd9Sstevel@tonic-gate tlsent = lmalloc(tlsm->tls_modinfo.tls_size * sizeof (tls_t)); 2387c478bd9Sstevel@tonic-gate if (self->ul_tlsent != NULL) { 2398cd45542Sraf (void) memcpy(tlsent, self->ul_tlsent, 2407c478bd9Sstevel@tonic-gate self->ul_ntlsent * sizeof (tls_t)); 2417c478bd9Sstevel@tonic-gate lfree(self->ul_tlsent, 2427c478bd9Sstevel@tonic-gate self->ul_ntlsent * sizeof (tls_t)); 2437c478bd9Sstevel@tonic-gate } 2447c478bd9Sstevel@tonic-gate self->ul_tlsent = tlsent; 2457c478bd9Sstevel@tonic-gate self->ul_ntlsent = tlsm->tls_modinfo.tls_size; 2467c478bd9Sstevel@tonic-gate } 2477c478bd9Sstevel@tonic-gate tlsent += moduleid; 2487c478bd9Sstevel@tonic-gate if ((base = tlsent->tls_data) == NULL) { 2497c478bd9Sstevel@tonic-gate tlsp = (TLS_modinfo *)tlsm->tls_modinfo.tls_data + moduleid; 2507c478bd9Sstevel@tonic-gate if (tlsp->tm_memsz == 0) { /* dlclose()d module? */ 2517c478bd9Sstevel@tonic-gate base = NULL; 2527c478bd9Sstevel@tonic-gate } else if (tlsp->tm_flags & TM_FLG_STATICTLS) { 2537c478bd9Sstevel@tonic-gate /* static TLS is already allocated/initialized */ 2547c478bd9Sstevel@tonic-gate base = (caddr_t)self - tlsp->tm_stattlsoffset; 2557c478bd9Sstevel@tonic-gate tlsent->tls_data = base; 2567c478bd9Sstevel@tonic-gate tlsent->tls_size = 0; /* don't lfree() this space */ 2577c478bd9Sstevel@tonic-gate } else { 2587c478bd9Sstevel@tonic-gate /* allocate/initialize the dynamic TLS */ 2597c478bd9Sstevel@tonic-gate base = lmalloc(tlsp->tm_memsz); 2607c478bd9Sstevel@tonic-gate if (tlsp->tm_filesz != 0) 2618cd45542Sraf (void) memcpy(base, tlsp->tm_tlsblock, 2627c478bd9Sstevel@tonic-gate tlsp->tm_filesz); 2637c478bd9Sstevel@tonic-gate tlsent->tls_data = base; 2647c478bd9Sstevel@tonic-gate tlsent->tls_size = tlsp->tm_memsz; 2657c478bd9Sstevel@tonic-gate /* remember the constructors */ 2667c478bd9Sstevel@tonic-gate arraycnt = tlsp->tm_tlsinitarraycnt; 2677c478bd9Sstevel@tonic-gate initarray = tlsp->tm_tlsinitarray; 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate } 2707c478bd9Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate /* 2737c478bd9Sstevel@tonic-gate * Call constructors, if any, in ascending order. 2747c478bd9Sstevel@tonic-gate * We have to do this after dropping tls_lock because 2757c478bd9Sstevel@tonic-gate * we have no idea what the constructors will do. 2767c478bd9Sstevel@tonic-gate * At least we have signals deferred until they are done. 2777c478bd9Sstevel@tonic-gate */ 2787c478bd9Sstevel@tonic-gate if (arraycnt) { 2797c478bd9Sstevel@tonic-gate do { 2807c478bd9Sstevel@tonic-gate (**initarray++)(); 2817c478bd9Sstevel@tonic-gate } while (--arraycnt != 0); 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2848cd45542Sraf if (base == NULL) /* kludge to get x86/x64 to boot */ 2858cd45542Sraf base = (caddr_t)self - 512; 2868cd45542Sraf 2877c478bd9Sstevel@tonic-gate sigon(self); 2887c478bd9Sstevel@tonic-gate return (base + tls_index->ti_tlsoffset); 2897c478bd9Sstevel@tonic-gate } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate #ifdef TLS_GET_ADDR_IS_WRITTEN_IN_ASSEMBLER 2927c478bd9Sstevel@tonic-gate /* 2937c478bd9Sstevel@tonic-gate * For speed, we do not make reference to any static data in this function. 2947c478bd9Sstevel@tonic-gate * If necessary to do so, we do a tail call to slow_tls_get_addr(). 2957c478bd9Sstevel@tonic-gate */ 2967c478bd9Sstevel@tonic-gate void * 2977c478bd9Sstevel@tonic-gate __tls_get_addr(TLS_index *tls_index) 2987c478bd9Sstevel@tonic-gate { 2997c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 3007c478bd9Sstevel@tonic-gate tls_t *tlsent = self->ul_tlsent; 3017c478bd9Sstevel@tonic-gate ulong_t moduleid; 3027c478bd9Sstevel@tonic-gate caddr_t base; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate if ((moduleid = tls_index->ti_moduleid) < self->ul_ntlsent && 3057c478bd9Sstevel@tonic-gate (base = tlsent[moduleid].tls_data) != NULL) 3067c478bd9Sstevel@tonic-gate return (base + tls_index->ti_tlsoffset); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate return (slow_tls_get_addr(tls_index)); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate #endif /* TLS_GET_ADDR_IS_WRITTEN_IN_ASSEMBLER */ 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137257d1b4Sraf * This is called by _thrp_setup() to initialize the thread's static TLS. 3147c478bd9Sstevel@tonic-gate * Constructors for initially allocated static TLS are called here. 3157c478bd9Sstevel@tonic-gate */ 3167c478bd9Sstevel@tonic-gate void 3177c478bd9Sstevel@tonic-gate tls_setup() 3187c478bd9Sstevel@tonic-gate { 3197c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 3207c478bd9Sstevel@tonic-gate tls_metadata_t *tlsm = &self->ul_uberdata->tls_metadata; 3217c478bd9Sstevel@tonic-gate TLS_modinfo *tlsp; 3227c478bd9Sstevel@tonic-gate long moduleid; 3237c478bd9Sstevel@tonic-gate ulong_t nmods; 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate if (tlsm->static_tls.tls_size == 0) /* no static TLS */ 3267c478bd9Sstevel@tonic-gate return; 3277c478bd9Sstevel@tonic-gate 3287c478bd9Sstevel@tonic-gate /* static TLS initialization */ 3298cd45542Sraf (void) memcpy((caddr_t)self - tlsm->static_tls.tls_size, 3307c478bd9Sstevel@tonic-gate tlsm->static_tls.tls_data, tlsm->static_tls.tls_size); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* call TLS constructors for the static TLS just initialized */ 3337c478bd9Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 3347c478bd9Sstevel@tonic-gate nmods = tlsm->tls_modinfo.tls_size; 3357c478bd9Sstevel@tonic-gate for (moduleid = 0; moduleid < nmods; moduleid++) { 3367c478bd9Sstevel@tonic-gate /* 3377c478bd9Sstevel@tonic-gate * Resume where we left off in the module array. 3387c478bd9Sstevel@tonic-gate * tls_modinfo.tls_data may have changed since we 3397c478bd9Sstevel@tonic-gate * dropped and reacquired tls_lock, but TLS modules 3407c478bd9Sstevel@tonic-gate * retain their positions in the new array. 3417c478bd9Sstevel@tonic-gate */ 3427c478bd9Sstevel@tonic-gate tlsp = (TLS_modinfo *)tlsm->tls_modinfo.tls_data + moduleid; 3437c478bd9Sstevel@tonic-gate /* 3447c478bd9Sstevel@tonic-gate * Call constructors for this module if there are any 3457c478bd9Sstevel@tonic-gate * to be called and if it is part of the static TLS. 3467c478bd9Sstevel@tonic-gate */ 3477c478bd9Sstevel@tonic-gate if (tlsp->tm_tlsinitarraycnt != 0 && 3487c478bd9Sstevel@tonic-gate (tlsp->tm_flags & TM_FLG_STATICTLS)) { 3497c478bd9Sstevel@tonic-gate ulong_t arraycnt = tlsp->tm_tlsinitarraycnt; 3507c478bd9Sstevel@tonic-gate void (**initarray)(void) = tlsp->tm_tlsinitarray; 3517c478bd9Sstevel@tonic-gate 3527c478bd9Sstevel@tonic-gate /* 3537c478bd9Sstevel@tonic-gate * Call the constructors in ascending order. 3547c478bd9Sstevel@tonic-gate * We must drop tls_lock while doing this because 3557c478bd9Sstevel@tonic-gate * we have no idea what the constructors will do. 3567c478bd9Sstevel@tonic-gate */ 3577c478bd9Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 3587c478bd9Sstevel@tonic-gate do { 3597c478bd9Sstevel@tonic-gate (**initarray++)(); 3607c478bd9Sstevel@tonic-gate } while (--arraycnt != 0); 3617c478bd9Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 3627c478bd9Sstevel@tonic-gate } 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 3657c478bd9Sstevel@tonic-gate } 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * This is called by _thrp_exit() to deallocate the thread's TLS. 3697c478bd9Sstevel@tonic-gate * Destructors for all allocated TLS are called here. 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate void 3727c478bd9Sstevel@tonic-gate tls_exit() 3737c478bd9Sstevel@tonic-gate { 3747c478bd9Sstevel@tonic-gate ulwp_t *self = curthread; 3757c478bd9Sstevel@tonic-gate tls_metadata_t *tlsm = &self->ul_uberdata->tls_metadata; 3767c478bd9Sstevel@tonic-gate tls_t *tlsent; 3777c478bd9Sstevel@tonic-gate TLS_modinfo *tlsp; 3787c478bd9Sstevel@tonic-gate long moduleid; 3797c478bd9Sstevel@tonic-gate ulong_t nmods; 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate if (tlsm->static_tls.tls_size == 0 && self->ul_ntlsent == 0) 3827c478bd9Sstevel@tonic-gate return; /* no TLS */ 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate /* 3857c478bd9Sstevel@tonic-gate * Call TLS destructors for all TLS allocated for this thread. 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 3887c478bd9Sstevel@tonic-gate nmods = tlsm->tls_modinfo.tls_size; 3897c478bd9Sstevel@tonic-gate for (moduleid = nmods - 1; moduleid >= 0; --moduleid) { 3907c478bd9Sstevel@tonic-gate /* 3917c478bd9Sstevel@tonic-gate * Resume where we left off in the module array. 3927c478bd9Sstevel@tonic-gate * tls_modinfo.tls_data may have changed since we 3937c478bd9Sstevel@tonic-gate * dropped and reacquired tls_lock, but TLS modules 3947c478bd9Sstevel@tonic-gate * retain their positions in the new array. 3957c478bd9Sstevel@tonic-gate */ 3967c478bd9Sstevel@tonic-gate tlsp = (TLS_modinfo *)tlsm->tls_modinfo.tls_data + moduleid; 3977c478bd9Sstevel@tonic-gate /* 3987c478bd9Sstevel@tonic-gate * Call destructors for this module if there are any 3997c478bd9Sstevel@tonic-gate * to be called and if it is part of the static TLS or 4007c478bd9Sstevel@tonic-gate * if the dynamic TLS for the module has been allocated. 4017c478bd9Sstevel@tonic-gate */ 4027c478bd9Sstevel@tonic-gate if (tlsp->tm_tlsfiniarraycnt != 0 && 4037c478bd9Sstevel@tonic-gate ((tlsp->tm_flags & TM_FLG_STATICTLS) || 4047c478bd9Sstevel@tonic-gate (moduleid < self->ul_ntlsent && 4057c478bd9Sstevel@tonic-gate (tlsent = self->ul_tlsent) != NULL && 4067c478bd9Sstevel@tonic-gate tlsent[moduleid].tls_data != NULL))) { 4077c478bd9Sstevel@tonic-gate ulong_t arraycnt = tlsp->tm_tlsfiniarraycnt; 4087c478bd9Sstevel@tonic-gate void (**finiarray)(void) = tlsp->tm_tlsfiniarray; 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate /* 4117c478bd9Sstevel@tonic-gate * Call the destructors in descending order. 4127c478bd9Sstevel@tonic-gate * We must drop tls_lock while doing this because 4137c478bd9Sstevel@tonic-gate * we have no idea what the destructors will do. 4147c478bd9Sstevel@tonic-gate */ 4157c478bd9Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 4167c478bd9Sstevel@tonic-gate finiarray += arraycnt; 4177c478bd9Sstevel@tonic-gate do { 4187c478bd9Sstevel@tonic-gate (**--finiarray)(); 4197c478bd9Sstevel@tonic-gate } while (--arraycnt != 0); 4207c478bd9Sstevel@tonic-gate lmutex_lock(&tlsm->tls_lock); 4217c478bd9Sstevel@tonic-gate } 4227c478bd9Sstevel@tonic-gate } 4237c478bd9Sstevel@tonic-gate lmutex_unlock(&tlsm->tls_lock); 4247c478bd9Sstevel@tonic-gate 4257c478bd9Sstevel@tonic-gate tls_free(self); 4267c478bd9Sstevel@tonic-gate } 4277c478bd9Sstevel@tonic-gate 4287c478bd9Sstevel@tonic-gate /* 4297c478bd9Sstevel@tonic-gate * We only free the dynamically allocated TLS; the statically 4307c478bd9Sstevel@tonic-gate * allocated TLS is reused when the ulwp_t is reallocated. 4317c478bd9Sstevel@tonic-gate */ 4327c478bd9Sstevel@tonic-gate void 4337c478bd9Sstevel@tonic-gate tls_free(ulwp_t *ulwp) 4347c478bd9Sstevel@tonic-gate { 4357c478bd9Sstevel@tonic-gate ulong_t moduleid; 4367c478bd9Sstevel@tonic-gate tls_t *tlsent; 4377c478bd9Sstevel@tonic-gate size_t ntlsent; 4387c478bd9Sstevel@tonic-gate void *base; 4397c478bd9Sstevel@tonic-gate size_t size; 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate if ((tlsent = ulwp->ul_tlsent) == NULL || 4427c478bd9Sstevel@tonic-gate (ntlsent = ulwp->ul_ntlsent) == 0) 4437c478bd9Sstevel@tonic-gate return; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate for (moduleid = 0; moduleid < ntlsent; moduleid++, tlsent++) { 4467c478bd9Sstevel@tonic-gate if ((base = tlsent->tls_data) != NULL && 4477c478bd9Sstevel@tonic-gate (size = tlsent->tls_size) != 0) 4487c478bd9Sstevel@tonic-gate lfree(base, size); 4497c478bd9Sstevel@tonic-gate tlsent->tls_data = NULL; /* paranoia */ 4507c478bd9Sstevel@tonic-gate tlsent->tls_size = 0; 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate lfree(ulwp->ul_tlsent, ntlsent * sizeof (tls_t)); 4537c478bd9Sstevel@tonic-gate ulwp->ul_tlsent = NULL; 4547c478bd9Sstevel@tonic-gate ulwp->ul_ntlsent = 0; 4557c478bd9Sstevel@tonic-gate } 456