blob: c119e4f014399e9566c091af010766869e3fbe81 [file] [log] [blame]
/*
* Copyright (c) 2008-2013 Apple Inc. All rights reserved.
*
* @APPLE_APACHE_LICENSE_HEADER_START@
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @APPLE_APACHE_LICENSE_HEADER_END@
*/
/*
* IMPORTANT: This header file describes INTERNAL interfaces to libdispatch
* which are subject to change in future releases of Mac OS X. Any applications
* relying on these interfaces WILL break.
*/
#ifndef __DISPATCH_SHIMS_TSD__
#define __DISPATCH_SHIMS_TSD__
#if HAVE_PTHREAD_MACHDEP_H
#include <pthread_machdep.h>
#endif
#define DISPATCH_TSD_INLINE DISPATCH_ALWAYS_INLINE_NDEBUG
#if USE_APPLE_TSD_OPTIMIZATIONS && HAVE_PTHREAD_KEY_INIT_NP && \
!defined(DISPATCH_USE_DIRECT_TSD)
#define DISPATCH_USE_DIRECT_TSD 1
#if __has_include(<os/tsd.h>)
#include <os/tsd.h>
#endif
#if !defined(OS_GS_RELATIVE) && (defined(__i386__) || defined(__x86_64__))
#define OS_GS_RELATIVE __attribute__((address_space(256)))
#endif
#ifdef _os_tsd_get_base
#ifdef OS_GS_RELATIVE
typedef long dispatch_tsd_pair_t \
__attribute__((vector_size(sizeof(long) * 2), aligned(sizeof(long))));
#define _os_tsd_get_pair_address(k) \
(dispatch_tsd_pair_t OS_GS_RELATIVE *)((k) * sizeof(long))
#else
typedef struct { void *a; void *b; } dispatch_tsd_pair_t;
#define _os_tsd_get_pair_address(k) \
(dispatch_tsd_pair_t *)(_os_tsd_get_base() + (k))
#endif
#endif // _os_tsd_get_base
#endif
#if DISPATCH_USE_DIRECT_TSD
#ifndef __TSD_THREAD_QOS_CLASS
#define __TSD_THREAD_QOS_CLASS 4
#endif
#ifndef __TSD_RETURN_TO_KERNEL
#define __TSD_RETURN_TO_KERNEL 5
#endif
#ifndef __TSD_MACH_SPECIAL_REPLY
#define __TSD_MACH_SPECIAL_REPLY 8
#endif
static const unsigned long dispatch_priority_key = __TSD_THREAD_QOS_CLASS;
static const unsigned long dispatch_r2k_key = __TSD_RETURN_TO_KERNEL;
// dispatch_queue_key & dispatch_frame_key need to be contiguous
// in that order, and queue_key to be an even number
static const unsigned long dispatch_queue_key = __PTK_LIBDISPATCH_KEY0;
static const unsigned long dispatch_frame_key = __PTK_LIBDISPATCH_KEY1;
static const unsigned long dispatch_cache_key = __PTK_LIBDISPATCH_KEY2;
static const unsigned long dispatch_context_key = __PTK_LIBDISPATCH_KEY3;
static const unsigned long dispatch_pthread_root_queue_observer_hooks_key =
__PTK_LIBDISPATCH_KEY4;
static const unsigned long dispatch_basepri_key = __PTK_LIBDISPATCH_KEY5;
#if DISPATCH_INTROSPECTION
static const unsigned long dispatch_introspection_key = __PTK_LIBDISPATCH_KEY6;
#elif DISPATCH_PERF_MON
static const unsigned long dispatch_bcounter_key = __PTK_LIBDISPATCH_KEY6;
#endif
static const unsigned long dispatch_wlh_key = __PTK_LIBDISPATCH_KEY7;
static const unsigned long dispatch_voucher_key = __PTK_LIBDISPATCH_KEY8;
static const unsigned long dispatch_deferred_items_key = __PTK_LIBDISPATCH_KEY9;
DISPATCH_TSD_INLINE
static inline void
_dispatch_thread_key_create(const unsigned long *k, void (*d)(void *))
{
if (!*k || !d) return;
dispatch_assert_zero(pthread_key_init_np((int)*k, d));
}
#elif DISPATCH_USE_THREAD_LOCAL_STORAGE
DISPATCH_TSD_INLINE
static inline void
_dispatch_thread_key_create(pthread_key_t *k, void (*d)(void *))
{
dispatch_assert_zero(pthread_key_create(k, d));
}
struct dispatch_tsd {
pid_t tid;
void *dispatch_queue_key;
void *dispatch_frame_key;
void *dispatch_cache_key;
void *dispatch_context_key;
void *dispatch_pthread_root_queue_observer_hooks_key;
void *dispatch_basepri_key;
#if DISPATCH_INTROSPECTION
void *dispatch_introspection_key;
#elif DISPATCH_PERF_MON
void *dispatch_bcounter_key;
#endif
void *dispatch_priority_key;
void *dispatch_r2k_key;
void *dispatch_wlh_key;
void *dispatch_voucher_key;
void *dispatch_deferred_items_key;
};
extern __thread struct dispatch_tsd __dispatch_tsd;
extern pthread_key_t __dispatch_tsd_key;
extern void libdispatch_tsd_init(void);
extern void _libdispatch_tsd_cleanup(void *ctx);
DISPATCH_ALWAYS_INLINE
static inline struct dispatch_tsd *
_dispatch_get_tsd_base(void)
{
if (unlikely(__dispatch_tsd.tid == 0)) {
libdispatch_tsd_init();
}
OS_COMPILER_CAN_ASSUME(__dispatch_tsd.tid != 0);
return &__dispatch_tsd;
}
#define _dispatch_thread_getspecific(key) \
(_dispatch_get_tsd_base()->key)
#define _dispatch_thread_setspecific(key, value) \
(void)(_dispatch_get_tsd_base()->key = (value))
#define _dispatch_thread_getspecific_pair(k1, p1, k2, p2) \
( *(p1) = _dispatch_thread_getspecific(k1), \
*(p2) = _dispatch_thread_getspecific(k2) )
#define _dispatch_thread_getspecific_packed_pair(k1, k2, p) \
( (p)[0] = _dispatch_thread_getspecific(k1), \
(p)[1] = _dispatch_thread_getspecific(k2) )
#define _dispatch_thread_setspecific_pair(k1, p1, k2, p2) \
( _dispatch_thread_setspecific(k1,p1), \
_dispatch_thread_setspecific(k2,p2) )
#define _dispatch_thread_setspecific_packed_pair(k1, k2, p) \
( _dispatch_thread_setspecific(k1,(p)[0]), \
_dispatch_thread_setspecific(k2,(p)[1]) )
#else
extern pthread_key_t dispatch_priority_key;
extern pthread_key_t dispatch_r2k_key;
extern pthread_key_t dispatch_queue_key;
extern pthread_key_t dispatch_frame_key;
extern pthread_key_t dispatch_cache_key;
extern pthread_key_t dispatch_context_key;
extern pthread_key_t dispatch_pthread_root_queue_observer_hooks_key;
extern pthread_key_t dispatch_basepri_key;
#if DISPATCH_INTROSPECTION
extern pthread_key_t dispatch_introspection_key;
#elif DISPATCH_PERF_MON
extern pthread_key_t dispatch_bcounter_key;
#endif
extern pthread_key_t dispatch_wlh_key;
extern pthread_key_t dispatch_voucher_key;
extern pthread_key_t dispatch_deferred_items_key;
DISPATCH_TSD_INLINE
static inline void
_dispatch_thread_key_create(pthread_key_t *k, void (*d)(void *))
{
dispatch_assert_zero(pthread_key_create(k, d));
}
#endif
#ifndef DISPATCH_USE_THREAD_LOCAL_STORAGE
DISPATCH_TSD_INLINE
static inline void
_dispatch_thread_setspecific(pthread_key_t k, void *v)
{
#if DISPATCH_USE_DIRECT_TSD
if (_pthread_has_direct_tsd()) {
(void)_pthread_setspecific_direct(k, v);
} else {
#if TARGET_IPHONE_SIMULATOR
(void)_pthread_setspecific_static(k, v); // rdar://26058142
#else
__builtin_trap(); // unreachable
#endif
}
return;
#endif
dispatch_assert_zero(pthread_setspecific(k, v));
}
DISPATCH_TSD_INLINE
static inline void *
_dispatch_thread_getspecific(pthread_key_t k)
{
#if DISPATCH_USE_DIRECT_TSD
if (_pthread_has_direct_tsd()) {
return _pthread_getspecific_direct(k);
}
#endif
return pthread_getspecific(k);
}
// this is used when loading a pair at once and the caller will want to
// look at each component individually.
// some platforms can load a pair of pointers efficiently that way (like arm)
// intel doesn't, hence this degrades to two loads on intel
DISPATCH_TSD_INLINE
static inline void
_dispatch_thread_getspecific_pair(pthread_key_t k1, void **p1,
pthread_key_t k2, void **p2)
{
*p1 = _dispatch_thread_getspecific(k1);
*p2 = _dispatch_thread_getspecific(k2);
}
// this is used for save/restore purposes
// and the caller doesn't need to look at a specific component
// this does SSE on intel, and SSE is bad at breaking/assembling components
DISPATCH_TSD_INLINE
static inline void
_dispatch_thread_getspecific_packed_pair(pthread_key_t k1, pthread_key_t k2,
void **p)
{
#if DISPATCH_USE_DIRECT_TSD && defined(_os_tsd_get_pair_address)
dispatch_assert(k2 == k1 + 1);
if (_pthread_has_direct_tsd()) {
*(dispatch_tsd_pair_t *)p = *_os_tsd_get_pair_address(k1);
return;
}
#endif
p[0] = _dispatch_thread_getspecific(k1);
p[1] = _dispatch_thread_getspecific(k2);
}
// this is used when storing a pair at once from separated components
// some platforms can store a pair of pointers efficiently that way (like arm)
// intel doesn't, hence this degrades to two stores on intel
DISPATCH_TSD_INLINE
static inline void
_dispatch_thread_setspecific_pair(pthread_key_t k1, void *p1,
pthread_key_t k2, void *p2)
{
_dispatch_thread_setspecific(k1, p1);
_dispatch_thread_setspecific(k2, p2);
}
// this is used for save/restore purposes
// and the caller doesn't need to look at a specific component
// this does SSE on intel, and SSE is bad at breaking/assembling components
DISPATCH_TSD_INLINE
static inline void
_dispatch_thread_setspecific_packed_pair(pthread_key_t k1, pthread_key_t k2,
void **p)
{
#if DISPATCH_USE_DIRECT_TSD && defined(_os_tsd_get_pair_address)
dispatch_assert(k2 == k1 + 1);
if (_pthread_has_direct_tsd()) {
*_os_tsd_get_pair_address(k1) = *(dispatch_tsd_pair_t *)p;
return;
}
#endif
_dispatch_thread_setspecific(k1, p[0]);
_dispatch_thread_setspecific(k2, p[1]);
}
#endif
#if TARGET_OS_WIN32
#define _dispatch_thread_self() ((uintptr_t)GetCurrentThreadId())
#else
#if DISPATCH_USE_DIRECT_TSD
#define _dispatch_thread_self() ((uintptr_t)_dispatch_thread_getspecific( \
_PTHREAD_TSD_SLOT_PTHREAD_SELF))
#else
#define _dispatch_thread_self() ((uintptr_t)pthread_self())
#endif
#endif
#if TARGET_OS_WIN32
#define _dispatch_thread_port() ((mach_port_t)0)
#elif !DISPATCH_USE_THREAD_LOCAL_STORAGE
#if DISPATCH_USE_DIRECT_TSD
#define _dispatch_thread_port() ((mach_port_t)(uintptr_t)\
_dispatch_thread_getspecific(_PTHREAD_TSD_SLOT_MACH_THREAD_SELF))
#else
#define _dispatch_thread_port() pthread_mach_thread_np(_dispatch_thread_self())
#endif
#endif
#if HAVE_MACH
#define _dispatch_get_thread_mig_reply_port() ((mach_port_t)(uintptr_t) \
_dispatch_thread_getspecific(_PTHREAD_TSD_SLOT_MIG_REPLY))
#define _dispatch_set_thread_mig_reply_port(p) ( \
_dispatch_thread_setspecific(_PTHREAD_TSD_SLOT_MIG_REPLY, \
(void*)(uintptr_t)(p)))
#define _dispatch_get_thread_special_reply_port() ((mach_port_t)(uintptr_t) \
_dispatch_thread_getspecific(__TSD_MACH_SPECIAL_REPLY))
#define _dispatch_set_thread_special_reply_port(p) ( \
_dispatch_thread_setspecific(__TSD_MACH_SPECIAL_REPLY, \
(void*)(uintptr_t)(p)))
#endif
DISPATCH_TSD_INLINE DISPATCH_CONST
static inline unsigned int
_dispatch_cpu_number(void)
{
#if __has_include(<os/tsd.h>)
return _os_cpu_number();
#elif defined(__x86_64__) || defined(__i386__)
struct { uintptr_t p1, p2; } p;
__asm__("sidt %[p]" : [p] "=&m" (p));
return (unsigned int)(p.p1 & 0xfff);
#else
// Not yet implemented.
return 0;
#endif
}
#undef DISPATCH_TSD_INLINE
#endif