LCOV - code coverage report
Current view: top level - mfbt - ThreadLocal.h (source / functions) Hit Total Coverage
Test: output.info Lines: 7 7 100.0 %
Date: 2017-07-14 16:53:18 Functions: 35 46 76.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /* Cross-platform lightweight thread local data wrappers. */
       8             : 
       9             : #ifndef mozilla_ThreadLocal_h
      10             : #define mozilla_ThreadLocal_h
      11             : 
      12             : #if !defined(XP_WIN)
      13             : #  include <pthread.h>
      14             : #endif
      15             : 
      16             : #include "mozilla/Assertions.h"
      17             : #include "mozilla/Attributes.h"
      18             : #include "mozilla/TypeTraits.h"
      19             : 
      20             : namespace mozilla {
      21             : 
      22             : namespace detail {
      23             : 
      24             : #ifdef XP_MACOSX
      25             : #  if defined(__has_feature)
      26             : #    if __has_feature(cxx_thread_local)
      27             : #      define MACOSX_HAS_THREAD_LOCAL
      28             : #    endif
      29             : #  endif
      30             : #endif
      31             : 
      32             : #if defined(HAVE_THREAD_TLS_KEYWORD) || defined(XP_WIN) || defined(MACOSX_HAS_THREAD_LOCAL)
      33             : #define MOZ_HAS_THREAD_LOCAL
      34             : #endif
      35             : 
      36             : /*
      37             :  * Thread Local Storage helpers.
      38             :  *
      39             :  * Usage:
      40             :  *
      41             :  * Do not directly instantiate this class.  Instead, use the
      42             :  * MOZ_THREAD_LOCAL macro to declare or define instances.  The macro
      43             :  * takes a type name as its argument.
      44             :  *
      45             :  * Declare like this:
      46             :  * extern MOZ_THREAD_LOCAL(int) tlsInt;
      47             :  * Define like this:
      48             :  * MOZ_THREAD_LOCAL(int) tlsInt;
      49             :  * or:
      50             :  * static MOZ_THREAD_LOCAL(int) tlsInt;
      51             :  *
      52             :  * Only static-storage-duration (e.g. global variables, or static class members)
      53             :  * objects of this class should be instantiated. This class relies on
      54             :  * zero-initialization, which is implicit for static-storage-duration objects.
      55             :  * It doesn't have a custom default constructor, to avoid static initializers.
      56             :  *
      57             :  * API usage:
      58             :  *
      59             :  * // Create a TLS item.
      60             :  * //
      61             :  * // Note that init() should be invoked before the first use of set()
      62             :  * // or get().  It is ok to call it multiple times.  This must be
      63             :  * // called in a way that avoids possible races with other threads.
      64             :  * MOZ_THREAD_LOCAL(int) tlsKey;
      65             :  * if (!tlsKey.init()) {
      66             :  *   // deal with the error
      67             :  * }
      68             :  *
      69             :  * // Set the TLS value
      70             :  * tlsKey.set(123);
      71             :  *
      72             :  * // Get the TLS value
      73             :  * int value = tlsKey.get();
      74             :  */
      75             : template<typename T>
      76             : class ThreadLocal
      77             : {
      78             : #ifndef MOZ_HAS_THREAD_LOCAL
      79             :   typedef pthread_key_t key_t;
      80             : 
      81             :   // Integral types narrower than void* must be extended to avoid
      82             :   // warnings from valgrind on some platforms.  This helper type
      83             :   // achieves that without penalizing the common case of ThreadLocals
      84             :   // instantiated using a pointer type.
      85             :   template<typename S>
      86             :   struct Helper
      87             :   {
      88             :     typedef uintptr_t Type;
      89             :   };
      90             : 
      91             :   template<typename S>
      92             :   struct Helper<S *>
      93             :   {
      94             :     typedef S *Type;
      95             :   };
      96             : #endif
      97             : 
      98             :   bool initialized() const {
      99             : #ifdef MOZ_HAS_THREAD_LOCAL
     100             :     return true;
     101             : #else
     102             :     return mInited;
     103             : #endif
     104             :   }
     105             : 
     106             : public:
     107             :   // __thread does not allow non-trivial constructors, but we can
     108             :   // instead rely on zero-initialization.
     109             : #ifndef MOZ_HAS_THREAD_LOCAL
     110             :   ThreadLocal()
     111             :     : mKey(0), mInited(false)
     112             :   {}
     113             : #endif
     114             : 
     115             :   MOZ_MUST_USE inline bool init();
     116             : 
     117             :   inline T get() const;
     118             : 
     119             :   inline void set(const T aValue);
     120             : 
     121             : private:
     122             : #ifdef MOZ_HAS_THREAD_LOCAL
     123             :   T mValue;
     124             : #else
     125             :   key_t mKey;
     126             :   bool mInited;
     127             : #endif
     128             : };
     129             : 
     130             : template<typename T>
     131             : inline bool
     132      358986 : ThreadLocal<T>::init()
     133             : {
     134             :   static_assert(mozilla::IsPointer<T>::value || mozilla::IsIntegral<T>::value,
     135             :                 "mozilla::ThreadLocal must be used with a pointer or "
     136             :                 "integral type");
     137             :   static_assert(sizeof(T) <= sizeof(void*),
     138             :                 "mozilla::ThreadLocal can't be used for types larger than "
     139             :                 "a pointer");
     140             : 
     141             : #ifdef MOZ_HAS_THREAD_LOCAL
     142      358986 :   return true;
     143             : #else
     144             :   if (!initialized()) {
     145             :     mInited = !pthread_key_create(&mKey, nullptr);
     146             :   }
     147             :   return mInited;
     148             : #endif
     149             : }
     150             : 
     151             : template<typename T>
     152             : inline T
     153   125212708 : ThreadLocal<T>::get() const
     154             : {
     155             : #ifdef MOZ_HAS_THREAD_LOCAL
     156   125212708 :   return mValue;
     157             : #else
     158             :   MOZ_ASSERT(initialized());
     159             :   void* h;
     160             :   h = pthread_getspecific(mKey);
     161             :   return static_cast<T>(reinterpret_cast<typename Helper<T>::Type>(h));
     162             : #endif
     163             : }
     164             : 
     165             : template<typename T>
     166             : inline void
     167       24337 : ThreadLocal<T>::set(const T aValue)
     168             : {
     169             : #ifdef MOZ_HAS_THREAD_LOCAL
     170       24337 :   mValue = aValue;
     171             : #else
     172             :   MOZ_ASSERT(initialized());
     173             :   void* h = reinterpret_cast<void*>(static_cast<typename Helper<T>::Type>(aValue));
     174             :   bool succeeded = !pthread_setspecific(mKey, h);
     175             :   if (!succeeded) {
     176             :     MOZ_CRASH();
     177             :   }
     178             : #endif
     179       24337 : }
     180             : 
     181             : #ifdef MOZ_HAS_THREAD_LOCAL
     182             : #if defined(XP_WIN) || defined(MACOSX_HAS_THREAD_LOCAL)
     183             : #define MOZ_THREAD_LOCAL(TYPE) thread_local mozilla::detail::ThreadLocal<TYPE>
     184             : #else
     185             : #define MOZ_THREAD_LOCAL(TYPE) __thread mozilla::detail::ThreadLocal<TYPE>
     186             : #endif
     187             : #else
     188             : #define MOZ_THREAD_LOCAL(TYPE) mozilla::detail::ThreadLocal<TYPE>
     189             : #endif
     190             : 
     191             : } // namespace detail
     192             : } // namespace mozilla
     193             : 
     194             : #endif /* mozilla_ThreadLocal_h */

Generated by: LCOV version 1.13