//===- subzero/src/IceTLS.h - thread_local workaround -----------*- C++ -*-===// // // The Subzero Code Generator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief Defines macros for working around the lack of support for /// thread_local in MacOS 10.6. /// /// This assumes std::thread is written in terms of pthread. Define /// ICE_THREAD_LOCAL_HACK to enable the pthread workarounds. /// //===----------------------------------------------------------------------===// #ifndef SUBZERO_SRC_ICETLS_H #define SUBZERO_SRC_ICETLS_H /// /// @defgroup /IceTLS Defines 5 macros for unifying thread_local and pthread: /// @{ /// /// \def ICE_TLS_DECLARE_FIELD(Type, FieldName) /// Declare a static thread_local field inside the current class definition. /// "Type" needs to be a pointer type, such as int* or class Foo*. /// /// \def ICE_TLS_DEFINE_FIELD(Type, ClassName, FieldName) /// Define a static thread_local field outside of its class definition. The /// field will ultimately be initialized to nullptr. /// /// \def ICE_TLS_INIT_FIELD(FieldName) /// Ensure the thread_local field is properly initialized. This is intended /// to be called from within a static method of the field's class after main() /// starts (to ensure that the pthread library is fully initialized) but before /// any uses of ICE_TLS_GET_FIELD or ICE_TLS_SET_FIELD. /// /// \def ICE_TLS_GET_FIELD(Type, FieldName) /// Read the value of the static thread_local field. Must be done within the /// context of its class. /// /// \def ICE_TLS_SET_FIELD(FieldName, Value) /// Write a value into the static thread_local field. Must be done within the /// context of its class. /// TODO(stichnot): Limit this define to only the platforms that absolutely /// require it. And ideally, eventually remove this hack altogether. /// /// /// \def ICE_THREAD_LOCAL_HACK /// #ifndef ICE_THREAD_LOCAL_HACK #define ICE_THREAD_LOCAL_HACK 1 #endif #if ICE_THREAD_LOCAL_HACK // For a static thread_local field F of a class C, instead of declaring and // defining C::F, we create two static fields: // static pthread_key_t F__key; // static int F__initStatus; // // The F__initStatus field is used to hold the result of the // pthread_key_create() call, where a zero value indicates success, and a // nonzero value indicates failure or that ICE_TLS_INIT_FIELD() was never // called. The F__key field is used as the argument to pthread_getspecific() // and pthread_setspecific(). #include "llvm/Support/ErrorHandling.h" #include #define ICE_TLS_DECLARE_FIELD(Type, FieldName) \ using FieldName##__type = Type; \ static pthread_key_t FieldName##__key; \ static int FieldName##__initStatus #define ICE_TLS_DEFINE_FIELD(Type, ClassName, FieldName) \ pthread_key_t ClassName::FieldName##__key; \ int ClassName::FieldName##__initStatus = 1 #define ICE_TLS_INIT_FIELD(FieldName) \ if (FieldName##__initStatus) { \ FieldName##__initStatus = pthread_key_create(&FieldName##__key, nullptr); \ if (FieldName##__initStatus) \ llvm::report_fatal_error("Failed to create pthread key"); \ } #define ICE_TLS_GET_FIELD(FieldName) \ (assert(FieldName##__initStatus == 0), \ static_cast(pthread_getspecific(FieldName##__key))) #define ICE_TLS_SET_FIELD(FieldName, Value) \ (assert(FieldName##__initStatus == 0), \ pthread_setspecific(FieldName##__key, (Value))) #else // !ICE_THREAD_LOCAL_HACK #if defined(_MSC_VER) #define ICE_ATTRIBUTE_TLS __declspec(thread) #else // !_MSC_VER #define ICE_ATTRIBUTE_TLS thread_local #endif // !_MSC_VER #define ICE_TLS_DECLARE_FIELD(Type, FieldName) \ static ICE_ATTRIBUTE_TLS Type FieldName #define ICE_TLS_DEFINE_FIELD(Type, ClassName, FieldName) \ ICE_ATTRIBUTE_TLS Type ClassName::FieldName = nullptr #define ICE_TLS_INIT_FIELD(FieldName) #define ICE_TLS_GET_FIELD(FieldName) (FieldName) #define ICE_TLS_SET_FIELD(FieldName, Value) (FieldName = (Value)) #endif // !ICE_THREAD_LOCAL_HACK /// /// @} /// #endif // SUBZERO_SRC_ICETLS_H