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 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 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 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 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 * 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 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 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 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 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 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 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 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