|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 /* Cross-platform lightweight thread local data wrappers. */ |
|
8 |
|
9 #ifndef mozilla_ThreadLocal_h |
|
10 #define mozilla_ThreadLocal_h |
|
11 |
|
12 #if defined(XP_WIN) |
|
13 // This file will get included in any file that wants to add a profiler mark. |
|
14 // In order to not bring <windows.h> together we could include windef.h and |
|
15 // winbase.h which are sufficient to get the prototypes for the Tls* functions. |
|
16 // # include <windef.h> |
|
17 // # include <winbase.h> |
|
18 // Unfortunately, even including these headers causes us to add a bunch of ugly |
|
19 // stuff to our namespace e.g #define CreateEvent CreateEventW |
|
20 extern "C" { |
|
21 __declspec(dllimport) void* __stdcall TlsGetValue(unsigned long); |
|
22 __declspec(dllimport) int __stdcall TlsSetValue(unsigned long, void*); |
|
23 __declspec(dllimport) unsigned long __stdcall TlsAlloc(); |
|
24 } |
|
25 #else |
|
26 # include <pthread.h> |
|
27 # include <signal.h> |
|
28 #endif |
|
29 |
|
30 #include "mozilla/Assertions.h" |
|
31 #include "mozilla/Attributes.h" |
|
32 #include "mozilla/NullPtr.h" |
|
33 |
|
34 namespace mozilla { |
|
35 |
|
36 // sig_safe_t denotes an atomic type which can be read or stored in a single |
|
37 // instruction. This means that data of this type is safe to be manipulated |
|
38 // from a signal handler, or other similar asynchronous execution contexts. |
|
39 #if defined(XP_WIN) |
|
40 typedef unsigned long sig_safe_t; |
|
41 #else |
|
42 typedef sig_atomic_t sig_safe_t; |
|
43 #endif |
|
44 |
|
45 /* |
|
46 * Thread Local Storage helpers. |
|
47 * |
|
48 * Usage: |
|
49 * |
|
50 * Only static-storage-duration (e.g. global variables, or static class members) |
|
51 * objects of this class should be instantiated. This class relies on |
|
52 * zero-initialization, which is implicit for static-storage-duration objects. |
|
53 * It doesn't have a custom default constructor, to avoid static initializers. |
|
54 * |
|
55 * API usage: |
|
56 * |
|
57 * // Create a TLS item. |
|
58 * // |
|
59 * // Note that init() should be invoked exactly once, before any usage of set() |
|
60 * // or get(). |
|
61 * mozilla::ThreadLocal<int> tlsKey; |
|
62 * if (!tlsKey.init()) { |
|
63 * // deal with the error |
|
64 * } |
|
65 * |
|
66 * // Set the TLS value |
|
67 * tlsKey.set(123); |
|
68 * |
|
69 * // Get the TLS value |
|
70 * int value = tlsKey.get(); |
|
71 */ |
|
72 template<typename T> |
|
73 class ThreadLocal |
|
74 { |
|
75 #if defined(XP_WIN) |
|
76 typedef unsigned long key_t; |
|
77 #else |
|
78 typedef pthread_key_t key_t; |
|
79 #endif |
|
80 |
|
81 union Helper { |
|
82 void* ptr; |
|
83 T value; |
|
84 }; |
|
85 |
|
86 public: |
|
87 MOZ_WARN_UNUSED_RESULT inline bool init(); |
|
88 |
|
89 inline T get() const; |
|
90 |
|
91 inline void set(const T value); |
|
92 |
|
93 bool initialized() const { |
|
94 return inited; |
|
95 } |
|
96 |
|
97 private: |
|
98 key_t key; |
|
99 bool inited; |
|
100 }; |
|
101 |
|
102 template<typename T> |
|
103 inline bool |
|
104 ThreadLocal<T>::init() |
|
105 { |
|
106 static_assert(sizeof(T) <= sizeof(void*), |
|
107 "mozilla::ThreadLocal can't be used for types larger than " |
|
108 "a pointer"); |
|
109 MOZ_ASSERT(!initialized()); |
|
110 #ifdef XP_WIN |
|
111 key = TlsAlloc(); |
|
112 inited = key != 0xFFFFFFFFUL; // TLS_OUT_OF_INDEXES |
|
113 #else |
|
114 inited = !pthread_key_create(&key, nullptr); |
|
115 #endif |
|
116 return inited; |
|
117 } |
|
118 |
|
119 template<typename T> |
|
120 inline T |
|
121 ThreadLocal<T>::get() const |
|
122 { |
|
123 MOZ_ASSERT(initialized()); |
|
124 Helper h; |
|
125 #ifdef XP_WIN |
|
126 h.ptr = TlsGetValue(key); |
|
127 #else |
|
128 h.ptr = pthread_getspecific(key); |
|
129 #endif |
|
130 return h.value; |
|
131 } |
|
132 |
|
133 template<typename T> |
|
134 inline void |
|
135 ThreadLocal<T>::set(const T value) |
|
136 { |
|
137 MOZ_ASSERT(initialized()); |
|
138 Helper h; |
|
139 h.value = value; |
|
140 bool succeeded; |
|
141 #ifdef XP_WIN |
|
142 succeeded = TlsSetValue(key, h.ptr); |
|
143 #else |
|
144 succeeded = !pthread_setspecific(key, h.ptr); |
|
145 #endif |
|
146 if (!succeeded) |
|
147 MOZ_CRASH(); |
|
148 } |
|
149 |
|
150 } // namespace mozilla |
|
151 |
|
152 #endif /* mozilla_ThreadLocal_h */ |