| //===- 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 <pthread.h> | |
| #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<FieldName##__type>(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 |