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() { return *GetPointer(); }
     68   Type Get() { return Ref(); }
     69   void Set(const Type& value) { Ref() = value; }
     70   Type* GetPointer() {
     71     pthread_once(once, ThreadLocalInit<Type*, key>);
     72     Type* value = reinterpret_cast<Type*>(pthread_getspecific(*key));
     73     if (value)
     74       return value;
     75     // new Type() for PODs means zero initialization.
     76     value = new Type();
     77     int error = pthread_setspecific(*key, value);
     78     if (error != 0)
     79       ERROR("Failed to set a TLS: error=%d", error);
     80     return value;
     81   }
     82 };
     83 
     84 // We need a namespace for name##_key and name##_once since template parameters
     85 // do not accept unnamed values such as static global variables.
     86 #define DEFINE_THREAD_LOCAL(Type, name)           \
     87   namespace {                                     \
     88   pthread_once_t name##_once = PTHREAD_ONCE_INIT; \
     89   pthread_key_t name##_key;                       \
     90   }                                               \
     91   ThreadLocal<Type, &name##_key, &name##_once> name;
     92 
     93 #define TLS_REF(x) x.Ref()
     94 
     95 #endif
     96 
     97 #endif  // THREAD_LOCAL_H_
     98