144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes/* 244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * Copyright (C) 2008 The Android Open Source Project 344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * All rights reserved. 444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * 544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * Redistribution and use in source and binary forms, with or without 644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * modification, are permitted provided that the following conditions 744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * are met: 844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * * Redistributions of source code must retain the above copyright 944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * notice, this list of conditions and the following disclaimer. 1044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * * Redistributions in binary form must reproduce the above copyright 1144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * notice, this list of conditions and the following disclaimer in 1244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * the documentation and/or other materials provided with the 1344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * distribution. 1444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * 1544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 1844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 1944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 2244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 2544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * SUCH DAMAGE. 2744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes */ 2844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 2944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes#include <pthread.h> 3044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 31eb847bc8666842a3cfc9c06e8458ad1abebebaf0Elliott Hughes#include "private/bionic_tls.h" 3244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes#include "pthread_internal.h" 3344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 3444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes/* A technical note regarding our thread-local-storage (TLS) implementation: 3544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * 3644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * There can be up to BIONIC_TLS_SLOTS independent TLS keys in a given process, 3744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * The keys below TLS_SLOT_FIRST_USER_SLOT are reserved for Bionic to hold 3844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * special thread-specific variables like errno or a pointer to 3944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * the current thread's descriptor. These entries cannot be accessed through 4044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * pthread_getspecific() / pthread_setspecific() or pthread_key_delete() 4144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * 4244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * The 'tls_map_t' type defined below implements a shared global map of 4344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * currently created/allocated TLS keys and the destructors associated 4444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * with them. 4544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * 4644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * The global TLS map simply contains a bitmap of allocated keys, and 4744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * an array of destructors. 4844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * 4944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * Each thread has a TLS area that is a simple array of BIONIC_TLS_SLOTS void* 5044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * pointers. the TLS area of the main thread is stack-allocated in 5144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * __libc_init_common, while the TLS area of other threads is placed at 5244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * the top of their stack in pthread_create. 5344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * 5444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * When pthread_key_delete() is called it will erase the key's bitmap bit 5544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * and its destructor, and will also clear the key data in the TLS area of 5644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * all created threads. As mandated by Posix, it is the responsibility of 5744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * the caller of pthread_key_delete() to properly reclaim the objects that 5844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes * were pointed to by these data fields (either before or after the call). 5944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes */ 6044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 6144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes#define TLSMAP_BITS 32 6244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes#define TLSMAP_WORDS ((BIONIC_TLS_SLOTS+TLSMAP_BITS-1)/TLSMAP_BITS) 6344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes#define TLSMAP_WORD(m,k) (m).map[(k)/TLSMAP_BITS] 6444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes#define TLSMAP_MASK(k) (1U << ((k)&(TLSMAP_BITS-1))) 6544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 6644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughesstatic inline bool IsValidUserKey(pthread_key_t key) { 6744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes return (key >= TLS_SLOT_FIRST_USER_SLOT && key < BIONIC_TLS_SLOTS); 6844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes} 6944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 7044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughestypedef void (*key_destructor_t)(void*); 7144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 7244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughesstruct tls_map_t { 7344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes bool is_initialized; 7444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 7544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes /* bitmap of allocated keys */ 7644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes uint32_t map[TLSMAP_WORDS]; 7744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 7844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes key_destructor_t key_destructors[BIONIC_TLS_SLOTS]; 7944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes}; 8044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 8144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughesclass ScopedTlsMapAccess { 8244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes public: 8344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes ScopedTlsMapAccess() { 8444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes Lock(); 8544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 8644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // If this is the first time the TLS map has been accessed, 8744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // mark the slots belonging to well-known keys as being in use. 8844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // This isn't currently necessary because the well-known keys 8944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // can only be accessed directly by bionic itself, do not have 9044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // destructors, and all the functions that touch the TLS map 9144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // start after the maximum well-known slot. 9244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes if (!s_tls_map_.is_initialized) { 9344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes for (pthread_key_t key = 0; key < TLS_SLOT_FIRST_USER_SLOT; ++key) { 9444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes SetInUse(key, NULL); 9544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 9644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes s_tls_map_.is_initialized = true; 9744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 9844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 9944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 10044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes ~ScopedTlsMapAccess() { 10144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes Unlock(); 10244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 10344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 10444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes int CreateKey(pthread_key_t* result, void (*key_destructor)(void*)) { 10544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // Take the first unallocated key. 10644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes for (int key = 0; key < BIONIC_TLS_SLOTS; ++key) { 10744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes if (!IsInUse(key)) { 10844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes SetInUse(key, key_destructor); 10944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes *result = key; 11044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes return 0; 11144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 11244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 11344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 11444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // We hit PTHREAD_KEYS_MAX. POSIX says EAGAIN for this case. 11544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes return EAGAIN; 11644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 11744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 11844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes void DeleteKey(pthread_key_t key) { 11944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes TLSMAP_WORD(s_tls_map_, key) &= ~TLSMAP_MASK(key); 12044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes s_tls_map_.key_destructors[key] = NULL; 12144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 12244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 12344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes bool IsInUse(pthread_key_t key) { 12444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes return (TLSMAP_WORD(s_tls_map_, key) & TLSMAP_MASK(key)) != 0; 12544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 12644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 12744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes void SetInUse(pthread_key_t key, void (*key_destructor)(void*)) { 12844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes TLSMAP_WORD(s_tls_map_, key) |= TLSMAP_MASK(key); 12944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes s_tls_map_.key_destructors[key] = key_destructor; 13044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 13144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 13244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // Called from pthread_exit() to remove all TLS key data 13344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // from this thread's TLS area. This must call the destructor of all keys 13444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // that have a non-NULL data value and a non-NULL destructor. 13544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes void CleanAll() { 1362a0b873065edb304fa2d1c54f8de663ea638b8abElliott Hughes void** tls = __get_tls(); 13744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 13844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // Because destructors can do funky things like deleting/creating other 13944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // keys, we need to implement this in a loop. 14044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes for (int rounds = PTHREAD_DESTRUCTOR_ITERATIONS; rounds > 0; --rounds) { 14144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes size_t called_destructor_count = 0; 14244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes for (int key = 0; key < BIONIC_TLS_SLOTS; ++key) { 14344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes if (IsInUse(key)) { 14444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes void* data = tls[key]; 14544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes void (*key_destructor)(void*) = s_tls_map_.key_destructors[key]; 14644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 14744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes if (data != NULL && key_destructor != NULL) { 14844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // we need to clear the key data now, this will prevent the 14944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // destructor (or a later one) from seeing the old value if 15044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // it calls pthread_getspecific() for some odd reason 15144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 15244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // we do not do this if 'key_destructor == NULL' just in case another 15344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // destructor function might be responsible for manually 15444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // releasing the corresponding data. 15544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes tls[key] = NULL; 15644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 15744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // because the destructor is free to call pthread_key_create 15844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // and/or pthread_key_delete, we need to temporarily unlock 15944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // the TLS map 16044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes Unlock(); 16144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes (*key_destructor)(data); 16244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes Lock(); 16344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes ++called_destructor_count; 16444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 16544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 16644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 16744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 16844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // If we didn't call any destructors, there is no need to check the TLS data again. 16944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes if (called_destructor_count == 0) { 17044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes break; 17144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 17244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 17344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 17444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 17544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes private: 17644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes static tls_map_t s_tls_map_; 17744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes static pthread_mutex_t s_tls_map_lock_; 17844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 17944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes void Lock() { 18044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes pthread_mutex_lock(&s_tls_map_lock_); 18144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 18244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 18344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes void Unlock() { 18444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes pthread_mutex_unlock(&s_tls_map_lock_); 18544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 18644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes}; 18744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 188ce532721aaf61d4b6a171903c851ac82adf08aa8Elliott Hughes__LIBC_HIDDEN__ tls_map_t ScopedTlsMapAccess::s_tls_map_; 189ce532721aaf61d4b6a171903c851ac82adf08aa8Elliott Hughes__LIBC_HIDDEN__ pthread_mutex_t ScopedTlsMapAccess::s_tls_map_lock_; 19044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 19144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes__LIBC_HIDDEN__ void pthread_key_clean_all() { 19244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes ScopedTlsMapAccess tls_map; 19344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes tls_map.CleanAll(); 19444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes} 19544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 19644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughesint pthread_key_create(pthread_key_t* key, void (*key_destructor)(void*)) { 19744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes ScopedTlsMapAccess tls_map; 19844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes return tls_map.CreateKey(key, key_destructor); 19944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes} 20044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 20144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes// Deletes a pthread_key_t. note that the standard mandates that this does 20244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes// not call the destructors for non-NULL key values. Instead, it is the 20344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes// responsibility of the caller to properly dispose of the corresponding data 20444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes// and resources, using any means it finds suitable. 20544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughesint pthread_key_delete(pthread_key_t key) { 20644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes ScopedTlsMapAccess tls_map; 20744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 20844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes if (!IsValidUserKey(key) || !tls_map.IsInUse(key)) { 20944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes return EINVAL; 21044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 21144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 21244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // Clear value in all threads. 2131728b2396591853345507a063ed6075dfd251706Elliott Hughes pthread_mutex_lock(&g_thread_list_lock); 2141728b2396591853345507a063ed6075dfd251706Elliott Hughes for (pthread_internal_t* t = g_thread_list; t != NULL; t = t->next) { 2150f020d18b138e24b1fe34074808e07ac412f35a4msg // Skip zombie threads. They don't have a valid TLS area any more. 21644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // Similarly, it is possible to have t->tls == NULL for threads that 21744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // were just recently created through pthread_create() but whose 218e48b68570d872ef7ece1d873c0ea298ea76393f3Elliott Hughes // startup trampoline (__pthread_start) hasn't been run yet by the 2190f020d18b138e24b1fe34074808e07ac412f35a4msg // scheduler. t->tls will also be NULL after a thread's stack has been 22044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // unmapped but before the ongoing pthread_join() is finished. 221877ec6d90418ff1d6597147d355a2229fdffae7eElliott Hughes if (t->tid == 0 || t->tls == NULL) { 22244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes continue; 22344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 22444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 22544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes t->tls[key] = NULL; 22644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 22744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes tls_map.DeleteKey(key); 22844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 2291728b2396591853345507a063ed6075dfd251706Elliott Hughes pthread_mutex_unlock(&g_thread_list_lock); 23044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes return 0; 23144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes} 23244b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 23344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughesvoid* pthread_getspecific(pthread_key_t key) { 23444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes if (!IsValidUserKey(key)) { 23544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes return NULL; 23644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 23744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 23844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // For performance reasons, we do not lock/unlock the global TLS map 23944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // to check that the key is properly allocated. If the key was not 24044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // allocated, the value read from the TLS should always be NULL 24144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes // due to pthread_key_delete() clearing the values for all threads. 2422a0b873065edb304fa2d1c54f8de663ea638b8abElliott Hughes return __get_tls()[key]; 24344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes} 24444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 24544b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughesint pthread_setspecific(pthread_key_t key, const void* ptr) { 24644b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes ScopedTlsMapAccess tls_map; 24744b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 24844b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes if (!IsValidUserKey(key) || !tls_map.IsInUse(key)) { 24944b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes return EINVAL; 25044b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes } 25144b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes 2522a0b873065edb304fa2d1c54f8de663ea638b8abElliott Hughes __get_tls()[key] = const_cast<void*>(ptr); 25344b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes return 0; 25444b53ad6818de344e0b499ad8fdbb21fcb0ff2b6Elliott Hughes} 255