Home | History | Annotate | Download | only in kati
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 //
      5 // A simple cross platform thread local storage implementation.
      6 //
      7 // This is a drop-in replacement of __thread keyword. If your compiler
      8 // toolchain supports __thread keyword, the user of this code should
      9 // be as fast as the code which uses __thread. Chrome's
     10 // base::ThreadLocalPointer and base::ThreadLocalStorage cannot be as
     11 // fast as __thread.
     12 // TODO(crbug.com/249345): If pthread_getspecific is slow for our use,
     13 // expose bionic's internal TLS and stop using pthread_getspecific
     14 // based implementation.
     15 //
     16 // Usage:
     17 //
     18 // Before (linux):
     19 //
     20 // __thread Foo* foo;
     21 // foo = new Foo();
     22 // foo->func();
     23 //
     24 //
     25 // After:
     26 //
     27 // DEFINE_THREAD_LOCAL(Foo*, foo);
     28 // foo.Ref() = new Foo();
     29 // foo.Ref()->func();
     30 //
     31 // Thread local PODs are zero-initialized.
     32 // Thread local non-PODs are initialized with the default constructor.
     33 
     34 #ifndef THREAD_LOCAL_H_
     35 #define THREAD_LOCAL_H_
     36 
     37 #include <errno.h>
     38 #include <pthread.h>
     39 
     40 #include "log.h"
     41 
     42 #ifdef __linux__
     43 
     44 #define DEFINE_THREAD_LOCAL(Type, name) thread_local Type name
     45 #define TLS_REF(x) x
     46 
     47 #else
     48 
     49 // Thread local storage implementation which uses pthread.
     50 // Note that DEFINE_THREAD_LOCAL creates a global variable just like
     51 // thread local storage based on __thread keyword. So we should not use
     52 // constructor in ThreadLocal class to avoid static initializator.
     53 template <typename Type>
     54 void ThreadLocalDestructor(void* ptr) {
     55   delete reinterpret_cast<Type>(ptr);
     56 }
     57 
     58 template<typename Type, pthread_key_t* key>
     59 void ThreadLocalInit() {
     60   if (pthread_key_create(key, ThreadLocalDestructor<Type>))
     61     ERROR("Failed to create a pthread key for TLS errno=%d", errno);
     62 }
     63 
     64 template<typename Type, pthread_key_t* key, pthread_once_t* once>
     65 class ThreadLocal {
     66  public:
     67   Type& Ref() {
     68     return *GetPointer();
     69   }
     70   Type Get() {
     71     return Ref();
     72   }
     73   void Set(const Type& value) {
     74     Ref() = value;
     75   }
     76   Type* GetPointer() {
     77     pthread_once(once, ThreadLocalInit<Type*, key>);
     78     Type* value = reinterpret_cast<Type*>(pthread_getspecific(*key));
     79     if (value) return value;
     80     // new Type() for PODs means zero initialization.
     81     value = new Type();
     82     int error = pthread_setspecific(*key, value);
     83     if (error != 0)
     84       ERROR("Failed to set a TLS: error=%d", error);
     85     return value;
     86   }
     87 };
     88 
     89 // We need a namespace for name##_key and name##_once since template parameters
     90 // do not accept unnamed values such as static global variables.
     91 #define DEFINE_THREAD_LOCAL(Type, name)                 \
     92   namespace {                                           \
     93   pthread_once_t name##_once = PTHREAD_ONCE_INIT;       \
     94   pthread_key_t name##_key;                             \
     95   }                                                     \
     96   ThreadLocal<Type, &name##_key, &name##_once> name;
     97 
     98 #define TLS_REF(x) x.Ref()
     99 
    100 #endif
    101 
    102 #endif  // THREAD_LOCAL_H_
    103