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
5cb620785Sraf * Common Development and Distribution License (the "License").
6cb620785Sraf * 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 */
21cb620785Sraf
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 #pragma ident "%Z%%M% %I% %E% SMI"
287c478bd9Sstevel@tonic-gate
297c478bd9Sstevel@tonic-gate #include "lint.h"
307c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
317c478bd9Sstevel@tonic-gate #include <stddef.h>
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate /*
34*7257d1b4Sraf * These symbols should not be exported from libc, but
35*7257d1b4Sraf * /lib/libm.so.2 references them. libm needs to be fixed.
36*7257d1b4Sraf * Also, some older versions of the Studio compiler/debugger
37*7257d1b4Sraf * components reference them. These need to be fixed, too.
38*7257d1b4Sraf */
39*7257d1b4Sraf #pragma weak _thr_getspecific = thr_getspecific
40*7257d1b4Sraf #pragma weak _thr_keycreate = thr_keycreate
41*7257d1b4Sraf #pragma weak _thr_setspecific = thr_setspecific
42*7257d1b4Sraf
43*7257d1b4Sraf /*
447c478bd9Sstevel@tonic-gate * 128 million keys should be enough for anyone.
457c478bd9Sstevel@tonic-gate * This allocates half a gigabyte of memory for the keys themselves and
467c478bd9Sstevel@tonic-gate * half a gigabyte of memory for each thread that uses the largest key.
477c478bd9Sstevel@tonic-gate */
487c478bd9Sstevel@tonic-gate #define MAX_KEYS 0x08000000U
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate int
thr_keycreate(thread_key_t * pkey,void (* destructor)(void *))51*7257d1b4Sraf thr_keycreate(thread_key_t *pkey, void (*destructor)(void *))
527c478bd9Sstevel@tonic-gate {
537c478bd9Sstevel@tonic-gate tsd_metadata_t *tsdm = &curthread->ul_uberdata->tsd_metadata;
547c478bd9Sstevel@tonic-gate void (**old_data)(void *) = NULL;
557c478bd9Sstevel@tonic-gate void (**new_data)(void *);
567c478bd9Sstevel@tonic-gate uint_t old_nkeys;
577c478bd9Sstevel@tonic-gate uint_t new_nkeys;
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate lmutex_lock(&tsdm->tsdm_lock);
607c478bd9Sstevel@tonic-gate
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate * Unfortunately, pthread_getspecific() specifies that a
637c478bd9Sstevel@tonic-gate * pthread_getspecific() on an allocated key upon which the
647c478bd9Sstevel@tonic-gate * calling thread has not performed a pthread_setspecifc()
657c478bd9Sstevel@tonic-gate * must return NULL. Consider the following sequence:
667c478bd9Sstevel@tonic-gate *
677c478bd9Sstevel@tonic-gate * pthread_key_create(&key);
687c478bd9Sstevel@tonic-gate * pthread_setspecific(key, datum);
697c478bd9Sstevel@tonic-gate * pthread_key_delete(&key);
707c478bd9Sstevel@tonic-gate * pthread_key_create(&key);
717c478bd9Sstevel@tonic-gate * val = pthread_getspecific(key);
727c478bd9Sstevel@tonic-gate *
737c478bd9Sstevel@tonic-gate * According to POSIX, if the deleted key is reused for the new
747c478bd9Sstevel@tonic-gate * key returned by the second pthread_key_create(), then the
757c478bd9Sstevel@tonic-gate * pthread_getspecific() in the above example must return NULL
767c478bd9Sstevel@tonic-gate * (and not the stale datum). The implementation is thus left
777c478bd9Sstevel@tonic-gate * with two alternatives:
787c478bd9Sstevel@tonic-gate *
797c478bd9Sstevel@tonic-gate * (1) Reuse deleted keys. If this is to be implemented optimally,
807c478bd9Sstevel@tonic-gate * it requires that pthread_key_create() somehow associate
817c478bd9Sstevel@tonic-gate * the value NULL with the new (reused) key for each thread.
827c478bd9Sstevel@tonic-gate * Keeping the hot path fast and lock-free induces substantial
837c478bd9Sstevel@tonic-gate * complexity on the implementation.
847c478bd9Sstevel@tonic-gate *
857c478bd9Sstevel@tonic-gate * (2) Never reuse deleted keys. This allows the pthread_getspecific()
867c478bd9Sstevel@tonic-gate * implementation to simply perform a check against the number
877c478bd9Sstevel@tonic-gate * of keys set by the calling thread, returning NULL if the
887c478bd9Sstevel@tonic-gate * specified key is larger than the highest set key. This has
897c478bd9Sstevel@tonic-gate * the disadvantage of wasting memory (a program which simply
907c478bd9Sstevel@tonic-gate * loops calling pthread_key_create()/pthread_key_delete()
917c478bd9Sstevel@tonic-gate * will ultimately run out of memory), but permits an optimal
927c478bd9Sstevel@tonic-gate * pthread_getspecific() while allowing for simple key creation
937c478bd9Sstevel@tonic-gate * and deletion.
947c478bd9Sstevel@tonic-gate *
957c478bd9Sstevel@tonic-gate * All Solaris implementations have opted for (2). Given the
967c478bd9Sstevel@tonic-gate * ~10 years that this has been in the field, it is safe to assume
977c478bd9Sstevel@tonic-gate * that applications don't loop creating and destroying keys; we
987c478bd9Sstevel@tonic-gate * stick with (2).
997c478bd9Sstevel@tonic-gate */
1007c478bd9Sstevel@tonic-gate if (tsdm->tsdm_nused == (old_nkeys = tsdm->tsdm_nkeys)) {
1017c478bd9Sstevel@tonic-gate /*
1027c478bd9Sstevel@tonic-gate * We need to allocate or double the number of keys.
1037c478bd9Sstevel@tonic-gate * tsdm->tsdm_nused must always be a power of two.
1047c478bd9Sstevel@tonic-gate */
1057c478bd9Sstevel@tonic-gate if ((new_nkeys = (old_nkeys << 1)) == 0)
1067c478bd9Sstevel@tonic-gate new_nkeys = 8;
1077c478bd9Sstevel@tonic-gate
1087c478bd9Sstevel@tonic-gate if (new_nkeys > MAX_KEYS) {
1097c478bd9Sstevel@tonic-gate lmutex_unlock(&tsdm->tsdm_lock);
1107c478bd9Sstevel@tonic-gate return (EAGAIN);
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate if ((new_data = lmalloc(new_nkeys * sizeof (void *))) == NULL) {
1137c478bd9Sstevel@tonic-gate lmutex_unlock(&tsdm->tsdm_lock);
1147c478bd9Sstevel@tonic-gate return (ENOMEM);
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate if ((old_data = tsdm->tsdm_destro) == NULL) {
1177c478bd9Sstevel@tonic-gate /* key == 0 is always invalid */
1187c478bd9Sstevel@tonic-gate new_data[0] = TSD_UNALLOCATED;
1197c478bd9Sstevel@tonic-gate tsdm->tsdm_nused = 1;
1207c478bd9Sstevel@tonic-gate } else {
1218cd45542Sraf (void) memcpy(new_data, old_data,
1227c478bd9Sstevel@tonic-gate old_nkeys * sizeof (void *));
1237c478bd9Sstevel@tonic-gate }
1247c478bd9Sstevel@tonic-gate tsdm->tsdm_destro = new_data;
1257c478bd9Sstevel@tonic-gate tsdm->tsdm_nkeys = new_nkeys;
1267c478bd9Sstevel@tonic-gate }
1277c478bd9Sstevel@tonic-gate
1287c478bd9Sstevel@tonic-gate *pkey = tsdm->tsdm_nused;
1297c478bd9Sstevel@tonic-gate tsdm->tsdm_destro[tsdm->tsdm_nused++] = destructor;
1307c478bd9Sstevel@tonic-gate lmutex_unlock(&tsdm->tsdm_lock);
1317c478bd9Sstevel@tonic-gate
1327c478bd9Sstevel@tonic-gate if (old_data != NULL)
1337c478bd9Sstevel@tonic-gate lfree(old_data, old_nkeys * sizeof (void *));
1347c478bd9Sstevel@tonic-gate
1357c478bd9Sstevel@tonic-gate return (0);
1367c478bd9Sstevel@tonic-gate }
1377c478bd9Sstevel@tonic-gate
138*7257d1b4Sraf #pragma weak _pthread_key_create = pthread_key_create
139*7257d1b4Sraf int
pthread_key_create(pthread_key_t * pkey,void (* destructor)(void *))140*7257d1b4Sraf pthread_key_create(pthread_key_t *pkey, void (*destructor)(void *))
141*7257d1b4Sraf {
142*7257d1b4Sraf return (thr_keycreate(pkey, destructor));
143*7257d1b4Sraf }
144*7257d1b4Sraf
145cb620785Sraf /*
146*7257d1b4Sraf * Same as thr_keycreate(), above, except that the key creation
147cb620785Sraf * is performed only once. This relies upon the fact that a key
148cb620785Sraf * value of THR_ONCE_KEY is invalid, and requires that the key be
149cb620785Sraf * allocated with a value of THR_ONCE_KEY before calling here.
150cb620785Sraf * THR_ONCE_KEY and PTHREAD_ONCE_KEY_NP, defined in <thread.h>
151cb620785Sraf * and <pthread.h> respectively, must have the same value.
152cb620785Sraf * Example:
153cb620785Sraf *
154cb620785Sraf * static pthread_key_t key = PTHREAD_ONCE_KEY_NP;
155cb620785Sraf * ...
156cb620785Sraf * pthread_key_create_once_np(&key, destructor);
157cb620785Sraf */
158*7257d1b4Sraf #pragma weak pthread_key_create_once_np = thr_keycreate_once
159cb620785Sraf int
thr_keycreate_once(thread_key_t * keyp,void (* destructor)(void *))160*7257d1b4Sraf thr_keycreate_once(thread_key_t *keyp, void (*destructor)(void *))
161cb620785Sraf {
162cb620785Sraf static mutex_t key_lock = DEFAULTMUTEX;
163cb620785Sraf thread_key_t key;
164cb620785Sraf int error;
165cb620785Sraf
166cb620785Sraf if (*keyp == THR_ONCE_KEY) {
167cb620785Sraf lmutex_lock(&key_lock);
168cb620785Sraf if (*keyp == THR_ONCE_KEY) {
169*7257d1b4Sraf error = thr_keycreate(&key, destructor);
170cb620785Sraf if (error) {
171cb620785Sraf lmutex_unlock(&key_lock);
172cb620785Sraf return (error);
173cb620785Sraf }
174*7257d1b4Sraf membar_producer();
175cb620785Sraf *keyp = key;
176cb620785Sraf }
177cb620785Sraf lmutex_unlock(&key_lock);
178cb620785Sraf }
179*7257d1b4Sraf membar_consumer();
180cb620785Sraf
181cb620785Sraf return (0);
182cb620785Sraf }
183cb620785Sraf
1847c478bd9Sstevel@tonic-gate int
pthread_key_delete(pthread_key_t key)185*7257d1b4Sraf pthread_key_delete(pthread_key_t key)
1867c478bd9Sstevel@tonic-gate {
1877c478bd9Sstevel@tonic-gate tsd_metadata_t *tsdm = &curthread->ul_uberdata->tsd_metadata;
1887c478bd9Sstevel@tonic-gate
1897c478bd9Sstevel@tonic-gate lmutex_lock(&tsdm->tsdm_lock);
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate if (key >= tsdm->tsdm_nused ||
1927c478bd9Sstevel@tonic-gate tsdm->tsdm_destro[key] == TSD_UNALLOCATED) {
1937c478bd9Sstevel@tonic-gate lmutex_unlock(&tsdm->tsdm_lock);
1947c478bd9Sstevel@tonic-gate return (EINVAL);
1957c478bd9Sstevel@tonic-gate }
1967c478bd9Sstevel@tonic-gate
1977c478bd9Sstevel@tonic-gate tsdm->tsdm_destro[key] = TSD_UNALLOCATED;
1987c478bd9Sstevel@tonic-gate lmutex_unlock(&tsdm->tsdm_lock);
1997c478bd9Sstevel@tonic-gate
2007c478bd9Sstevel@tonic-gate return (0);
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate /*
2047c478bd9Sstevel@tonic-gate * Blessedly, the pthread_getspecific() interface is much better than the
2057c478bd9Sstevel@tonic-gate * thr_getspecific() interface in that it cannot return an error status.
2067c478bd9Sstevel@tonic-gate * Thus, if the key specified is bogus, pthread_getspecific()'s behavior
2077c478bd9Sstevel@tonic-gate * is undefined. As an added bonus (and as an artificat of not returning
2087c478bd9Sstevel@tonic-gate * an error code), the requested datum is returned rather than stored
2097c478bd9Sstevel@tonic-gate * through a parameter -- thereby avoiding the unnecessary store/load pair
2107c478bd9Sstevel@tonic-gate * incurred by thr_getspecific(). Every once in a while, the Standards
2117c478bd9Sstevel@tonic-gate * get it right -- but usually by accident.
2127c478bd9Sstevel@tonic-gate */
2137c478bd9Sstevel@tonic-gate void *
pthread_getspecific(pthread_key_t key)214*7257d1b4Sraf pthread_getspecific(pthread_key_t key)
2157c478bd9Sstevel@tonic-gate {
2167c478bd9Sstevel@tonic-gate tsd_t *stsd;
2177c478bd9Sstevel@tonic-gate
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate * We are cycle-shaving in this function because some
2207c478bd9Sstevel@tonic-gate * applications make heavy use of it and one machine cycle
2217c478bd9Sstevel@tonic-gate * can make a measurable difference in performance. This
2227c478bd9Sstevel@tonic-gate * is why we waste a little memory and allocate a NULL value
2237c478bd9Sstevel@tonic-gate * for the invalid key == 0 in curthread->ul_ftsd[0] rather
2247c478bd9Sstevel@tonic-gate * than adjusting the key by subtracting one.
2257c478bd9Sstevel@tonic-gate */
2267c478bd9Sstevel@tonic-gate if (key < TSD_NFAST)
2277c478bd9Sstevel@tonic-gate return (curthread->ul_ftsd[key]);
2287c478bd9Sstevel@tonic-gate
2297c478bd9Sstevel@tonic-gate if ((stsd = curthread->ul_stsd) != NULL && key < stsd->tsd_nalloc)
2307c478bd9Sstevel@tonic-gate return (stsd->tsd_data[key]);
2317c478bd9Sstevel@tonic-gate
2327c478bd9Sstevel@tonic-gate return (NULL);
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate
2357c478bd9Sstevel@tonic-gate int
thr_getspecific(thread_key_t key,void ** valuep)236*7257d1b4Sraf thr_getspecific(thread_key_t key, void **valuep)
2377c478bd9Sstevel@tonic-gate {
2387c478bd9Sstevel@tonic-gate tsd_t *stsd;
2397c478bd9Sstevel@tonic-gate
2407c478bd9Sstevel@tonic-gate /*
2417c478bd9Sstevel@tonic-gate * Amazingly, some application code (and worse, some particularly
2427c478bd9Sstevel@tonic-gate * fugly Solaris library code) _relies_ on the fact that 0 is always
2437c478bd9Sstevel@tonic-gate * an invalid key. To preserve this semantic, 0 is never returned
2447c478bd9Sstevel@tonic-gate * as a key from thr_/pthread_key_create(); we explicitly check
2457c478bd9Sstevel@tonic-gate * for it here and return EINVAL.
2467c478bd9Sstevel@tonic-gate */
2477c478bd9Sstevel@tonic-gate if (key == 0)
2487c478bd9Sstevel@tonic-gate return (EINVAL);
2497c478bd9Sstevel@tonic-gate
2507c478bd9Sstevel@tonic-gate if (key < TSD_NFAST)
2517c478bd9Sstevel@tonic-gate *valuep = curthread->ul_ftsd[key];
2527c478bd9Sstevel@tonic-gate else if ((stsd = curthread->ul_stsd) != NULL && key < stsd->tsd_nalloc)
2537c478bd9Sstevel@tonic-gate *valuep = stsd->tsd_data[key];
2547c478bd9Sstevel@tonic-gate else
2557c478bd9Sstevel@tonic-gate *valuep = NULL;
2567c478bd9Sstevel@tonic-gate
2577c478bd9Sstevel@tonic-gate return (0);
2587c478bd9Sstevel@tonic-gate }
2597c478bd9Sstevel@tonic-gate
2607c478bd9Sstevel@tonic-gate /*
261*7257d1b4Sraf * We call thr_setspecific_slow() when the key specified
2627c478bd9Sstevel@tonic-gate * is beyond the current thread's currently allocated range.
2637c478bd9Sstevel@tonic-gate * This case is in a separate function because we want
2647c478bd9Sstevel@tonic-gate * the compiler to optimize for the common case.
2657c478bd9Sstevel@tonic-gate */
2667c478bd9Sstevel@tonic-gate static int
thr_setspecific_slow(thread_key_t key,void * value)267*7257d1b4Sraf thr_setspecific_slow(thread_key_t key, void *value)
2687c478bd9Sstevel@tonic-gate {
2697c478bd9Sstevel@tonic-gate ulwp_t *self = curthread;
2707c478bd9Sstevel@tonic-gate tsd_metadata_t *tsdm = &self->ul_uberdata->tsd_metadata;
2717c478bd9Sstevel@tonic-gate tsd_t *stsd;
2727c478bd9Sstevel@tonic-gate tsd_t *ntsd;
2737c478bd9Sstevel@tonic-gate uint_t nkeys;
2747c478bd9Sstevel@tonic-gate
2757c478bd9Sstevel@tonic-gate /*
2767c478bd9Sstevel@tonic-gate * It isn't necessary to grab locks in this path;
2777c478bd9Sstevel@tonic-gate * tsdm->tsdm_nused can only increase.
2787c478bd9Sstevel@tonic-gate */
2797c478bd9Sstevel@tonic-gate if (key >= tsdm->tsdm_nused)
2807c478bd9Sstevel@tonic-gate return (EINVAL);
2817c478bd9Sstevel@tonic-gate
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate * We would like to test (tsdm->tsdm_destro[key] == TSD_UNALLOCATED)
2847c478bd9Sstevel@tonic-gate * here but that would require acquiring tsdm->tsdm_lock and we
2857c478bd9Sstevel@tonic-gate * want to avoid locks in this path.
2867c478bd9Sstevel@tonic-gate *
2877c478bd9Sstevel@tonic-gate * We have a key which is (or at least _was_) valid. If this key
2887c478bd9Sstevel@tonic-gate * is later deleted (or indeed, is deleted before we set the value),
2897c478bd9Sstevel@tonic-gate * we don't care; such a condition would indicate an application
2907c478bd9Sstevel@tonic-gate * race for which POSIX thankfully leaves the behavior unspecified.
2917c478bd9Sstevel@tonic-gate *
2927c478bd9Sstevel@tonic-gate * First, determine our new size. To avoid allocating more than we
2937c478bd9Sstevel@tonic-gate * have to, continue doubling our size only until the new key fits.
2947c478bd9Sstevel@tonic-gate * stsd->tsd_nalloc must always be a power of two.
2957c478bd9Sstevel@tonic-gate */
2967c478bd9Sstevel@tonic-gate nkeys = ((stsd = self->ul_stsd) != NULL)? stsd->tsd_nalloc : 8;
2977c478bd9Sstevel@tonic-gate for (; key >= nkeys; nkeys <<= 1)
2987c478bd9Sstevel@tonic-gate continue;
2997c478bd9Sstevel@tonic-gate
3007c478bd9Sstevel@tonic-gate /*
3017c478bd9Sstevel@tonic-gate * Allocate the new TSD.
3027c478bd9Sstevel@tonic-gate */
3037c478bd9Sstevel@tonic-gate if ((ntsd = lmalloc(nkeys * sizeof (void *))) == NULL)
3047c478bd9Sstevel@tonic-gate return (ENOMEM);
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate if (stsd != NULL) {
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate * Copy the old TSD across to the new.
3097c478bd9Sstevel@tonic-gate */
3108cd45542Sraf (void) memcpy(ntsd, stsd, stsd->tsd_nalloc * sizeof (void *));
3117c478bd9Sstevel@tonic-gate lfree(stsd, stsd->tsd_nalloc * sizeof (void *));
3127c478bd9Sstevel@tonic-gate }
3137c478bd9Sstevel@tonic-gate
3147c478bd9Sstevel@tonic-gate ntsd->tsd_nalloc = nkeys;
3157c478bd9Sstevel@tonic-gate ntsd->tsd_data[key] = value;
3167c478bd9Sstevel@tonic-gate self->ul_stsd = ntsd;
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate return (0);
3197c478bd9Sstevel@tonic-gate }
3207c478bd9Sstevel@tonic-gate
3217c478bd9Sstevel@tonic-gate int
thr_setspecific(thread_key_t key,void * value)322*7257d1b4Sraf thr_setspecific(thread_key_t key, void *value)
3237c478bd9Sstevel@tonic-gate {
3247c478bd9Sstevel@tonic-gate tsd_t *stsd;
3257c478bd9Sstevel@tonic-gate int ret;
3267c478bd9Sstevel@tonic-gate ulwp_t *self = curthread;
3277c478bd9Sstevel@tonic-gate
3287c478bd9Sstevel@tonic-gate /*
329*7257d1b4Sraf * See the comment in thr_getspecific(), above.
3307c478bd9Sstevel@tonic-gate */
3317c478bd9Sstevel@tonic-gate if (key == 0)
3327c478bd9Sstevel@tonic-gate return (EINVAL);
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate if (key < TSD_NFAST) {
3357c478bd9Sstevel@tonic-gate curthread->ul_ftsd[key] = value;
3367c478bd9Sstevel@tonic-gate return (0);
3377c478bd9Sstevel@tonic-gate }
3387c478bd9Sstevel@tonic-gate
3397c478bd9Sstevel@tonic-gate if ((stsd = curthread->ul_stsd) != NULL && key < stsd->tsd_nalloc) {
3407c478bd9Sstevel@tonic-gate stsd->tsd_data[key] = value;
3417c478bd9Sstevel@tonic-gate return (0);
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate
3447c478bd9Sstevel@tonic-gate /*
3457c478bd9Sstevel@tonic-gate * This is a critical region since we are dealing with memory
3467c478bd9Sstevel@tonic-gate * allocation and free. Similar protection required in tsd_free().
3477c478bd9Sstevel@tonic-gate */
3487c478bd9Sstevel@tonic-gate enter_critical(self);
349*7257d1b4Sraf ret = thr_setspecific_slow(key, value);
3507c478bd9Sstevel@tonic-gate exit_critical(self);
3517c478bd9Sstevel@tonic-gate return (ret);
3527c478bd9Sstevel@tonic-gate }
3537c478bd9Sstevel@tonic-gate
354*7257d1b4Sraf int
pthread_setspecific(pthread_key_t key,const void * value)355*7257d1b4Sraf pthread_setspecific(pthread_key_t key, const void *value)
356*7257d1b4Sraf {
357*7257d1b4Sraf return (thr_setspecific(key, (void *)value));
358*7257d1b4Sraf }
359*7257d1b4Sraf
3607c478bd9Sstevel@tonic-gate /*
3617c478bd9Sstevel@tonic-gate * Contract-private interface for java. See PSARC/2003/159
3627c478bd9Sstevel@tonic-gate *
3637c478bd9Sstevel@tonic-gate * If the key falls within the TSD_NFAST range, return a non-negative
3647c478bd9Sstevel@tonic-gate * offset that can be used by the caller to fetch the TSD data value
3657c478bd9Sstevel@tonic-gate * directly out of the thread structure using %g7 (sparc) or %gs (x86).
3667c478bd9Sstevel@tonic-gate * With the advent of TLS, %g7 and %gs are part of the ABI, even though
3677c478bd9Sstevel@tonic-gate * the definition of the thread structure itself (ulwp_t) is private.
3687c478bd9Sstevel@tonic-gate *
3697c478bd9Sstevel@tonic-gate * We guarantee that the offset returned on sparc will fit within
3707c478bd9Sstevel@tonic-gate * a SIMM13 field (that is, it is less than 2048).
3717c478bd9Sstevel@tonic-gate *
3727c478bd9Sstevel@tonic-gate * On failure (key is not in the TSD_NFAST range), return -1.
3737c478bd9Sstevel@tonic-gate */
3747c478bd9Sstevel@tonic-gate ptrdiff_t
_thr_slot_offset(thread_key_t key)3757c478bd9Sstevel@tonic-gate _thr_slot_offset(thread_key_t key)
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate if (key != 0 && key < TSD_NFAST)
3787c478bd9Sstevel@tonic-gate return ((ptrdiff_t)offsetof(ulwp_t, ul_ftsd[key]));
3797c478bd9Sstevel@tonic-gate return (-1);
3807c478bd9Sstevel@tonic-gate }
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate /*
3837c478bd9Sstevel@tonic-gate * This is called by _thrp_exit() to apply destructors to the thread's tsd.
3847c478bd9Sstevel@tonic-gate */
3857c478bd9Sstevel@tonic-gate void
tsd_exit()3867c478bd9Sstevel@tonic-gate tsd_exit()
3877c478bd9Sstevel@tonic-gate {
3887c478bd9Sstevel@tonic-gate ulwp_t *self = curthread;
3897c478bd9Sstevel@tonic-gate tsd_metadata_t *tsdm = &self->ul_uberdata->tsd_metadata;
3907c478bd9Sstevel@tonic-gate thread_key_t key;
3917c478bd9Sstevel@tonic-gate int recheck;
3927c478bd9Sstevel@tonic-gate void *val;
3937c478bd9Sstevel@tonic-gate void (*func)(void *);
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate lmutex_lock(&tsdm->tsdm_lock);
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate do {
3987c478bd9Sstevel@tonic-gate recheck = 0;
3997c478bd9Sstevel@tonic-gate
4007c478bd9Sstevel@tonic-gate for (key = 1; key < TSD_NFAST &&
4017c478bd9Sstevel@tonic-gate key < tsdm->tsdm_nused; key++) {
4027c478bd9Sstevel@tonic-gate if ((func = tsdm->tsdm_destro[key]) != NULL &&
4037c478bd9Sstevel@tonic-gate func != TSD_UNALLOCATED &&
4047c478bd9Sstevel@tonic-gate (val = self->ul_ftsd[key]) != NULL) {
4057c478bd9Sstevel@tonic-gate self->ul_ftsd[key] = NULL;
4067c478bd9Sstevel@tonic-gate lmutex_unlock(&tsdm->tsdm_lock);
4077c478bd9Sstevel@tonic-gate (*func)(val);
4087c478bd9Sstevel@tonic-gate lmutex_lock(&tsdm->tsdm_lock);
4097c478bd9Sstevel@tonic-gate recheck = 1;
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate
4137c478bd9Sstevel@tonic-gate if (self->ul_stsd == NULL)
4147c478bd9Sstevel@tonic-gate continue;
4157c478bd9Sstevel@tonic-gate
4167c478bd9Sstevel@tonic-gate /*
4177c478bd9Sstevel@tonic-gate * Any of these destructors could cause us to grow the number
4187c478bd9Sstevel@tonic-gate * TSD keys in the slow TSD; we cannot cache the slow TSD
4197c478bd9Sstevel@tonic-gate * pointer through this loop.
4207c478bd9Sstevel@tonic-gate */
4217c478bd9Sstevel@tonic-gate for (; key < self->ul_stsd->tsd_nalloc &&
4227c478bd9Sstevel@tonic-gate key < tsdm->tsdm_nused; key++) {
4237c478bd9Sstevel@tonic-gate if ((func = tsdm->tsdm_destro[key]) != NULL &&
4247c478bd9Sstevel@tonic-gate func != TSD_UNALLOCATED &&
4257c478bd9Sstevel@tonic-gate (val = self->ul_stsd->tsd_data[key]) != NULL) {
4267c478bd9Sstevel@tonic-gate self->ul_stsd->tsd_data[key] = NULL;
4277c478bd9Sstevel@tonic-gate lmutex_unlock(&tsdm->tsdm_lock);
4287c478bd9Sstevel@tonic-gate (*func)(val);
4297c478bd9Sstevel@tonic-gate lmutex_lock(&tsdm->tsdm_lock);
4307c478bd9Sstevel@tonic-gate recheck = 1;
4317c478bd9Sstevel@tonic-gate }
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate } while (recheck);
4347c478bd9Sstevel@tonic-gate
4357c478bd9Sstevel@tonic-gate lmutex_unlock(&tsdm->tsdm_lock);
4367c478bd9Sstevel@tonic-gate
4377c478bd9Sstevel@tonic-gate /*
4387c478bd9Sstevel@tonic-gate * We're done; if we have slow TSD, we need to free it.
4397c478bd9Sstevel@tonic-gate */
4407c478bd9Sstevel@tonic-gate tsd_free(self);
4417c478bd9Sstevel@tonic-gate }
4427c478bd9Sstevel@tonic-gate
4437c478bd9Sstevel@tonic-gate void
tsd_free(ulwp_t * ulwp)4447c478bd9Sstevel@tonic-gate tsd_free(ulwp_t *ulwp)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate tsd_t *stsd;
4477c478bd9Sstevel@tonic-gate ulwp_t *self = curthread;
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate enter_critical(self);
4507c478bd9Sstevel@tonic-gate if ((stsd = ulwp->ul_stsd) != NULL)
4517c478bd9Sstevel@tonic-gate lfree(stsd, stsd->tsd_nalloc * sizeof (void *));
4527c478bd9Sstevel@tonic-gate ulwp->ul_stsd = NULL;
4537c478bd9Sstevel@tonic-gate exit_critical(self);
4547c478bd9Sstevel@tonic-gate }
455