blob: 683766849e5287bb1b60255b15b96b3fc8615567 [file] [log] [blame]
//===- 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
/// This file defines macros for working around the lack of support for
/// thread_local in MacOS 10.6. It 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
#if defined(_MSC_VER)
#define ICE_ATTRIBUTE_TLS __declspec(thread)
#else // !_MSC_VER
#define ICE_ATTRIBUTE_TLS thread_local
#endif // !_MSC_VER
// Defines 4 macros for unifying thread_local and pthread:
//
// 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*.
//
// 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.
//
// 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.
//
// ICE_TLS_GET_FIELD(Type, FieldName): Read the value of the static
// thread_local field. Must be done within the context of its class.
//
// 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.
#define ICE_THREAD_LOCAL_HACK
#ifdef 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 <pthread.h>
#define ICE_TLS_DECLARE_FIELD(Type, FieldName) \
typedef Type FieldName##__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
#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