xref: /onnv-gate/usr/src/lib/libc/port/threads/tls.c (revision 7890:24cdfdc10811)
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 #include "lint.h"
280Sstevel@tonic-gate #include "thr_uberdata.h"
290Sstevel@tonic-gate 
30*7890SRoger.Faulkner@Sun.COM #define	MIN_MOD_SLOTS	8
310Sstevel@tonic-gate 
320Sstevel@tonic-gate /*
336515Sraf  * Used to inform libc_init() that we are on the primary link map,
346515Sraf  * and to cause certain functions (like malloc() and sbrk()) to fail
356515Sraf  * (with ENOTSUP) when they are called on an alternate link map.
360Sstevel@tonic-gate  */
376515Sraf int primary_link_map = 0;
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 *
tls_modinfo_alloc(tls_metadata_t * tlsm,ulong_t moduleid)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) {
656515Sraf 			(void) memcpy(modinfo, tls_modinfo->tls_data,
666515Sraf 			    tls_modinfo->tls_size * sizeof (TLS_modinfo));
670Sstevel@tonic-gate 			lfree(tls_modinfo->tls_data,
686515Sraf 			    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
__tls_static_mods(TLS_modinfo ** tlslist,unsigned long statictlssize)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) {
1096515Sraf 		(void) memcpy(tlsm,
1101111Sraf 		    &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)
1386515Sraf 			(void) memcpy(data_end-tlsp->tm_stattlsoffset,
1396515Sraf 			    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++)
1486515Sraf 		(void) memcpy(&modinfo[tlsp->tm_modid],
1491111Sraf 		    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)
1566515Sraf 		(void) memcpy(&oldself->ul_uberdata->tls_metadata,
1571111Sraf 		    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
__tls_mod_add(TLS_modinfo * tlsp)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);
1766515Sraf 	(void) 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
__tls_mod_remove(TLS_modinfo * tlsp)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;
1946515Sraf 	(void) 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 *
slow_tls_get_addr(TLS_index * tls_index)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) {
2396515Sraf 			(void) memcpy(tlsent, self->ul_tlsent,
2406515Sraf 			    self->ul_ntlsent * sizeof (tls_t));
2410Sstevel@tonic-gate 			lfree(self->ul_tlsent,
2426515Sraf 			    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)
2616515Sraf 				(void) memcpy(base, tlsp->tm_tlsblock,
2626515Sraf 				    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 
2846515Sraf 	if (base == NULL)	/* kludge to get x86/x64 to boot */
2856515Sraf 		base = (caddr_t)self - 512;
2866515Sraf 
2870Sstevel@tonic-gate 	sigon(self);
2880Sstevel@tonic-gate 	return (base + tls_index->ti_tlsoffset);
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate #ifdef	TLS_GET_ADDR_IS_WRITTEN_IN_ASSEMBLER
2920Sstevel@tonic-gate /*
2930Sstevel@tonic-gate  * For speed, we do not make reference to any static data in this function.
2940Sstevel@tonic-gate  * If necessary to do so, we do a tail call to slow_tls_get_addr().
2950Sstevel@tonic-gate  */
2960Sstevel@tonic-gate void *
__tls_get_addr(TLS_index * tls_index)2970Sstevel@tonic-gate __tls_get_addr(TLS_index *tls_index)
2980Sstevel@tonic-gate {
2990Sstevel@tonic-gate 	ulwp_t *self = curthread;
3000Sstevel@tonic-gate 	tls_t *tlsent = self->ul_tlsent;
3010Sstevel@tonic-gate 	ulong_t moduleid;
3020Sstevel@tonic-gate 	caddr_t	base;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	if ((moduleid = tls_index->ti_moduleid) < self->ul_ntlsent &&
3050Sstevel@tonic-gate 	    (base = tlsent[moduleid].tls_data) != NULL)
3060Sstevel@tonic-gate 		return (base + tls_index->ti_tlsoffset);
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	return (slow_tls_get_addr(tls_index));
3090Sstevel@tonic-gate }
3100Sstevel@tonic-gate #endif	/* TLS_GET_ADDR_IS_WRITTEN_IN_ASSEMBLER */
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate /*
3136812Sraf  * This is called by _thrp_setup() to initialize the thread's static TLS.
3140Sstevel@tonic-gate  * Constructors for initially allocated static TLS are called here.
3150Sstevel@tonic-gate  */
3160Sstevel@tonic-gate void
tls_setup()3170Sstevel@tonic-gate tls_setup()
3180Sstevel@tonic-gate {
3190Sstevel@tonic-gate 	ulwp_t *self = curthread;
3200Sstevel@tonic-gate 	tls_metadata_t *tlsm = &self->ul_uberdata->tls_metadata;
3210Sstevel@tonic-gate 	TLS_modinfo *tlsp;
3220Sstevel@tonic-gate 	long moduleid;
3230Sstevel@tonic-gate 	ulong_t nmods;
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate 	if (tlsm->static_tls.tls_size == 0)	/* no static TLS */
3260Sstevel@tonic-gate 		return;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	/* static TLS initialization */
3296515Sraf 	(void) memcpy((caddr_t)self - tlsm->static_tls.tls_size,
3306515Sraf 	    tlsm->static_tls.tls_data, tlsm->static_tls.tls_size);
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	/* call TLS constructors for the static TLS just initialized */
3330Sstevel@tonic-gate 	lmutex_lock(&tlsm->tls_lock);
3340Sstevel@tonic-gate 	nmods = tlsm->tls_modinfo.tls_size;
3350Sstevel@tonic-gate 	for (moduleid = 0; moduleid < nmods; moduleid++) {
3360Sstevel@tonic-gate 		/*
3370Sstevel@tonic-gate 		 * Resume where we left off in the module array.
3380Sstevel@tonic-gate 		 * tls_modinfo.tls_data may have changed since we
3390Sstevel@tonic-gate 		 * dropped and reacquired tls_lock, but TLS modules
3400Sstevel@tonic-gate 		 * retain their positions in the new array.
3410Sstevel@tonic-gate 		 */
3420Sstevel@tonic-gate 		tlsp = (TLS_modinfo *)tlsm->tls_modinfo.tls_data + moduleid;
3430Sstevel@tonic-gate 		/*
3440Sstevel@tonic-gate 		 * Call constructors for this module if there are any
3450Sstevel@tonic-gate 		 * to be called and if it is part of the static TLS.
3460Sstevel@tonic-gate 		 */
3470Sstevel@tonic-gate 		if (tlsp->tm_tlsinitarraycnt != 0 &&
3480Sstevel@tonic-gate 		    (tlsp->tm_flags & TM_FLG_STATICTLS)) {
3490Sstevel@tonic-gate 			ulong_t arraycnt = tlsp->tm_tlsinitarraycnt;
3500Sstevel@tonic-gate 			void (**initarray)(void) = tlsp->tm_tlsinitarray;
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 			/*
3530Sstevel@tonic-gate 			 * Call the constructors in ascending order.
3540Sstevel@tonic-gate 			 * We must drop tls_lock while doing this because
3550Sstevel@tonic-gate 			 * we have no idea what the constructors will do.
3560Sstevel@tonic-gate 			 */
3570Sstevel@tonic-gate 			lmutex_unlock(&tlsm->tls_lock);
3580Sstevel@tonic-gate 			do {
3590Sstevel@tonic-gate 				(**initarray++)();
3600Sstevel@tonic-gate 			} while (--arraycnt != 0);
3610Sstevel@tonic-gate 			lmutex_lock(&tlsm->tls_lock);
3620Sstevel@tonic-gate 		}
3630Sstevel@tonic-gate 	}
3640Sstevel@tonic-gate 	lmutex_unlock(&tlsm->tls_lock);
3650Sstevel@tonic-gate }
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate /*
3680Sstevel@tonic-gate  * This is called by _thrp_exit() to deallocate the thread's TLS.
3690Sstevel@tonic-gate  * Destructors for all allocated TLS are called here.
3700Sstevel@tonic-gate  */
3710Sstevel@tonic-gate void
tls_exit()3720Sstevel@tonic-gate tls_exit()
3730Sstevel@tonic-gate {
3740Sstevel@tonic-gate 	ulwp_t *self = curthread;
3750Sstevel@tonic-gate 	tls_metadata_t *tlsm = &self->ul_uberdata->tls_metadata;
3760Sstevel@tonic-gate 	tls_t *tlsent;
3770Sstevel@tonic-gate 	TLS_modinfo *tlsp;
3780Sstevel@tonic-gate 	long moduleid;
3790Sstevel@tonic-gate 	ulong_t nmods;
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 	if (tlsm->static_tls.tls_size == 0 && self->ul_ntlsent == 0)
3820Sstevel@tonic-gate 		return;		/* no TLS */
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	/*
3850Sstevel@tonic-gate 	 * Call TLS destructors for all TLS allocated for this thread.
3860Sstevel@tonic-gate 	 */
3870Sstevel@tonic-gate 	lmutex_lock(&tlsm->tls_lock);
3880Sstevel@tonic-gate 	nmods = tlsm->tls_modinfo.tls_size;
3890Sstevel@tonic-gate 	for (moduleid = nmods - 1; moduleid >= 0; --moduleid) {
3900Sstevel@tonic-gate 		/*
3910Sstevel@tonic-gate 		 * Resume where we left off in the module array.
3920Sstevel@tonic-gate 		 * tls_modinfo.tls_data may have changed since we
3930Sstevel@tonic-gate 		 * dropped and reacquired tls_lock, but TLS modules
3940Sstevel@tonic-gate 		 * retain their positions in the new array.
3950Sstevel@tonic-gate 		 */
3960Sstevel@tonic-gate 		tlsp = (TLS_modinfo *)tlsm->tls_modinfo.tls_data + moduleid;
3970Sstevel@tonic-gate 		/*
3980Sstevel@tonic-gate 		 * Call destructors for this module if there are any
3990Sstevel@tonic-gate 		 * to be called and if it is part of the static TLS or
4000Sstevel@tonic-gate 		 * if the dynamic TLS for the module has been allocated.
4010Sstevel@tonic-gate 		 */
4020Sstevel@tonic-gate 		if (tlsp->tm_tlsfiniarraycnt != 0 &&
4030Sstevel@tonic-gate 		    ((tlsp->tm_flags & TM_FLG_STATICTLS) ||
4040Sstevel@tonic-gate 		    (moduleid < self->ul_ntlsent &&
4050Sstevel@tonic-gate 		    (tlsent = self->ul_tlsent) != NULL &&
4060Sstevel@tonic-gate 		    tlsent[moduleid].tls_data != NULL))) {
4070Sstevel@tonic-gate 			ulong_t arraycnt = tlsp->tm_tlsfiniarraycnt;
4080Sstevel@tonic-gate 			void (**finiarray)(void) = tlsp->tm_tlsfiniarray;
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 			/*
4110Sstevel@tonic-gate 			 * Call the destructors in descending order.
4120Sstevel@tonic-gate 			 * We must drop tls_lock while doing this because
4130Sstevel@tonic-gate 			 * we have no idea what the destructors will do.
4140Sstevel@tonic-gate 			 */
4150Sstevel@tonic-gate 			lmutex_unlock(&tlsm->tls_lock);
4160Sstevel@tonic-gate 			finiarray += arraycnt;
4170Sstevel@tonic-gate 			do {
4180Sstevel@tonic-gate 				(**--finiarray)();
4190Sstevel@tonic-gate 			} while (--arraycnt != 0);
4200Sstevel@tonic-gate 			lmutex_lock(&tlsm->tls_lock);
4210Sstevel@tonic-gate 		}
4220Sstevel@tonic-gate 	}
4230Sstevel@tonic-gate 	lmutex_unlock(&tlsm->tls_lock);
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 	tls_free(self);
4260Sstevel@tonic-gate }
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate /*
4290Sstevel@tonic-gate  * We only free the dynamically allocated TLS; the statically
4300Sstevel@tonic-gate  * allocated TLS is reused when the ulwp_t is reallocated.
4310Sstevel@tonic-gate  */
4320Sstevel@tonic-gate void
tls_free(ulwp_t * ulwp)4330Sstevel@tonic-gate tls_free(ulwp_t *ulwp)
4340Sstevel@tonic-gate {
4350Sstevel@tonic-gate 	ulong_t moduleid;
4360Sstevel@tonic-gate 	tls_t *tlsent;
4370Sstevel@tonic-gate 	size_t ntlsent;
4380Sstevel@tonic-gate 	void *base;
4390Sstevel@tonic-gate 	size_t size;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	if ((tlsent = ulwp->ul_tlsent) == NULL ||
4420Sstevel@tonic-gate 	    (ntlsent = ulwp->ul_ntlsent) == 0)
4430Sstevel@tonic-gate 		return;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	for (moduleid = 0; moduleid < ntlsent; moduleid++, tlsent++) {
4460Sstevel@tonic-gate 		if ((base = tlsent->tls_data) != NULL &&
4470Sstevel@tonic-gate 		    (size = tlsent->tls_size) != 0)
4480Sstevel@tonic-gate 			lfree(base, size);
4490Sstevel@tonic-gate 		tlsent->tls_data = NULL;	/* paranoia */
4500Sstevel@tonic-gate 		tlsent->tls_size = 0;
4510Sstevel@tonic-gate 	}
4520Sstevel@tonic-gate 	lfree(ulwp->ul_tlsent, ntlsent * sizeof (tls_t));
4530Sstevel@tonic-gate 	ulwp->ul_tlsent = NULL;
4540Sstevel@tonic-gate 	ulwp->ul_ntlsent = 0;
4550Sstevel@tonic-gate }
456