| |
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 */ |