X-Git-Url: https://git.saurik.com/apple/libpthread.git/blobdiff_plain/45deb508575711c47d78d19e326a9a26e43e63e0..c1f56ec94c29e576da2d6d7164bee1bdb2f02471:/src/types_internal.h diff --git a/src/types_internal.h b/src/types_internal.h new file mode 100644 index 0000000..858d94f --- /dev/null +++ b/src/types_internal.h @@ -0,0 +1,507 @@ +/* + * Copyright (c) 2003-2019 Apple Inc. All rights reserved. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * unlawful or unlicensed copies of an Apple operating system, or to + * circumvent, violate, or enable the circumvention or violation of, any + * terms of an Apple operating system software license agreement. + * + * Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ + */ + +#ifndef __LIBPTHREAD_TYPES_INTERNAL_H__ +#define __LIBPTHREAD_TYPES_INTERNAL_H__ + +/*! + * @file types_internal.h + * + * @brief + * This file exposes all the internal pthread types used by the library. + * + * @discussion + * This header must be included first, as it masks the opaque definitions + * exposed to libpthread clients in the SDK. + */ + +#define _PTHREAD_ONCE_T +typedef struct pthread_once_s pthread_once_t; + +#define _PTHREAD_MUTEX_T +#define _PTHREAD_MUTEXATTR_T +typedef struct pthread_mutex_s pthread_mutex_t; +typedef struct pthread_mutexattr_s pthread_mutexattr_t; + +#define _PTHREAD_COND_T +#define _PTHREAD_CONDATTR_T +typedef struct pthread_cond_s pthread_cond_t; +typedef struct pthread_condattr_s pthread_condattr_t; + +#define _PTHREAD_RWLOCK_T +#define _PTHREAD_RWLOCKATTR_T +typedef struct pthread_rwlock_s pthread_rwlock_t; +typedef struct pthread_rwlockattr_s pthread_rwlockattr_t; + +#define _PTHREAD_T +#define _PTHREAD_ATTR_T +typedef struct pthread_s *pthread_t; +typedef struct pthread_attr_s pthread_attr_t; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "pthread/posix_sched.h" +#include "pthread/workqueue_private.h" +#include "sys/_pthread/_pthread_types.h" + +#pragma mark - constants + +#define _PTHREAD_NO_SIG 0x00000000 +#define _PTHREAD_MUTEX_ATTR_SIG 0x4D545841 /* 'MTXA' */ +#define _PTHREAD_MUTEX_SIG 0x4D555458 /* 'MUTX' */ +#define _PTHREAD_MUTEX_SIG_fast 0x4D55545A /* 'MUTZ' */ +#define _PTHREAD_MUTEX_SIG_MASK 0xfffffffd +#define _PTHREAD_MUTEX_SIG_CMP 0x4D555458 /* _PTHREAD_MUTEX_SIG & _PTHREAD_MUTEX_SIG_MASK */ +#define _PTHREAD_MUTEX_SIG_init 0x32AAABA7 /* [almost] ~'MUTX' */ +#define _PTHREAD_ERRORCHECK_MUTEX_SIG_init 0x32AAABA1 +#define _PTHREAD_RECURSIVE_MUTEX_SIG_init 0x32AAABA2 +#define _PTHREAD_FIRSTFIT_MUTEX_SIG_init 0x32AAABA3 +#define _PTHREAD_MUTEX_SIG_init_MASK 0xfffffff0 +#define _PTHREAD_MUTEX_SIG_init_CMP 0x32AAABA0 +#define _PTHREAD_COND_ATTR_SIG 0x434E4441 /* 'CNDA' */ +#define _PTHREAD_COND_SIG_init 0x3CB0B1BB /* [almost] ~'COND' */ +#define _PTHREAD_COND_SIG_pristine 0x434F4E44 /* 'COND' */ +#define _PTHREAD_COND_SIG_psynch 0x434F4E45 /* 'COND' + 0b01: 'CONE' */ +#define _PTHREAD_COND_SIG_ulock 0x434F4E46 /* 'COND' + 0b10: 'CONF' */ +#define _PTHREAD_ATTR_SIG 0x54484441 /* 'THDA' */ +#define _PTHREAD_ONCE_SIG 0x4F4E4345 /* 'ONCE' */ +#define _PTHREAD_ONCE_SIG_init 0x30B1BCBA /* [almost] ~'ONCE' */ +#define _PTHREAD_SIG 0x54485244 /* 'THRD' */ +#define _PTHREAD_RWLOCK_ATTR_SIG 0x52574C41 /* 'RWLA' */ +#define _PTHREAD_RWLOCK_SIG 0x52574C4B /* 'RWLK' */ +#define _PTHREAD_RWLOCK_SIG_init 0x2DA8B3B4 /* [almost] ~'RWLK' */ + +__enum_closed_decl(pthread_conformance_t, unsigned, { + PTHREAD_CONFORM_UNIX03_NOCANCEL = 1, + PTHREAD_CONFORM_UNIX03_CANCELABLE = 2, +}); + +/* Pull the pthread_t into the same page as the top of the stack so we dirty one less page. + * The pthread_s struct at the top of the stack shouldn't be page-aligned + */ +#if defined(__arm64__) +#define PTHREAD_T_OFFSET (12*1024) +#else +#define PTHREAD_T_OFFSET 0 +#endif + +#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR +#define _EXTERNAL_POSIX_THREAD_KEYS_MAX 256 +#define _INTERNAL_POSIX_THREAD_KEYS_MAX 256 +#define _INTERNAL_POSIX_THREAD_KEYS_END 512 +#else +#define _EXTERNAL_POSIX_THREAD_KEYS_MAX 512 +#define _INTERNAL_POSIX_THREAD_KEYS_MAX 256 +#define _INTERNAL_POSIX_THREAD_KEYS_END 768 +#endif + +#define PTHREAD_ATFORK_INLINE_MAX 10 + +#define MAXTHREADNAMESIZE 64 + +#define _PTHREAD_DEFAULT_INHERITSCHED PTHREAD_INHERIT_SCHED +#define _PTHREAD_DEFAULT_PROTOCOL PTHREAD_PRIO_NONE +#define _PTHREAD_DEFAULT_PRIOCEILING 0 +#define _PTHREAD_DEFAULT_POLICY SCHED_OTHER +#define _PTHREAD_DEFAULT_STACKSIZE 0x80000 /* 512K */ +#define _PTHREAD_DEFAULT_PSHARED PTHREAD_PROCESS_PRIVATE + +#define _PTHREAD_CANCEL_STATE_MASK 0x01 +#define _PTHREAD_CANCEL_TYPE_MASK 0x02 +#define _PTHREAD_CANCEL_PENDING 0x10 /* pthread_cancel() has been called for this thread */ +#define _PTHREAD_CANCEL_EXITING 0x20 + +#define pthread_assert_type_size(type) \ + static_assert(sizeof(struct type##_s) == sizeof(struct _opaque_##type##_t), "") +#define pthread_assert_type_alias(type, f1, f2) \ + static_assert(offsetof(struct type##_s, f1) == offsetof(struct _opaque_##type##_t, f2), "") + +typedef os_unfair_lock _pthread_lock; +struct _pthread_registration_data; + + +#pragma mark - pthread_once_t + +struct pthread_once_s { + long sig; + os_once_t once; +}; + +pthread_assert_type_size(pthread_once); +pthread_assert_type_alias(pthread_once, sig, __sig); + +#pragma mark - pthread_mutex_t, pthread_mutexattr_t + +#define _PTHREAD_MUTEX_POLICY_LAST (PTHREAD_MUTEX_POLICY_FIRSTFIT_NP + 1) +#define _PTHREAD_MTX_OPT_POLICY_FAIRSHARE 1 +#define _PTHREAD_MTX_OPT_POLICY_FIRSTFIT 2 +#define _PTHREAD_MTX_OPT_POLICY_DEFAULT _PTHREAD_MTX_OPT_POLICY_FIRSTFIT +// The following pthread_mutex_options_s defintions exist in synch_internal.h +// such that the kernel extension can test for flags. They must be kept in +// sync with the bit values in the struct above. +// _PTHREAD_MTX_OPT_PSHARED 0x010 +// _PTHREAD_MTX_OPT_NOTIFY 0x1000 +// _PTHREAD_MTX_OPT_MUTEX 0x2000 + +#define _PTHREAD_MTX_OPT_ULOCK_DEFAULT false +#define _PTHREAD_MTX_OPT_ADAPTIVE_DEFAULT false + +// The fixed mask is used to mask out portions of the mutex options that +// change on a regular basis (notify, lock_count). +#define _PTHREAD_MTX_OPT_FIXED_MASK 0x27ff + +struct pthread_mutex_options_s { + uint32_t + protocol:2, + type:2, + pshared:2, + policy:3, + hold:2, + misalign:1, + notify:1, + mutex:1, + ulock:1, + unused:1, + lock_count:16; +}; + +#define _PTHREAD_MUTEX_ULOCK_OWNER_MASK 0xfffffffcu +#define _PTHREAD_MUTEX_ULOCK_WAITERS_BIT 0x00000001u +#define _PTHREAD_MUTEX_ULOCK_UNLOCKED_VALUE 0x0u +#define _PTHREAD_MUTEX_ULOCK_UNLOCKED \ + ((struct _pthread_mutex_ulock_s){0}) + +typedef struct _pthread_mutex_ulock_s { + uint32_t uval; +} *_pthread_mutex_ulock_t; + +struct pthread_mutex_s { + long sig; + _pthread_lock lock; + union { + uint32_t value; + struct pthread_mutex_options_s options; + } mtxopts; + int16_t prioceiling; + int16_t priority; +#if defined(__LP64__) + uint32_t _pad; +#endif + union { + struct { + uint32_t m_tid[2]; // thread id of thread that has mutex locked + uint32_t m_seq[2]; // mutex sequence id + uint32_t m_mis[2]; // for misaligned locks m_tid/m_seq will span into here + } psynch; + struct _pthread_mutex_ulock_s ulock; + }; +#if defined(__LP64__) + uint32_t _reserved[4]; +#else + uint32_t _reserved[1]; +#endif +}; + +pthread_assert_type_size(pthread_mutex); +pthread_assert_type_alias(pthread_mutex, sig, __sig); + +struct pthread_mutexattr_s { + long sig; + int prioceiling; + uint32_t + protocol:2, + type:2, + pshared:2, + opt:3, + unused:23; +}; + +pthread_assert_type_size(pthread_mutexattr); +pthread_assert_type_alias(pthread_mutexattr, sig, __sig); + +#pragma mark - pthread_rwlock_t, pthread_rwlockattr_t + +struct pthread_rwlock_s { + long sig; + _pthread_lock lock; + uint32_t + unused:29, + misalign:1, + pshared:2; + uint32_t rw_flags; +#if defined(__LP64__) + uint32_t _pad; +#endif + uint32_t rw_tid[2]; // thread id of thread that has exclusive (write) lock + uint32_t rw_seq[4]; // rw sequence id (at 128-bit aligned boundary) + uint32_t rw_mis[4]; // for misaligned locks rw_seq will span into here +#if defined(__LP64__) + uint32_t _reserved[34]; +#else + uint32_t _reserved[18]; +#endif +}; + +pthread_assert_type_size(pthread_rwlock); +pthread_assert_type_alias(pthread_rwlock, sig, __sig); + +struct pthread_rwlockattr_s { + long sig; + int pshared; +#if defined(__LP64__) + uint32_t _reserved[3]; +#else + uint32_t _reserved[2]; +#endif +}; + +pthread_assert_type_size(pthread_rwlockattr); +pthread_assert_type_alias(pthread_rwlockattr, sig, __sig); + +#pragma mark - pthread_cond_t, pthread_condattr_t + +struct pthread_cond_s { + struct { + uint32_t val; +#if defined(__LP64__) + uint32_t _pad; +#endif + } sig; + _pthread_lock lock; + uint32_t + unused:29, + misalign:1, + pshared:2; + pthread_mutex_t *busy; + uint32_t c_seq[3]; +#if defined(__LP64__) + uint32_t _reserved[3]; +#endif +}; + +pthread_assert_type_size(pthread_cond); +pthread_assert_type_alias(pthread_cond, sig, __sig); + +struct pthread_condattr_s { + long sig; + uint32_t + pshared:2, + unsupported:30; +}; + +pthread_assert_type_size(pthread_condattr); +pthread_assert_type_alias(pthread_condattr, sig, __sig); + +#pragma mark - pthread_t, pthread_attr_t + +typedef struct pthread_join_context_s { + pthread_t waiter; + void **value_ptr; + mach_port_t kport; + semaphore_t custom_stack_sema; + bool detached; +} pthread_join_context_s, *pthread_join_context_t; + +#define MAXTHREADNAMESIZE 64 + +struct pthread_s { + long sig; + struct __darwin_pthread_handler_rec *__cleanup_stack; + + // + // Fields protected by _pthread_list_lock + // + + TAILQ_ENTRY(pthread_s) tl_plist; // global thread list [aligned] + struct pthread_join_context_s *tl_join_ctx; + void *tl_exit_value; + uint8_t tl_policy; + // pthread knows that tl_joinable bit comes immediately after tl_policy + uint8_t + tl_joinable:1, + tl_joiner_cleans_up:1, + tl_has_custom_stack:1, + __tl_pad:5; + uint16_t introspection; + // MACH_PORT_NULL if no joiner + // tsd[_PTHREAD_TSD_SLOT_MACH_THREAD_SELF] when has a joiner + // MACH_PORT_DEAD if the thread exited + uint32_t tl_exit_gate; + struct sched_param tl_param; + void *__unused_padding; + + // + // Fields protected by pthread_t::lock + // + + _pthread_lock lock; + uint16_t max_tsd_key; + uint16_t + inherit:8, + kernalloc:1, + schedset:1, + wqthread:1, + wqkillset:1, + __flags_pad:4; + + char pthread_name[MAXTHREADNAMESIZE]; // includes NUL [aligned] + + void *(*fun)(void *); // thread start routine + void *arg; // thread start routine argument + int wq_nevents; // wqthreads (workloop / kevent) + bool wq_outsideqos; + uint8_t canceled; // 4597450 set if conformant cancelation happened + uint16_t cancel_state; // whether the thread can be canceled [atomic] + errno_t cancel_error; + errno_t err_no; // thread-local errno + + void *stackaddr; // base of the stack (page aligned) + void *stackbottom; // stackaddr - stacksize + void *freeaddr; // stack/thread allocation base address + size_t freesize; // stack/thread allocation size + size_t guardsize; // guard page size in bytes + + // tsd-base relative accessed elements + __attribute__((aligned(8))) + uint64_t thread_id; // 64-bit unique thread id + + /* Thread Specific Data slots + * + * The offset of this field from the start of the structure is difficult to + * change on OS X because of a thorny bitcompat issue: mono has hard coded + * the value into their source. Newer versions of mono will fall back to + * scanning to determine it at runtime, but there's lots of software built + * with older mono that won't. We will have to break them someday... + */ + __attribute__ ((aligned (16))) + void *tsd[_EXTERNAL_POSIX_THREAD_KEYS_MAX + _INTERNAL_POSIX_THREAD_KEYS_MAX]; +}; + +TAILQ_HEAD(__pthread_list, pthread_s); + +#if 0 // pthread_t is never stack-allocated, so it doesn't matter +pthread_assert_type_size(pthread); +#endif +pthread_assert_type_alias(pthread, sig, __sig); +pthread_assert_type_alias(pthread, __cleanup_stack, __cleanup_stack); +#if __LP64__ +static_assert(offsetof(struct pthread_s, tsd) == 224, "TSD LP64 offset"); +#else +static_assert(offsetof(struct pthread_s, tsd) == 176, "TSD ILP32 offset"); +#endif + +#define _PTHREAD_ATTR_REFILLMS_MAX ((2<<24) - 1) + +struct pthread_attr_s { + long sig; + size_t guardsize; // size in bytes of stack overflow guard area + void *stackaddr; // stack base; vm_page_size aligned + size_t stacksize; // stack size; multiple of vm_page_size and >= PTHREAD_STACK_MIN + union { + struct sched_param param; // [aligned] + unsigned long qosclass; // pthread_priority_t + }; + uint32_t + detached:8, + inherit:8, + policy:8, + schedset:1, + qosset:1, + policyset:1, + cpupercentset:1, + defaultguardpage:1, + unused:3; + uint32_t + cpupercent:8, + refillms:24; +#if defined(__LP64__) + uint32_t _reserved[4]; +#else + uint32_t _reserved[2]; +#endif +}; + +pthread_assert_type_size(pthread_attr); +pthread_assert_type_alias(pthread_attr, sig, __sig); + +#pragma mark - atfork / qos + +struct pthread_atfork_entry { + void (*prepare)(void); + void (*parent)(void); + void (*child)(void); +}; + +#define PTHREAD_ATFORK_INLINE_MAX 10 +#if defined(__arm__) +// Hack. We don't want to depend on libcompiler_rt. armv7 implements integer +// division by calling into compiler_rt. vm_page_size isn't a constant and +// pthread_atfork_entry is 12 bytes so the compiler can't strength-reduce the +// division, so it generates a call into compiler_rt. +// So let's just use PAGE_MAX_SIZE on armv7, which is a constant. At worst +// this wastes a maybe dozen K if we are actaully running on a smaller page +// size than the max. +// At the time of this writing we don't have any supported iOS armv7 hardware +// that has different vm_page_size and PAGE_MAX_SIZE. +#define PTHREAD_ATFORK_MAX (PAGE_MAX_SIZE/sizeof(struct pthread_atfork_entry)) +#else // defined(__arm__) +#define PTHREAD_ATFORK_MAX (vm_page_size/sizeof(struct pthread_atfork_entry)) +#endif // defined(__arm__) + +struct pthread_globals_s { + // atfork.c + pthread_t psaved_self; + _pthread_lock psaved_self_global_lock; + _pthread_lock pthread_atfork_lock; + + size_t atfork_count; + struct pthread_atfork_entry atfork_storage[PTHREAD_ATFORK_INLINE_MAX]; + struct pthread_atfork_entry *atfork; + uint16_t qmp_logical[THREAD_QOS_LAST]; + uint16_t qmp_physical[THREAD_QOS_LAST]; + +}; +typedef struct pthread_globals_s *pthread_globals_t; + +#endif // __LIBPTHREAD_TYPES_INTERNAL_H__