tlds
Transactional Operations for Linked Data Structures
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
ThreadLocal.hpp
Go to the documentation of this file.
1 /**
2  * Copyright (C) 2011
3  * University of Rochester Department of Computer Science
4  * and
5  * Lehigh University Department of Computer Science and Engineering
6  *
7  * License: Modified BSD
8  * Please see the file LICENSE.RSTM for licensing information
9  */
10 
11 /**
12  * Since Apple doesn't support __thread in its toolchain, we need a clean
13  * interface that lets us use either __thread or pthread_getspecific. This
14  * file hides all interaction with thread-local storage behind a simple
15  * macro, so that the complexities of non-__thread are hidden from the
16  * programmer
17  *
18  * Note, too, that we allow a non-Apple user to configure the library in
19  * order to explicitly use pthread_getspecific.
20  */
21 
22 // NB: This file could use significant hardening, using template
23 // metaprogramming to support all the necessary types, i.e., arrays,
24 // unions, etc.
25 
26 #ifndef STM_COMMON_THREAD_LOCAL_H
27 #define STM_COMMON_THREAD_LOCAL_H
28 
29 #include <stm/config.h>
30 
31 /**
32  * We define the following interface for interacting with thread local data.
33  *
34  * THREAD_LOCAL_DECL_TYPE(X)
35  *
36  * The macro will expand in a platform specific manner into the correct
37  * thread local type for X.
38  *
39  * Examples:
40  *
41  * static THREAD_LOCAL_DECL_TYPE(unsigned) a;
42  * Linux: static __thread unsigned a;
43  * Windows: static __declspec(thread) unsigned a;
44  * pthreads: static ThreadLocal<unsigned, sizeof(unsigned)> a;
45  *
46  * extern THREAD_LOCAL_DECL_TYPE(Foo*) foo;
47  * Linux: extern __thread Foo* foo;
48  * Windows: extern __declspec(thread) Foo* foo;
49  * pthreads: extern ThreadLocal<Foo*, sizeof(Foo*)> a;
50  */
51 #if defined(STM_TLS_PTHREAD)
52 # define THREAD_LOCAL_DECL_TYPE(X) stm::tls::ThreadLocal<X, sizeof(X)>
53 #elif defined(STM_OS_WINDOWS)
54 # define THREAD_LOCAL_DECL_TYPE(X) __declspec(thread) X
55 #elif defined(STM_CC_GCC) || defined(STM_CC_SUN)
56 # define THREAD_LOCAL_DECL_TYPE(X) __thread X
57 #else
58 # warning "No thread local implementation defined."
59 #endif
60 
61 /**
62  * In the above macro definitions, only STM_TLS_PTHREAD needs more work.
63  * The remainder of this file implements the ThreadLocal<> templates that
64  * make pthread_getspecific and pthread_setspecific look like __thread to
65  * client code
66  */
67 #if defined(STM_TLS_PTHREAD)
68 
69 #include <pthread.h>
70 #include <cstdlib>
71 
72 namespace stm
73 {
74  namespace tls
75  {
76  /**
77  * The basic thread local wrapper. The pthread interface stores the
78  * value as a void*, and this class manages that void* along with the
79  * pthread key.
80  */
81  class PThreadLocalImplementation
82  {
83  protected:
84  PThreadLocalImplementation(void* const v)
85  {
86  pthread_key_create(&key, NULL);
87  pthread_setspecific(key, v);
88  }
89 
90  virtual ~PThreadLocalImplementation() { pthread_key_delete(key); }
91  void* getValue() const { return pthread_getspecific(key); }
92  void setValue(void* const v) { pthread_setspecific(key, v); }
93 
94  private:
95  pthread_key_t key;
96 
97  private:
98  // Do not implement
99  PThreadLocalImplementation();
100  PThreadLocalImplementation(const PThreadLocalImplementation&);
101 
102  PThreadLocalImplementation&
103  operator=(const PThreadLocalImplementation&);
104  };
105 
106  /**
107  * Templates allow us to mimic an __thread interface to PThread data. We
108  * have two basic categories of data.
109  *
110  * 1) Value data.
111  * 2) Pointer data.
112  *
113  * Value data is builtin types and user defined structs that are
114  * compatible with direct __thread allocation. We can split this type of
115  * data into two cases.
116  *
117  * 1) Data that can fit in the size of a void*.
118  * 2) Data that is too large.
119  *
120  * This distinction is important when we consider levels of
121  * indirection. The pthread interface gives us access to void* sized
122  * slots of data. If we can fit what we need there, then we have just
123  * the one level of indirection to access it. If we can't, then we need
124  * to allocate space elsewhere for it, and store a pointer to that space
125  * in the slot.
126  *
127  * Pointer data is easy to manage, since the client expects the location
128  * to look like a pointer, and pthreads is giving us a pointer. The
129  * client is going to have to manage the memory if it's dynamically
130  * allocated, so we can just return it as needed.
131  *
132  * The main problem to this interface is that each interaction requires
133  * a pthread library call. If the client knew there was a pthreads
134  * interface (or just an interface more expensive than __thread)
135  * underneath then it could optimize for that situation.
136  */
137 
138  /**
139  * The ThreadLocal template for objects that are larger than the size
140  * allotted by a pthread_getspecific. It uses either malloc and free or
141  * a trivial new constructor to allocate and deallocate space for the
142  * data, and memcpy to write to the data as needed. It owns the
143  * allocated space, which is fine because the client is thinking of this
144  * as automatically managed anyway.
145  *
146  * Currently, we trigger an error if the type has a constructor, but
147  * doesn't have a default constructor. This is the same approach that
148  * C++ takes with arrays of user-defined classes.
149  */
150  template <typename T, unsigned S>
151  class ThreadLocal : public PThreadLocalImplementation
152  {
153  public:
154  ThreadLocal() : PThreadLocalImplementation(new T()) { }
155 
156  ThreadLocal(T t) : PThreadLocalImplementation(new T())
157  {
158  __builtin_memcpy(getValue(), &t, S);
159  }
160 
161  virtual ~ThreadLocal() { delete static_cast<T*>(getValue()); }
162 
163  T* operator&() const { return static_cast<T*>(getValue()); }
164 
165  private:
166  // Do not implement these. We assume that anyone trying to copy the
167  // ThreadLocal object probably wants to copy the underlying object
168  // instead.
169  ThreadLocal(const ThreadLocal<T, S>&);
170  ThreadLocal<T, S>& operator=(const ThreadLocal<T, S>&);
171  };
172 
173  /**
174  * The ThreadLocal template for objects that are the size of a void*,
175  * but not a pointer. This differs from the basic template in that we
176  * don't need to allocate any extra space for the stored item.
177  */
178  template <typename T>
179  class ThreadLocal<T, sizeof(void*)> : public PThreadLocalImplementation
180  {
181  public:
182  ThreadLocal() : PThreadLocalImplementation(NULL) { }
183 
184  ThreadLocal(T t) : PThreadLocalImplementation(NULL)
185  {
186  __builtin_memcpy(getValue(), &t, sizeof(T));
187  }
188 
189  T* operator&() const { return static_cast<T*>(getValue()); }
190 
191  private:
192  // Do not implement these. We assume that anyone trying to copy the
193  // ThreadLocal object probably wants to copy the underlying object
194  // instead.
195  ThreadLocal(const ThreadLocal<T, sizeof(void*)>&);
196 
197  ThreadLocal<T,sizeof(void*)>&
198  operator=(const ThreadLocal<T,sizeof(void*)>&);
199  };
200 
201  /**
202  * We use partial template specialization to implement a thread local
203  * type just for pointers. This extends the interface to allow
204  * interaction with the stored variable in "smart pointer" fashion.
205  *
206  * This differs from the basic thread local implementation in that we
207  * don't provide an address-of operator, in the expectation that no one
208  * is going to want it, but we do provide an implicit cast to the
209  * underlying pointer type that returns the pointer value stored at the
210  * key.
211  *
212  * This allows clients to pass and return the value as expected. A
213  * normal smart pointer would be hesitant to do this because of
214  * ownership issues, but this class is really just trying to emulate
215  * __thread. The ThreadLocal does *not* take ownership of managing the
216  * underlying pointer.
217  */
218  template <typename T>
219  class ThreadLocal<T*, sizeof(void*)> : public PThreadLocalImplementation
220  {
221  public:
222  ThreadLocal(T* t = NULL) : PThreadLocalImplementation(t) { }
223 
224  virtual ~ThreadLocal() { }
225 
226  // The smart pointer interface to the variable.
227  const T& operator*() const { return *static_cast<T*>(getValue()); }
228  const T* operator->() const { return static_cast<T*>(getValue()); }
229  T& operator*() { return *static_cast<T*>(getValue()); }
230  T* operator->() { return static_cast<T*>(getValue()); }
231  operator T*() { return static_cast<T*>(getValue()); }
232 
233  // allow assignments
234  ThreadLocal<T*, sizeof(void*)>& operator=(T* rhs) {
235  setValue(rhs);
236  return *this;
237  }
238 
239  bool operator==(T* rhs) { return (getValue() == rhs); }
240 
241  private:
242  // Restrict access to potentially dangerous things. Start by
243  // preventing the thread local to be copied around (presumably people
244  // trying to copy a ThreadLocal /actually/ want to copy the
245  // underlying object).
246  ThreadLocal(const ThreadLocal<T*, sizeof(T*)>&);
247 
248  ThreadLocal<T*, sizeof(T*)>&
249  operator=(const ThreadLocal<T*, sizeof(T*)>&);
250  };
251  } // namespace stm::tls
252 } // namespace stm
253 #endif
254 
255 #endif // STM_COMMON_THREAD_LOCAL_H
Definition: stm_fraser.c:61