1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <pthread.h> 30 31 #include "bionic_tls.h" 32 #include "pthread_internal.h" 33 34 /* A technical note regarding our thread-local-storage (TLS) implementation: 35 * 36 * There can be up to BIONIC_TLS_SLOTS independent TLS keys in a given process, 37 * The keys below TLS_SLOT_FIRST_USER_SLOT are reserved for Bionic to hold 38 * special thread-specific variables like errno or a pointer to 39 * the current thread's descriptor. These entries cannot be accessed through 40 * pthread_getspecific() / pthread_setspecific() or pthread_key_delete() 41 * 42 * The 'tls_map_t' type defined below implements a shared global map of 43 * currently created/allocated TLS keys and the destructors associated 44 * with them. 45 * 46 * The global TLS map simply contains a bitmap of allocated keys, and 47 * an array of destructors. 48 * 49 * Each thread has a TLS area that is a simple array of BIONIC_TLS_SLOTS void* 50 * pointers. the TLS area of the main thread is stack-allocated in 51 * __libc_init_common, while the TLS area of other threads is placed at 52 * the top of their stack in pthread_create. 53 * 54 * When pthread_key_delete() is called it will erase the key's bitmap bit 55 * and its destructor, and will also clear the key data in the TLS area of 56 * all created threads. As mandated by Posix, it is the responsibility of 57 * the caller of pthread_key_delete() to properly reclaim the objects that 58 * were pointed to by these data fields (either before or after the call). 59 */ 60 61 #define TLSMAP_BITS 32 62 #define TLSMAP_WORDS ((BIONIC_TLS_SLOTS+TLSMAP_BITS-1)/TLSMAP_BITS) 63 #define TLSMAP_WORD(m,k) (m).map[(k)/TLSMAP_BITS] 64 #define TLSMAP_MASK(k) (1U << ((k)&(TLSMAP_BITS-1))) 65 66 static inline bool IsValidUserKey(pthread_key_t key) { 67 return (key >= TLS_SLOT_FIRST_USER_SLOT && key < BIONIC_TLS_SLOTS); 68 } 69 70 typedef void (*key_destructor_t)(void*); 71 72 struct tls_map_t { 73 bool is_initialized; 74 75 /* bitmap of allocated keys */ 76 uint32_t map[TLSMAP_WORDS]; 77 78 key_destructor_t key_destructors[BIONIC_TLS_SLOTS]; 79 }; 80 81 class ScopedTlsMapAccess { 82 public: 83 ScopedTlsMapAccess() { 84 Lock(); 85 86 // If this is the first time the TLS map has been accessed, 87 // mark the slots belonging to well-known keys as being in use. 88 // This isn't currently necessary because the well-known keys 89 // can only be accessed directly by bionic itself, do not have 90 // destructors, and all the functions that touch the TLS map 91 // start after the maximum well-known slot. 92 if (!s_tls_map_.is_initialized) { 93 for (pthread_key_t key = 0; key < TLS_SLOT_FIRST_USER_SLOT; ++key) { 94 SetInUse(key, NULL); 95 } 96 s_tls_map_.is_initialized = true; 97 } 98 } 99 100 ~ScopedTlsMapAccess() { 101 Unlock(); 102 } 103 104 int CreateKey(pthread_key_t* result, void (*key_destructor)(void*)) { 105 // Take the first unallocated key. 106 for (int key = 0; key < BIONIC_TLS_SLOTS; ++key) { 107 if (!IsInUse(key)) { 108 SetInUse(key, key_destructor); 109 *result = key; 110 return 0; 111 } 112 } 113 114 // We hit PTHREAD_KEYS_MAX. POSIX says EAGAIN for this case. 115 return EAGAIN; 116 } 117 118 void DeleteKey(pthread_key_t key) { 119 TLSMAP_WORD(s_tls_map_, key) &= ~TLSMAP_MASK(key); 120 s_tls_map_.key_destructors[key] = NULL; 121 } 122 123 bool IsInUse(pthread_key_t key) { 124 return (TLSMAP_WORD(s_tls_map_, key) & TLSMAP_MASK(key)) != 0; 125 } 126 127 void SetInUse(pthread_key_t key, void (*key_destructor)(void*)) { 128 TLSMAP_WORD(s_tls_map_, key) |= TLSMAP_MASK(key); 129 s_tls_map_.key_destructors[key] = key_destructor; 130 } 131 132 // Called from pthread_exit() to remove all TLS key data 133 // from this thread's TLS area. This must call the destructor of all keys 134 // that have a non-NULL data value and a non-NULL destructor. 135 void CleanAll() { 136 void** tls = (void**)__get_tls(); 137 138 // Because destructors can do funky things like deleting/creating other 139 // keys, we need to implement this in a loop. 140 for (int rounds = PTHREAD_DESTRUCTOR_ITERATIONS; rounds > 0; --rounds) { 141 size_t called_destructor_count = 0; 142 for (int key = 0; key < BIONIC_TLS_SLOTS; ++key) { 143 if (IsInUse(key)) { 144 void* data = tls[key]; 145 void (*key_destructor)(void*) = s_tls_map_.key_destructors[key]; 146 147 if (data != NULL && key_destructor != NULL) { 148 // we need to clear the key data now, this will prevent the 149 // destructor (or a later one) from seeing the old value if 150 // it calls pthread_getspecific() for some odd reason 151 152 // we do not do this if 'key_destructor == NULL' just in case another 153 // destructor function might be responsible for manually 154 // releasing the corresponding data. 155 tls[key] = NULL; 156 157 // because the destructor is free to call pthread_key_create 158 // and/or pthread_key_delete, we need to temporarily unlock 159 // the TLS map 160 Unlock(); 161 (*key_destructor)(data); 162 Lock(); 163 ++called_destructor_count; 164 } 165 } 166 } 167 168 // If we didn't call any destructors, there is no need to check the TLS data again. 169 if (called_destructor_count == 0) { 170 break; 171 } 172 } 173 } 174 175 private: 176 static tls_map_t s_tls_map_; 177 static pthread_mutex_t s_tls_map_lock_; 178 179 void Lock() { 180 pthread_mutex_lock(&s_tls_map_lock_); 181 } 182 183 void Unlock() { 184 pthread_mutex_unlock(&s_tls_map_lock_); 185 } 186 }; 187 188 __LIBC_HIDDEN__ tls_map_t ScopedTlsMapAccess::s_tls_map_; 189 __LIBC_HIDDEN__ pthread_mutex_t ScopedTlsMapAccess::s_tls_map_lock_; 190 191 __LIBC_HIDDEN__ void pthread_key_clean_all() { 192 ScopedTlsMapAccess tls_map; 193 tls_map.CleanAll(); 194 } 195 196 int pthread_key_create(pthread_key_t* key, void (*key_destructor)(void*)) { 197 ScopedTlsMapAccess tls_map; 198 return tls_map.CreateKey(key, key_destructor); 199 } 200 201 // Deletes a pthread_key_t. note that the standard mandates that this does 202 // not call the destructors for non-NULL key values. Instead, it is the 203 // responsibility of the caller to properly dispose of the corresponding data 204 // and resources, using any means it finds suitable. 205 int pthread_key_delete(pthread_key_t key) { 206 ScopedTlsMapAccess tls_map; 207 208 if (!IsValidUserKey(key) || !tls_map.IsInUse(key)) { 209 return EINVAL; 210 } 211 212 // Clear value in all threads. 213 pthread_mutex_lock(&gThreadListLock); 214 for (pthread_internal_t* t = gThreadList; t != NULL; t = t->next) { 215 // Skip zombie threads. They don't have a valid TLS area any more. 216 // Similarly, it is possible to have t->tls == NULL for threads that 217 // were just recently created through pthread_create() but whose 218 // startup trampoline (__thread_entry) hasn't been run yet by the 219 // scheduler. t->tls will also be NULL after a thread's stack has been 220 // unmapped but before the ongoing pthread_join() is finished. 221 if ((t->attr.flags & PTHREAD_ATTR_FLAG_ZOMBIE) || t->tls == NULL) { 222 continue; 223 } 224 225 t->tls[key] = NULL; 226 } 227 tls_map.DeleteKey(key); 228 229 pthread_mutex_unlock(&gThreadListLock); 230 return 0; 231 } 232 233 void* pthread_getspecific(pthread_key_t key) { 234 if (!IsValidUserKey(key)) { 235 return NULL; 236 } 237 238 // For performance reasons, we do not lock/unlock the global TLS map 239 // to check that the key is properly allocated. If the key was not 240 // allocated, the value read from the TLS should always be NULL 241 // due to pthread_key_delete() clearing the values for all threads. 242 return (void *)(((unsigned *)__get_tls())[key]); 243 } 244 245 int pthread_setspecific(pthread_key_t key, const void* ptr) { 246 ScopedTlsMapAccess tls_map; 247 248 if (!IsValidUserKey(key) || !tls_map.IsInUse(key)) { 249 return EINVAL; 250 } 251 252 ((uint32_t *)__get_tls())[key] = (uint32_t)ptr; 253 return 0; 254 } 255