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