1/* 2 * Copyright (c) 2000-2003, 2007, 2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991 25 * All Rights Reserved 26 * 27 * Permission to use, copy, modify, and distribute this software and 28 * its documentation for any purpose and without fee is hereby granted, 29 * provided that the above copyright notice appears in all copies and 30 * that both the copyright notice and this permission notice appear in 31 * supporting documentation. 32 * 33 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 34 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 35 * FOR A PARTICULAR PURPOSE. 36 * 37 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 38 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 39 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 40 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 41 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 42 * 43 */ 44/* 45 * MkLinux 46 */ 47 48/* 49 * POSIX Pthread Library 50 * Thread Specific Data support 51 * NB: pthread_getspecific() is in a separate assembly file 52 */ 53 54#include "internal.h" 55#include <TargetConditionals.h> 56 57#if !VARIANT_DYLD 58// __pthread_tsd_first is first static key managed by libpthread. 59// __pthread_tsd_max is the (observed) end of static key destructors. 60// __pthread_tsd_start is the start of dynamic keys. 61// __pthread_tsd_end is the end of dynamic keys. 62 63static const int __pthread_tsd_first = __TSD_RESERVED_MAX + 1; 64static int __pthread_tsd_max = __pthread_tsd_first; 65static const int __pthread_tsd_start = _INTERNAL_POSIX_THREAD_KEYS_MAX; 66static const int __pthread_tsd_end = _INTERNAL_POSIX_THREAD_KEYS_END; 67 68// Omit support for pthread key destructors in the static archive for dyld. 69// dyld does not create and destroy threads so these are not necessary. 70// 71// We store the bit-wise negation of the destructor so that a quick non-zero 72// test can be used to determine if the destructor has been set, even if it is 73// NULL. This means that a destructor of value ~0x0ull cannot be used. That 74// shouldn't be a problem in practice since it isn't a valid function address. 75 76static struct { 77 uintptr_t destructor; 78} _pthread_keys[_INTERNAL_POSIX_THREAD_KEYS_END]; 79 80static pthread_lock_t tsd_lock = LOCK_INITIALIZER; 81 82// Returns true if successful, false if destructor was already set. 83static bool 84_pthread_key_set_destructor(pthread_key_t key, void (*destructor)(void *)) 85{ 86 uintptr_t *ptr = &_pthread_keys[key].destructor; 87 uintptr_t value = ~(uintptr_t)destructor; 88 if (*ptr == 0) { 89 *ptr = value; 90 return true; 91 } 92 return false; 93} 94 95// Returns true if successful, false if the destructor was not set. 96static bool 97_pthread_key_unset_destructor(pthread_key_t key) 98{ 99 uintptr_t *ptr = &_pthread_keys[key].destructor; 100 if (*ptr != 0) { 101 *ptr = 0; 102 return true; 103 } 104 return false; 105} 106 107// Returns true if successful, false if the destructor was not set. 108static bool 109_pthread_key_get_destructor(pthread_key_t key, void (**destructor)(void *)) 110{ 111 uintptr_t value = _pthread_keys[key].destructor; 112 if (destructor) { 113 *destructor = (void (*)(void *))(~value); 114 } 115 return (value != 0); 116} 117 118int 119pthread_key_create(pthread_key_t *key, void (*destructor)(void *)) 120{ 121 int res = EAGAIN; // Returns EAGAIN if key cannot be allocated. 122 pthread_key_t k; 123 124 LOCK(tsd_lock); 125 for (k = __pthread_tsd_start; k < __pthread_tsd_end; k++) { 126 if (_pthread_key_set_destructor(k, destructor)) { 127 *key = k; 128 res = 0; 129 break; 130 } 131 } 132 UNLOCK(tsd_lock); 133 134 return res; 135} 136 137int 138pthread_key_delete(pthread_key_t key) 139{ 140 int res = EINVAL; // Returns EINVAL if key is not allocated. 141 142 LOCK(tsd_lock); 143 if (key >= __pthread_tsd_start && key < __pthread_tsd_end) { 144 if (_pthread_key_unset_destructor(key)) { 145 struct _pthread *p; 146 LOCK(_pthread_list_lock); 147 TAILQ_FOREACH(p, &__pthread_head, plist) { 148 // No lock for word-sized write. 149 p->tsd[key] = 0; 150 } 151 UNLOCK(_pthread_list_lock); 152 res = 0; 153 } 154 } 155 UNLOCK(tsd_lock); 156 157 return res; 158} 159#endif // !VARIANT_DYLD 160 161int 162pthread_setspecific(pthread_key_t key, const void *value) 163{ 164 int res = EINVAL; 165 166#if !VARIANT_DYLD 167 if (key >= __pthread_tsd_first && key < __pthread_tsd_end) { 168 bool created = _pthread_key_get_destructor(key, NULL); 169 if (key < __pthread_tsd_start || created) { 170 struct _pthread *self = pthread_self(); 171 self->tsd[key] = (void *)value; 172 res = 0; 173 174 if (key < __pthread_tsd_start) { 175 // XXX: is this really necessary? 176 _pthread_key_set_destructor(key, NULL); 177 } 178 if (key > self->max_tsd_key) { 179 self->max_tsd_key = (int)key; 180 } 181 } 182 } 183#endif // !VARIANT_DYLD 184 185 return res; 186} 187 188void* 189pthread_getspecific(pthread_key_t key) 190{ 191 return _pthread_getspecific_direct(key); 192} 193 194#if !VARIANT_DYLD 195static void 196_pthread_tsd_cleanup_key(pthread_t self, pthread_key_t key) 197{ 198 void (*destructor)(void *); 199 if (_pthread_key_get_destructor(key, &destructor)) { 200 void **ptr = &self->tsd[key]; 201 void *value = *ptr; 202 if (value) { 203 *ptr = NULL; 204 if (destructor) { 205 destructor(value); 206 } 207 } 208 } 209} 210#endif // !VARIANT_DYLD 211 212void 213_pthread_tsd_cleanup(pthread_t self) 214{ 215#if !VARIANT_DYLD 216 int j; 217 218 // clean up dynamic keys first 219 for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) { 220 pthread_key_t k; 221 for (k = __pthread_tsd_start; k <= self->max_tsd_key; k++) { 222 _pthread_tsd_cleanup_key(self, k); 223 } 224 } 225 226 self->max_tsd_key = 0; 227 228 // clean up static keys 229 for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) { 230 pthread_key_t k; 231 for (k = __pthread_tsd_first; k <= __pthread_tsd_max; k++) { 232 _pthread_tsd_cleanup_key(self, k); 233 } 234 } 235#endif // !VARIANT_DYLD 236} 237 238#if !VARIANT_DYLD 239// XXX: key should be pthread_key_t 240int 241pthread_key_init_np(int key, void (*destructor)(void *)) 242{ 243 int res = EINVAL; // Returns EINVAL if key is out of range. 244 if (key >= __pthread_tsd_first && key < __pthread_tsd_start) { 245 LOCK(tsd_lock); 246 _pthread_key_set_destructor(key, destructor); 247 if (key > __pthread_tsd_max) { 248 __pthread_tsd_max = key; 249 } 250 UNLOCK(tsd_lock); 251 res = 0; 252 } 253 return res; 254} 255#endif // !VARIANT_DYLD 256 257#undef pthread_self 258pthread_t 259pthread_self(void) 260{ 261 return _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF); 262} 263