#ifndef __LIBPTHREAD_INLINE_INTERNAL_H__
#define __LIBPTHREAD_INLINE_INTERNAL_H__
#define PTHREAD_INTERNAL_CRASH(c, x) OS_BUG_INTERNAL(c, "LIBPTHREAD", x)
#define PTHREAD_CLIENT_CRASH(c, x) OS_BUG_CLIENT(c, "LIBPTHREAD", x)
#ifdef DEBUG
#define PTHREAD_DEBUG_ASSERT(b) \
do { \
if (os_unlikely(!(b))) { \
PTHREAD_INTERNAL_CRASH(0, "Assertion failed: " #b); \
} \
} while (0)
#else
#define PTHREAD_DEBUG_ASSERT(b) ((void)0)
#endif
#pragma mark _pthread_mutex_check_signature
OS_ALWAYS_INLINE
static inline bool
_pthread_mutex_check_signature_fast(pthread_mutex_t *mutex)
{
return (mutex->sig == _PTHREAD_MUTEX_SIG_fast);
}
OS_ALWAYS_INLINE
static inline bool
_pthread_mutex_check_signature(const pthread_mutex_t *mutex)
{
return ((mutex->sig & _PTHREAD_MUTEX_SIG_MASK) == _PTHREAD_MUTEX_SIG_CMP);
}
OS_ALWAYS_INLINE
static inline bool
_pthread_mutex_check_signature_init(const pthread_mutex_t *mutex)
{
return ((mutex->sig & _PTHREAD_MUTEX_SIG_init_MASK) ==
_PTHREAD_MUTEX_SIG_init_CMP);
}
#pragma mark pthread mutex accessors
OS_ALWAYS_INLINE
static inline bool
_pthread_mutex_uses_ulock(pthread_mutex_t *mutex)
{
return mutex->mtxopts.options.ulock;
}
#pragma mark _pthread_rwlock_check_signature
OS_ALWAYS_INLINE
static inline bool
_pthread_rwlock_check_signature(const pthread_rwlock_t *rwlock)
{
return (rwlock->sig == _PTHREAD_RWLOCK_SIG);
}
OS_ALWAYS_INLINE
static inline bool
_pthread_rwlock_check_signature_init(const pthread_rwlock_t *rwlock)
{
return (rwlock->sig == _PTHREAD_RWLOCK_SIG_init);
}
#pragma mark unfair lock wrappers
#define _PTHREAD_LOCK_INITIALIZER OS_UNFAIR_LOCK_INIT
#define _PTHREAD_LOCK_OPTIONS \
(OS_UNFAIR_LOCK_DATA_SYNCHRONIZATION | OS_UNFAIR_LOCK_ADAPTIVE_SPIN)
OS_ALWAYS_INLINE
static inline void
_pthread_lock_init(os_unfair_lock_t lock)
{
*lock = _PTHREAD_LOCK_INITIALIZER;
}
OS_OVERLOADABLE OS_ALWAYS_INLINE
static inline void
_pthread_lock_lock(os_unfair_lock_t lock)
{
#if OS_UNFAIR_LOCK_INLINE
os_unfair_lock_lock_with_options_inline(lock, _PTHREAD_LOCK_OPTIONS);
#else
os_unfair_lock_lock_with_options(lock, _PTHREAD_LOCK_OPTIONS);
#endif
}
OS_OVERLOADABLE OS_ALWAYS_INLINE
static inline void
_pthread_lock_lock(os_unfair_lock_t lock, mach_port_t mts)
{
#if OS_UNFAIR_LOCK_INLINE
os_unfair_lock_lock_no_tsd_inline(lock, _PTHREAD_LOCK_OPTIONS, mts);
#else
os_unfair_lock_lock_no_tsd(lock, _PTHREAD_LOCK_OPTIONS, mts);
#endif
}
OS_OVERLOADABLE OS_ALWAYS_INLINE
static inline void
_pthread_lock_unlock(os_unfair_lock_t lock)
{
#if OS_UNFAIR_LOCK_INLINE
os_unfair_lock_unlock_inline(lock);
#else
os_unfair_lock_unlock(lock);
#endif
}
OS_OVERLOADABLE OS_ALWAYS_INLINE
static inline void
_pthread_lock_unlock(os_unfair_lock_t lock, mach_port_t mts)
{
#if OS_UNFAIR_LOCK_INLINE
os_unfair_lock_unlock_no_tsd_inline(lock, mts);
#else
os_unfair_lock_unlock_no_tsd(lock, mts);
#endif
}
#pragma mark pthread accessors
#define pthread_self() _pthread_self_direct()
#undef errno
#define errno (*_pthread_errno_address_direct())
#define _pthread_tsd_slot(th, name) \
(*(_PTHREAD_TSD_SLOT_##name##_TYPE *)(uintptr_t *)&(th)->tsd[_PTHREAD_TSD_SLOT_##name])
OS_ALWAYS_INLINE
static inline void
_pthread_validate_signature(pthread_t thread)
{
pthread_t th = (pthread_t)(thread->sig ^ _pthread_ptr_munge_token);
#if __has_feature(ptrauth_calls)
th = ptrauth_auth_data(th, ptrauth_key_process_dependent_data,
ptrauth_string_discriminator("pthread.signature"));
#endif
if (os_unlikely(th != thread)) {
abort_with_reason(OS_REASON_LIBSYSTEM, 4, "pthread_t was corrupted", 0);
}
}
OS_ALWAYS_INLINE
static inline void
_pthread_init_signature(pthread_t thread)
{
pthread_t th = thread;
#if __has_feature(ptrauth_calls)
th = ptrauth_sign_unauthenticated(th, ptrauth_key_process_dependent_data,
ptrauth_string_discriminator("pthread.signature"));
#endif
thread->sig = (uintptr_t)th ^ _pthread_ptr_munge_token;
}
OS_ALWAYS_INLINE
static inline bool
_pthread_validate_thread_and_list_lock(pthread_t thread)
{
pthread_t p;
if (thread == NULL) return false;
_pthread_lock_lock(&_pthread_list_lock);
TAILQ_FOREACH(p, &__pthread_head, tl_plist) {
if (p != thread) continue;
_pthread_validate_signature(p);
return true;
}
_pthread_lock_unlock(&_pthread_list_lock);
return false;
}
OS_ALWAYS_INLINE
static inline bool
_pthread_is_valid(pthread_t thread, mach_port_t *portp)
{
mach_port_t kport = MACH_PORT_NULL;
bool valid;
if (thread == pthread_self()) {
_pthread_validate_signature(thread);
valid = true;
kport = _pthread_tsd_slot(thread, MACH_THREAD_SELF);
} else if (!_pthread_validate_thread_and_list_lock(thread)) {
valid = false;
} else {
kport = _pthread_tsd_slot(thread, MACH_THREAD_SELF);
valid = true;
_pthread_lock_unlock(&_pthread_list_lock);
}
if (portp != NULL) {
*portp = kport;
}
return valid;
}
OS_ALWAYS_INLINE OS_CONST
static inline pthread_globals_t
_pthread_globals(void)
{
return os_alloc_once(OS_ALLOC_ONCE_KEY_LIBSYSTEM_PTHREAD,
sizeof(struct pthread_globals_s), NULL);
}
#endif // __LIBPTHREAD_INLINE_INTERNAL_H__