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