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