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