--- /dev/null
+/*
+ * 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 <assert.h>
+#include <errno.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/queue.h>
+#include <sys/param.h>
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <os/base_private.h>
+#include <os/once_private.h>
+#include <os/lock.h>
+
+#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.
+ * <rdar://problem/19941744> 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__