Home | History | Annotate | Download | only in src
      1 //===- subzero/src/IceTLS.h - thread_local workaround -----------*- C++ -*-===//
      2 //
      3 //                        The Subzero Code Generator
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 ///
     10 /// \file
     11 /// \brief Defines macros for working around the lack of support for
     12 /// thread_local in MacOS 10.6.
     13 ///
     14 /// This assumes std::thread is written in terms of pthread. Define
     15 /// ICE_THREAD_LOCAL_HACK to enable the pthread workarounds.
     16 ///
     17 //===----------------------------------------------------------------------===//
     18 
     19 #ifndef SUBZERO_SRC_ICETLS_H
     20 #define SUBZERO_SRC_ICETLS_H
     21 
     22 ///
     23 /// @defgroup /IceTLS Defines 5 macros for unifying thread_local and pthread:
     24 /// @{
     25 ///
     26 /// \def ICE_TLS_DECLARE_FIELD(Type, FieldName)
     27 /// Declare a static thread_local field inside the current class definition.
     28 /// "Type" needs to be a pointer type, such as int* or class Foo*.
     29 ///
     30 /// \def ICE_TLS_DEFINE_FIELD(Type, ClassName, FieldName)
     31 /// Define a static thread_local field outside of its class definition. The
     32 /// field will ultimately be initialized to nullptr.
     33 ///
     34 /// \def ICE_TLS_INIT_FIELD(FieldName)
     35 /// Ensure the thread_local field is properly initialized. This is intended
     36 /// to be called from within a static method of the field's class after main()
     37 /// starts (to ensure that the pthread library is fully initialized) but before
     38 /// any uses of ICE_TLS_GET_FIELD or ICE_TLS_SET_FIELD.
     39 ///
     40 /// \def ICE_TLS_GET_FIELD(Type, FieldName)
     41 /// Read the value of the static thread_local field. Must be done within the
     42 /// context of its class.
     43 ///
     44 /// \def ICE_TLS_SET_FIELD(FieldName, Value)
     45 /// Write a value into the static thread_local field. Must be done within the
     46 /// context of its class.
     47 
     48 /// TODO(stichnot): Limit this define to only the platforms that absolutely
     49 /// require it. And ideally, eventually remove this hack altogether.
     50 ///
     51 
     52 ///
     53 /// \def ICE_THREAD_LOCAL_HACK
     54 ///
     55 #ifndef ICE_THREAD_LOCAL_HACK
     56 #define ICE_THREAD_LOCAL_HACK 1
     57 #endif
     58 
     59 #if ICE_THREAD_LOCAL_HACK
     60 
     61 // For a static thread_local field F of a class C, instead of declaring and
     62 // defining C::F, we create two static fields:
     63 //   static pthread_key_t F__key;
     64 //   static int F__initStatus;
     65 //
     66 // The F__initStatus field is used to hold the result of the
     67 // pthread_key_create() call, where a zero value indicates success, and a
     68 // nonzero value indicates failure or that ICE_TLS_INIT_FIELD() was never
     69 // called. The F__key field is used as the argument to pthread_getspecific()
     70 // and pthread_setspecific().
     71 
     72 #include "llvm/Support/ErrorHandling.h"
     73 
     74 #include <pthread.h>
     75 
     76 #define ICE_TLS_DECLARE_FIELD(Type, FieldName)                                 \
     77   using FieldName##__type = Type;                                              \
     78   static pthread_key_t FieldName##__key;                                       \
     79   static int FieldName##__initStatus
     80 #define ICE_TLS_DEFINE_FIELD(Type, ClassName, FieldName)                       \
     81   pthread_key_t ClassName::FieldName##__key;                                   \
     82   int ClassName::FieldName##__initStatus = 1
     83 #define ICE_TLS_INIT_FIELD(FieldName)                                          \
     84   if (FieldName##__initStatus) {                                               \
     85     FieldName##__initStatus = pthread_key_create(&FieldName##__key, nullptr);  \
     86     if (FieldName##__initStatus)                                               \
     87       llvm::report_fatal_error("Failed to create pthread key");                \
     88   }
     89 #define ICE_TLS_GET_FIELD(FieldName)                                           \
     90   (assert(FieldName##__initStatus == 0),                                       \
     91    static_cast<FieldName##__type>(pthread_getspecific(FieldName##__key)))
     92 #define ICE_TLS_SET_FIELD(FieldName, Value)                                    \
     93   (assert(FieldName##__initStatus == 0),                                       \
     94    pthread_setspecific(FieldName##__key, (Value)))
     95 
     96 #else // !ICE_THREAD_LOCAL_HACK
     97 
     98 #if defined(_MSC_VER)
     99 #define ICE_ATTRIBUTE_TLS __declspec(thread)
    100 #else // !_MSC_VER
    101 #define ICE_ATTRIBUTE_TLS thread_local
    102 #endif // !_MSC_VER
    103 
    104 #define ICE_TLS_DECLARE_FIELD(Type, FieldName)                                 \
    105   static ICE_ATTRIBUTE_TLS Type FieldName
    106 #define ICE_TLS_DEFINE_FIELD(Type, ClassName, FieldName)                       \
    107   ICE_ATTRIBUTE_TLS Type ClassName::FieldName = nullptr
    108 #define ICE_TLS_INIT_FIELD(FieldName)
    109 #define ICE_TLS_GET_FIELD(FieldName) (FieldName)
    110 #define ICE_TLS_SET_FIELD(FieldName, Value) (FieldName = (Value))
    111 
    112 #endif // !ICE_THREAD_LOCAL_HACK
    113 
    114 ///
    115 /// @}
    116 ///
    117 
    118 #endif // SUBZERO_SRC_ICETLS_H
    119