]> git.saurik.com Git - apple/libdispatch.git/blob - src/shims/tsd.h
libdispatch-703.30.5.tar.gz
[apple/libdispatch.git] / src / shims / tsd.h
1 /*
2 * Copyright (c) 2008-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20
21 /*
22 * IMPORTANT: This header file describes INTERNAL interfaces to libdispatch
23 * which are subject to change in future releases of Mac OS X. Any applications
24 * relying on these interfaces WILL break.
25 */
26
27 #ifndef __DISPATCH_SHIMS_TSD__
28 #define __DISPATCH_SHIMS_TSD__
29
30 #if HAVE_PTHREAD_MACHDEP_H
31 #include <pthread_machdep.h>
32 #endif
33
34 #define DISPATCH_TSD_INLINE DISPATCH_ALWAYS_INLINE_NDEBUG
35
36 #if USE_APPLE_TSD_OPTIMIZATIONS && HAVE_PTHREAD_KEY_INIT_NP && \
37 !defined(DISPATCH_USE_DIRECT_TSD)
38 #define DISPATCH_USE_DIRECT_TSD 1
39 #if __has_include(<os/tsd.h>)
40 #include <os/tsd.h>
41 #endif
42
43 #if !defined(OS_GS_RELATIVE) && (defined(__i386__) || defined(__x86_64__))
44 #define OS_GS_RELATIVE __attribute__((address_space(256)))
45 #endif
46
47 #ifdef _os_tsd_get_base
48 #ifdef OS_GS_RELATIVE
49 typedef long dispatch_tsd_pair_t \
50 __attribute__((vector_size(sizeof(long) * 2), aligned(sizeof(long))));
51 #define _os_tsd_get_pair_address(k) \
52 (dispatch_tsd_pair_t OS_GS_RELATIVE *)((k) * sizeof(long))
53 #else
54 typedef struct { void *a; void *b; } dispatch_tsd_pair_t;
55 #define _os_tsd_get_pair_address(k) \
56 (dispatch_tsd_pair_t *)(_os_tsd_get_base() + (k))
57 #endif
58 #endif // _os_tsd_get_base
59 #endif
60
61 #if DISPATCH_USE_DIRECT_TSD
62 // dispatch_queue_key & dispatch_frame_key need to be contiguous
63 // in that order, and queue_key to be an even number
64 static const unsigned long dispatch_queue_key = __PTK_LIBDISPATCH_KEY0;
65 static const unsigned long dispatch_frame_key = __PTK_LIBDISPATCH_KEY1;
66 static const unsigned long dispatch_cache_key = __PTK_LIBDISPATCH_KEY2;
67 static const unsigned long dispatch_context_key = __PTK_LIBDISPATCH_KEY3;
68 static const unsigned long dispatch_pthread_root_queue_observer_hooks_key =
69 __PTK_LIBDISPATCH_KEY4;
70 static const unsigned long dispatch_defaultpriority_key =__PTK_LIBDISPATCH_KEY5;
71 #if DISPATCH_INTROSPECTION
72 static const unsigned long dispatch_introspection_key = __PTK_LIBDISPATCH_KEY6;
73 #elif DISPATCH_PERF_MON
74 static const unsigned long dispatch_bcounter_key = __PTK_LIBDISPATCH_KEY6;
75 #endif
76 static const unsigned long dispatch_sema4_key = __PTK_LIBDISPATCH_KEY7;
77
78 #ifndef __TSD_THREAD_QOS_CLASS
79 #define __TSD_THREAD_QOS_CLASS 4
80 #endif
81 #ifndef __TSD_THREAD_VOUCHER
82 #define __TSD_THREAD_VOUCHER 6
83 #endif
84 static const unsigned long dispatch_priority_key = __TSD_THREAD_QOS_CLASS;
85 static const unsigned long dispatch_voucher_key = __PTK_LIBDISPATCH_KEY8;
86 static const unsigned long dispatch_deferred_items_key = __PTK_LIBDISPATCH_KEY9;
87
88 DISPATCH_TSD_INLINE
89 static inline void
90 _dispatch_thread_key_create(const unsigned long *k, void (*d)(void *))
91 {
92 if (!*k || !d) return;
93 dispatch_assert_zero(pthread_key_init_np((int)*k, d));
94 }
95 #elif DISPATCH_USE_THREAD_LOCAL_STORAGE
96
97 DISPATCH_TSD_INLINE
98 static inline void
99 _dispatch_thread_key_create(pthread_key_t *k, void (*d)(void *))
100 {
101 dispatch_assert_zero(pthread_key_create(k, d));
102 }
103
104 struct dispatch_tsd {
105 pid_t tid;
106 void *dispatch_queue_key;
107 void *dispatch_frame_key;
108 void *dispatch_cache_key;
109 void *dispatch_context_key;
110 void *dispatch_pthread_root_queue_observer_hooks_key;
111 void *dispatch_defaultpriority_key;
112 #if DISPATCH_INTROSPECTION
113 void *dispatch_introspection_key;
114 #elif DISPATCH_PERF_MON
115 void *dispatch_bcounter_key;
116 #endif
117 #if DISPATCH_LOCK_USE_SEMAPHORE_FALLBACK
118 void *dispatch_sema4_key;
119 #endif
120 void *dispatch_priority_key;
121 void *dispatch_voucher_key;
122 void *dispatch_deferred_items_key;
123 };
124
125 extern __thread struct dispatch_tsd __dispatch_tsd;
126 extern pthread_key_t __dispatch_tsd_key;
127 extern void libdispatch_tsd_init(void);
128 extern void _libdispatch_tsd_cleanup(void *ctx);
129
130 DISPATCH_ALWAYS_INLINE
131 static inline struct dispatch_tsd *
132 _dispatch_get_tsd_base(void)
133 {
134 if (unlikely(__dispatch_tsd.tid == 0)) {
135 libdispatch_tsd_init();
136 }
137 OS_COMPILER_CAN_ASSUME(__dispatch_tsd.tid != 0);
138 return &__dispatch_tsd;
139 }
140
141 #define _dispatch_thread_getspecific(key) \
142 (_dispatch_get_tsd_base()->key)
143 #define _dispatch_thread_setspecific(key, value) \
144 (void)(_dispatch_get_tsd_base()->key = (value))
145
146 #define _dispatch_thread_getspecific_pair(k1, p1, k2, p2) \
147 ( *(p1) = _dispatch_thread_getspecific(k1), \
148 *(p2) = _dispatch_thread_getspecific(k2) )
149
150 #define _dispatch_thread_getspecific_packed_pair(k1, k2, p) \
151 ( (p)[0] = _dispatch_thread_getspecific(k1), \
152 (p)[1] = _dispatch_thread_getspecific(k2) )
153
154 #define _dispatch_thread_setspecific_pair(k1, p1, k2, p2) \
155 ( _dispatch_thread_setspecific(k1,p1), \
156 _dispatch_thread_setspecific(k2,p2) )
157
158 #define _dispatch_thread_setspecific_packed_pair(k1, k2, p) \
159 ( _dispatch_thread_setspecific(k1,(p)[0]), \
160 _dispatch_thread_setspecific(k2,(p)[1]) )
161
162 #else
163 extern pthread_key_t dispatch_queue_key;
164 extern pthread_key_t dispatch_frame_key;
165 extern pthread_key_t dispatch_cache_key;
166 extern pthread_key_t dispatch_context_key;
167 extern pthread_key_t dispatch_pthread_root_queue_observer_hooks_key;
168 extern pthread_key_t dispatch_defaultpriority_key;
169 #if DISPATCH_INTROSPECTION
170 extern pthread_key_t dispatch_introspection_key;
171 #elif DISPATCH_PERF_MON
172 extern pthread_key_t dispatch_bcounter_key;
173 #endif
174 extern pthread_key_t dispatch_sema4_key;
175 extern pthread_key_t dispatch_priority_key;
176 extern pthread_key_t dispatch_voucher_key;
177 extern pthread_key_t dispatch_deferred_items_key;
178
179 DISPATCH_TSD_INLINE
180 static inline void
181 _dispatch_thread_key_create(pthread_key_t *k, void (*d)(void *))
182 {
183 dispatch_assert_zero(pthread_key_create(k, d));
184 }
185 #endif
186
187 #ifndef DISPATCH_USE_THREAD_LOCAL_STORAGE
188 DISPATCH_TSD_INLINE
189 static inline void
190 _dispatch_thread_setspecific(pthread_key_t k, void *v)
191 {
192 #if DISPATCH_USE_DIRECT_TSD
193 if (_pthread_has_direct_tsd()) {
194 (void)_pthread_setspecific_direct(k, v);
195 } else {
196 #if TARGET_IPHONE_SIMULATOR
197 (void)_pthread_setspecific_static(k, v); // rdar://26058142
198 #else
199 __builtin_trap(); // unreachable
200 #endif
201 }
202 return;
203 #endif
204 dispatch_assert_zero(pthread_setspecific(k, v));
205 }
206
207 DISPATCH_TSD_INLINE
208 static inline void *
209 _dispatch_thread_getspecific(pthread_key_t k)
210 {
211 #if DISPATCH_USE_DIRECT_TSD
212 if (_pthread_has_direct_tsd()) {
213 return _pthread_getspecific_direct(k);
214 }
215 #endif
216 return pthread_getspecific(k);
217 }
218
219 // this is used when loading a pair at once and the caller will want to
220 // look at each component individually.
221 // some platforms can load a pair of pointers efficiently that way (like arm)
222 // intel doesn't, hence this degrades to two loads on intel
223 DISPATCH_TSD_INLINE
224 static inline void
225 _dispatch_thread_getspecific_pair(pthread_key_t k1, void **p1,
226 pthread_key_t k2, void **p2)
227 {
228 *p1 = _dispatch_thread_getspecific(k1);
229 *p2 = _dispatch_thread_getspecific(k2);
230 }
231
232 // this is used for save/restore purposes
233 // and the caller doesn't need to look at a specific component
234 // this does SSE on intel, and SSE is bad at breaking/assembling components
235 DISPATCH_TSD_INLINE
236 static inline void
237 _dispatch_thread_getspecific_packed_pair(pthread_key_t k1, pthread_key_t k2,
238 void **p)
239 {
240 #if DISPATCH_USE_DIRECT_TSD && defined(_os_tsd_get_pair_address)
241 dispatch_assert(k2 == k1 + 1);
242 if (_pthread_has_direct_tsd()) {
243 *(dispatch_tsd_pair_t *)p = *_os_tsd_get_pair_address(k1);
244 return;
245 }
246 #endif
247 p[0] = _dispatch_thread_getspecific(k1);
248 p[1] = _dispatch_thread_getspecific(k2);
249 }
250
251 // this is used when storing a pair at once from separated components
252 // some platforms can store a pair of pointers efficiently that way (like arm)
253 // intel doesn't, hence this degrades to two stores on intel
254 DISPATCH_TSD_INLINE
255 static inline void
256 _dispatch_thread_setspecific_pair(pthread_key_t k1, void *p1,
257 pthread_key_t k2, void *p2)
258 {
259 _dispatch_thread_setspecific(k1, p1);
260 _dispatch_thread_setspecific(k2, p2);
261 }
262
263 // this is used for save/restore purposes
264 // and the caller doesn't need to look at a specific component
265 // this does SSE on intel, and SSE is bad at breaking/assembling components
266 DISPATCH_TSD_INLINE
267 static inline void
268 _dispatch_thread_setspecific_packed_pair(pthread_key_t k1, pthread_key_t k2,
269 void **p)
270 {
271 #if DISPATCH_USE_DIRECT_TSD && defined(_os_tsd_get_pair_address)
272 dispatch_assert(k2 == k1 + 1);
273 if (_pthread_has_direct_tsd()) {
274 *_os_tsd_get_pair_address(k1) = *(dispatch_tsd_pair_t *)p;
275 return;
276 }
277 #endif
278 _dispatch_thread_setspecific(k1, p[0]);
279 _dispatch_thread_setspecific(k2, p[1]);
280 }
281 #endif
282
283 #if TARGET_OS_WIN32
284 #define _dispatch_thread_self() ((uintptr_t)GetCurrentThreadId())
285 #else
286 #if DISPATCH_USE_DIRECT_TSD
287 #define _dispatch_thread_self() ((uintptr_t)_dispatch_thread_getspecific( \
288 _PTHREAD_TSD_SLOT_PTHREAD_SELF))
289 #else
290 #define _dispatch_thread_self() ((uintptr_t)pthread_self())
291 #endif
292 #endif
293
294 #if TARGET_OS_WIN32
295 #define _dispatch_thread_port() ((mach_port_t)0)
296 #elif !DISPATCH_USE_THREAD_LOCAL_STORAGE
297 #if DISPATCH_USE_DIRECT_TSD
298 #define _dispatch_thread_port() ((mach_port_t)(uintptr_t)\
299 _dispatch_thread_getspecific(_PTHREAD_TSD_SLOT_MACH_THREAD_SELF))
300 #else
301 #define _dispatch_thread_port() pthread_mach_thread_np(_dispatch_thread_self())
302 #endif
303 #endif
304
305 #if HAVE_MACH
306 #define _dispatch_get_thread_mig_reply_port() ((mach_port_t)(uintptr_t) \
307 _dispatch_thread_getspecific(_PTHREAD_TSD_SLOT_MIG_REPLY))
308 #define _dispatch_set_thread_mig_reply_port(p) ( \
309 _dispatch_thread_setspecific(_PTHREAD_TSD_SLOT_MIG_REPLY, \
310 (void*)(uintptr_t)(p)))
311 #endif
312
313 DISPATCH_TSD_INLINE DISPATCH_CONST
314 static inline unsigned int
315 _dispatch_cpu_number(void)
316 {
317 #if __has_include(<os/tsd.h>)
318 return _os_cpu_number();
319 #elif defined(__x86_64__) || defined(__i386__)
320 struct { uintptr_t p1, p2; } p;
321 __asm__("sidt %[p]" : [p] "=&m" (p));
322 return (unsigned int)(p.p1 & 0xfff);
323 #else
324 // Not yet implemented.
325 return 0;
326 #endif
327 }
328
329 #undef DISPATCH_TSD_INLINE
330
331 #endif