--- /dev/null
+//
+// pthread.c
+// pthread
+//
+// Created by Matt Wright on 9/13/12.
+// Copyright (c) 2012 Matt Wright. All rights reserved.
+//
+
+#include <kern/thread.h>
+#include <kern/debug.h>
+#include "kern_internal.h"
+
+kern_return_t pthread_start(kmod_info_t * ki, void *d);
+kern_return_t pthread_stop(kmod_info_t *ki, void *d);
+
+pthread_callbacks_t pthread_kern;
+
+const struct pthread_functions_s pthread_internal_functions = {
+ .pthread_init = _pthread_init,
+ .fill_procworkqueue = _fill_procworkqueue,
+ .workqueue_init_lock = _workqueue_init_lock,
+ .workqueue_destroy_lock = _workqueue_destroy_lock,
+ .workqueue_exit = _workqueue_exit,
+ .workqueue_mark_exiting = _workqueue_mark_exiting,
+ .workqueue_thread_yielded = _workqueue_thread_yielded,
+ .workqueue_get_sched_callback = _workqueue_get_sched_callback,
+ .pth_proc_hashinit = _pth_proc_hashinit,
+ .pth_proc_hashdelete = _pth_proc_hashdelete,
+ .bsdthread_create = _bsdthread_create,
+ .bsdthread_register = _bsdthread_register,
+ .bsdthread_terminate = _bsdthread_terminate,
+ .bsdthread_ctl = _bsdthread_ctl,
+ .thread_selfid = _thread_selfid,
+ .workq_kernreturn = _workq_kernreturn,
+ .workq_open = _workq_open,
+
+ .psynch_mutexwait = _psynch_mutexwait,
+ .psynch_mutexdrop = _psynch_mutexdrop,
+ .psynch_cvbroad = _psynch_cvbroad,
+ .psynch_cvsignal = _psynch_cvsignal,
+ .psynch_cvwait = _psynch_cvwait,
+ .psynch_cvclrprepost = _psynch_cvclrprepost,
+ .psynch_rw_longrdlock = _psynch_rw_longrdlock,
+ .psynch_rw_rdlock = _psynch_rw_rdlock,
+ .psynch_rw_unlock = _psynch_rw_unlock,
+ .psynch_rw_wrlock = _psynch_rw_wrlock,
+ .psynch_rw_yieldwrlock = _psynch_rw_yieldwrlock,
+};
+
+kern_return_t pthread_start(__unused kmod_info_t * ki, __unused void *d)
+{
+ pthread_kext_register((pthread_functions_t)&pthread_internal_functions, &pthread_kern);
+ return KERN_SUCCESS;
+}
+
+kern_return_t pthread_stop(__unused kmod_info_t *ki, __unused void *d)
+{
+ return KERN_FAILURE;
+}
+
+struct uthread*
+current_uthread(void)
+{
+ thread_t th = current_thread();
+ return pthread_kern->get_bsdthread_info(th);
+}
--- /dev/null
+/*
+ * Copyright (c) 2000-2003 Apple Computer, 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 _SYS_PTHREAD_INTERNAL_H_
+#define _SYS_PTHREAD_INTERNAL_H_
+
+#ifdef KERNEL
+#include <kern/thread_call.h>
+#include <sys/pthread_shims.h>
+#include <sys/queue.h>
+#endif
+
+#include "kern/synch_internal.h"
+#include "kern/workqueue_internal.h"
+#include "kern/kern_trace.h"
+#include "pthread/qos.h"
+#include "private/qos_private.h"
+
+/* pthread userspace SPI feature checking, these constants are returned from bsdthread_register,
+ * as a bitmask, to inform userspace of the supported feature set. Old releases of OS X return
+ * from this call either zero or -1, allowing us to return a positive number for feature bits.
+ */
+#define PTHREAD_FEATURE_DISPATCHFUNC 0x01 /* same as WQOPS_QUEUE_NEWSPISUPP, checks for dispatch function support */
+#define PTHREAD_FEATURE_FINEPRIO 0x02 /* are fine grained prioirities available */
+#define PTHREAD_FEATURE_BSDTHREADCTL 0x04 /* is the bsdthread_ctl syscall available */
+#define PTHREAD_FEATURE_SETSELF 0x08 /* is the BSDTHREAD_CTL_SET_SELF command of bsdthread_ctl available */
+#define PTHREAD_FEATURE_QOS_MAINTENANCE 0x10 /* is QOS_CLASS_MAINTENANCE available */
+#define PTHREAD_FEATURE_QOS_DEFAULT 0x40000000 /* the kernel supports QOS_CLASS_DEFAULT */
+
+/* pthread bsdthread_ctl sysctl commands */
+#define BSDTHREAD_CTL_SET_QOS 0x10 /* bsdthread_ctl(BSDTHREAD_CTL_SET_QOS, thread_port, tsd_entry_addr, 0) */
+#define BSDTHREAD_CTL_GET_QOS 0x20 /* bsdthread_ctl(BSDTHREAD_CTL_GET_QOS, thread_port, 0, 0) */
+#define BSDTHREAD_CTL_QOS_OVERRIDE_START 0x40 /* bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_START, thread_port, priority, 0) */
+#define BSDTHREAD_CTL_QOS_OVERRIDE_END 0x80 /* bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_END, thread_port, 0, 0) */
+#define BSDTHREAD_CTL_SET_SELF 0x100 /* bsdthread_ctl(BSDTHREAD_CTL_SET_SELF, priority, voucher, flags) */
+#define BSDTHREAD_CTL_QOS_OVERRIDE_RESET 0x200 /* bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_RESET, 0, 0, 0) */
+#define BSDTHREAD_CTL_QOS_OVERRIDE_DISPATCH 0x400 /* bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_DISPATCH, thread_port, priority, 0) */
+
+/* qos_class_t is mapped into one of these bits in the bitfield, this mapping now exists here because
+ * libdispatch requires the QoS class mask of the pthread_priority_t to be a bitfield.
+ */
+#define __PTHREAD_PRIORITY_CBIT_USER_INTERACTIVE 0x20
+#define __PTHREAD_PRIORITY_CBIT_USER_INITIATED 0x10
+#define __PTHREAD_PRIORITY_CBIT_DEFAULT 0x8
+#define __PTHREAD_PRIORITY_CBIT_UTILITY 0x4
+#define __PTHREAD_PRIORITY_CBIT_BACKGROUND 0x2
+#define __PTHREAD_PRIORITY_CBIT_MAINTENANCE 0x1
+#define __PTHREAD_PRIORITY_CBIT_UNSPECIFIED 0x0
+
+/* Added support for QOS_CLASS_MAINTENANCE */
+static inline pthread_priority_t
+_pthread_priority_make_newest(qos_class_t qc, int rel, unsigned long flags)
+{
+ pthread_priority_t cls;
+ switch (qc) {
+ case QOS_CLASS_USER_INTERACTIVE: cls = __PTHREAD_PRIORITY_CBIT_USER_INTERACTIVE; break;
+ case QOS_CLASS_USER_INITIATED: cls = __PTHREAD_PRIORITY_CBIT_USER_INITIATED; break;
+ case QOS_CLASS_DEFAULT: cls = __PTHREAD_PRIORITY_CBIT_DEFAULT; break;
+ case QOS_CLASS_UTILITY: cls = __PTHREAD_PRIORITY_CBIT_UTILITY; break;
+ case QOS_CLASS_BACKGROUND: cls = __PTHREAD_PRIORITY_CBIT_BACKGROUND; break;
+ case QOS_CLASS_MAINTENANCE: cls = __PTHREAD_PRIORITY_CBIT_MAINTENANCE; break;
+ case QOS_CLASS_UNSPECIFIED:
+ default:
+ cls = __PTHREAD_PRIORITY_CBIT_UNSPECIFIED;
+ rel = 1; // results in priority bits == 0 <rdar://problem/16184900>
+ break;
+ }
+
+ pthread_priority_t p =
+ (flags & _PTHREAD_PRIORITY_FLAGS_MASK) |
+ ((cls << _PTHREAD_PRIORITY_QOS_CLASS_SHIFT) & _PTHREAD_PRIORITY_QOS_CLASS_MASK) |
+ (((uint8_t)rel - 1) & _PTHREAD_PRIORITY_PRIORITY_MASK);
+
+ return p;
+}
+
+/* Added support for QOS_CLASS_LEGACY and QOS_CLASS_INHERIT */
+static inline pthread_priority_t
+_pthread_priority_make_version2(qos_class_t qc, int rel, unsigned long flags)
+{
+ pthread_priority_t cls;
+ switch (qc) {
+ case QOS_CLASS_USER_INTERACTIVE: cls = __PTHREAD_PRIORITY_CBIT_USER_INTERACTIVE; break;
+ case QOS_CLASS_USER_INITIATED: cls = __PTHREAD_PRIORITY_CBIT_USER_INITIATED; break;
+ case QOS_CLASS_DEFAULT: cls = __PTHREAD_PRIORITY_CBIT_DEFAULT; break;
+ case QOS_CLASS_UTILITY: cls = __PTHREAD_PRIORITY_CBIT_UTILITY; break;
+ case QOS_CLASS_BACKGROUND: cls = __PTHREAD_PRIORITY_CBIT_BACKGROUND; break;
+ case QOS_CLASS_UNSPECIFIED:
+ default:
+ cls = __PTHREAD_PRIORITY_CBIT_UNSPECIFIED;
+ rel = 1; // results in priority bits == 0 <rdar://problem/16184900>
+ break;
+ }
+
+ /*
+ * __PTHREAD_PRIORITY_CBIT_MAINTENANCE was defined as the 0th bit by shifting all the
+ * existing bits to the left by one. So for backward compatiblity for kernels that does
+ * not support QOS_CLASS_MAINTENANCE, we have to make it up by shifting the cls bit to
+ * right by one.
+ */
+ cls >>= 1;
+
+ pthread_priority_t p =
+ (flags & _PTHREAD_PRIORITY_FLAGS_MASK) |
+ ((cls << _PTHREAD_PRIORITY_QOS_CLASS_SHIFT) & _PTHREAD_PRIORITY_QOS_CLASS_MASK) |
+ (((uint8_t)rel - 1) & _PTHREAD_PRIORITY_PRIORITY_MASK);
+
+ return p;
+}
+
+/* QOS_CLASS_MAINTENANCE is supported */
+static inline qos_class_t
+_pthread_priority_get_qos_newest(pthread_priority_t priority)
+{
+ qos_class_t qc;
+ switch ((priority & _PTHREAD_PRIORITY_QOS_CLASS_MASK) >> _PTHREAD_PRIORITY_QOS_CLASS_SHIFT) {
+ case __PTHREAD_PRIORITY_CBIT_USER_INTERACTIVE: qc = QOS_CLASS_USER_INTERACTIVE; break;
+ case __PTHREAD_PRIORITY_CBIT_USER_INITIATED: qc = QOS_CLASS_USER_INITIATED; break;
+ case __PTHREAD_PRIORITY_CBIT_DEFAULT: qc = QOS_CLASS_DEFAULT; break;
+ case __PTHREAD_PRIORITY_CBIT_UTILITY: qc = QOS_CLASS_UTILITY; break;
+ case __PTHREAD_PRIORITY_CBIT_BACKGROUND: qc = QOS_CLASS_BACKGROUND; break;
+ case __PTHREAD_PRIORITY_CBIT_MAINTENANCE: qc = QOS_CLASS_MAINTENANCE; break;
+ case __PTHREAD_PRIORITY_CBIT_UNSPECIFIED:
+ default: qc = QOS_CLASS_UNSPECIFIED; break;
+ }
+ return qc;
+}
+
+/* QOS_CLASS_MAINTENANCE is not supported */
+static inline qos_class_t
+_pthread_priority_get_qos_version2(pthread_priority_t priority)
+{
+ qos_class_t qc;
+ pthread_priority_t cls;
+
+ cls = (priority & _PTHREAD_PRIORITY_QOS_CLASS_MASK) >> _PTHREAD_PRIORITY_QOS_CLASS_SHIFT;
+
+ /*
+ * __PTHREAD_PRIORITY_CBIT_MAINTENANCE was defined as the 0th bit by shifting all the
+ * existing bits to the left by one. So for backward compatiblity for kernels that does
+ * not support QOS_CLASS_MAINTENANCE, pthread_priority_make() shifted the cls bit to the
+ * right by one. Therefore we have to shift it back during decoding the priority bit.
+ */
+ cls <<= 1;
+
+ switch (cls) {
+ case __PTHREAD_PRIORITY_CBIT_USER_INTERACTIVE: qc = QOS_CLASS_USER_INTERACTIVE; break;
+ case __PTHREAD_PRIORITY_CBIT_USER_INITIATED: qc = QOS_CLASS_USER_INITIATED; break;
+ case __PTHREAD_PRIORITY_CBIT_DEFAULT: qc = QOS_CLASS_DEFAULT; break;
+ case __PTHREAD_PRIORITY_CBIT_UTILITY: qc = QOS_CLASS_UTILITY; break;
+ case __PTHREAD_PRIORITY_CBIT_BACKGROUND: qc = QOS_CLASS_BACKGROUND; break;
+ case __PTHREAD_PRIORITY_CBIT_UNSPECIFIED:
+ default: qc = QOS_CLASS_UNSPECIFIED; break;
+ }
+ return qc;
+}
+
+#define _pthread_priority_get_relpri(priority) \
+ ((int8_t)((priority & _PTHREAD_PRIORITY_PRIORITY_MASK) >> _PTHREAD_PRIORITY_PRIORITY_SHIFT) + 1)
+
+#define _pthread_priority_get_flags(priority) \
+ (priority & _PTHREAD_PRIORITY_FLAGS_MASK)
+
+#define _pthread_priority_split_newest(priority, qos, relpri) \
+ ({ qos = _pthread_priority_get_qos_newest(priority); \
+ relpri = (qos == QOS_CLASS_UNSPECIFIED) ? 0 : \
+ _pthread_priority_get_relpri(priority); \
+ })
+
+#define _pthread_priority_split_version2(priority, qos, relpri) \
+ ({ qos = _pthread_priority_get_qos_version2(priority); \
+ relpri = (qos == QOS_CLASS_UNSPECIFIED) ? 0 : \
+ _pthread_priority_get_relpri(priority); \
+ })
+
+/* <rdar://problem/15969976> Required for backward compatibility on older kernels. */
+#define _pthread_priority_make_version1(qos, relpri, flags) \
+ (((flags >> 15) & 0xffff0000) | \
+ ((qos << 8) & 0x0000ff00) | \
+ (((uint8_t)relpri - 1) & 0x000000ff))
+
+/* userspace <-> kernel registration struct, for passing data to/from the kext during main thread init. */
+struct _pthread_registration_data {
+ uint64_t version; /* copy-in */
+ uint64_t dispatch_queue_offset; /* copy-in */
+ pthread_priority_t main_qos; /* copy-out */
+};
+
+#ifdef KERNEL
+
+/* The set of features, from the feature bits above, that we support. */
+#define PTHREAD_FEATURE_SUPPORTED ( \
+ PTHREAD_FEATURE_DISPATCHFUNC | \
+ PTHREAD_FEATURE_FINEPRIO | \
+ PTHREAD_FEATURE_BSDTHREADCTL | \
+ PTHREAD_FEATURE_SETSELF | \
+ PTHREAD_FEATURE_QOS_MAINTENANCE | \
+ PTHREAD_FEATURE_QOS_DEFAULT)
+
+extern pthread_callbacks_t pthread_kern;
+
+struct ksyn_waitq_element {
+ TAILQ_ENTRY(ksyn_waitq_element) kwe_list; /* link to other list members */
+ void * kwe_kwqqueue; /* queue blocked on */
+ uint32_t kwe_state; /* state */
+ uint32_t kwe_lockseq; /* the sequence of the entry */
+ uint32_t kwe_count; /* upper bound on number of matches still pending */
+ uint32_t kwe_psynchretval; /* thread retval */
+ void *kwe_uth; /* uthread */
+ uint64_t kwe_tid; /* tid of waiter */
+};
+typedef struct ksyn_waitq_element * ksyn_waitq_element_t;
+
+pthread_priority_t pthread_qos_class_get_priority(int qos);
+int pthread_priority_get_qos_class(pthread_priority_t priority);
+int pthread_priority_get_class_index(pthread_priority_t priority);
+pthread_priority_t pthread_priority_from_class_index(int index);
+
+#define PTH_DEFAULT_STACKSIZE 512*1024
+#define MAX_PTHREAD_SIZE 64*1024
+
+/* exported from the kernel but not present in any headers. */
+extern thread_t port_name_to_thread(mach_port_name_t port_name);
+
+/* function declarations for pthread_kext.c */
+void pthread_init(void);
+void psynch_zoneinit(void);
+void _pth_proc_hashinit(proc_t p);
+void _pth_proc_hashdelete(proc_t p);
+void pth_global_hashinit(void);
+void psynch_wq_cleanup(void*, void*);
+
+void _pthread_init(void);
+int _fill_procworkqueue(proc_t p, struct proc_workqueueinfo * pwqinfo);
+void _workqueue_init_lock(proc_t p);
+void _workqueue_destroy_lock(proc_t p);
+void _workqueue_exit(struct proc *p);
+void _workqueue_mark_exiting(struct proc *p);
+void _workqueue_thread_yielded(void);
+sched_call_t _workqueue_get_sched_callback(void);
+
+int _bsdthread_create(struct proc *p, user_addr_t user_func, user_addr_t user_funcarg, user_addr_t user_stack, user_addr_t user_pthread, uint32_t flags, user_addr_t *retval);
+int _bsdthread_register(struct proc *p, user_addr_t threadstart, user_addr_t wqthread, int pthsize, user_addr_t dummy_value, user_addr_t targetconc_ptr, uint64_t dispatchqueue_offset, int32_t *retval);
+int _bsdthread_terminate(struct proc *p, user_addr_t stackaddr, size_t size, uint32_t kthport, uint32_t sem, int32_t *retval);
+int _bsdthread_ctl_set_qos(struct proc *p, user_addr_t cmd, mach_port_name_t kport, user_addr_t tsd_priority_addr, user_addr_t arg3, int *retval);
+int _bsdthread_ctl_set_self(struct proc *p, user_addr_t cmd, pthread_priority_t priority, mach_port_name_t voucher, _pthread_set_flags_t flags, int *retval);
+int _bsdthread_ctl_qos_override_start(struct proc *p, user_addr_t cmd, mach_port_name_t kport, pthread_priority_t priority, user_addr_t arg3, int *retval);
+int _bsdthread_ctl_qos_override_end(struct proc *p, user_addr_t cmd, mach_port_name_t kport, user_addr_t arg2, user_addr_t arg3, int *retval);
+int _bsdthread_ctl_qos_override_dispatch(struct proc __unused *p, user_addr_t __unused cmd, mach_port_name_t kport, pthread_priority_t priority, user_addr_t arg3, int __unused *retval);
+int _bsdthread_ctl_qos_override_reset(struct proc __unused *p, user_addr_t __unused cmd, user_addr_t arg1, user_addr_t arg2, user_addr_t arg3, int __unused *retval);
+int _bsdthread_ctl(struct proc *p, user_addr_t cmd, user_addr_t arg1, user_addr_t arg2, user_addr_t arg3, int *retval);
+int _thread_selfid(__unused struct proc *p, uint64_t *retval);
+int _workq_kernreturn(struct proc *p, int options, user_addr_t item, int arg2, int arg3, int32_t *retval);
+int _workq_open(struct proc *p, int32_t *retval);
+
+int _psynch_mutexwait(proc_t p, user_addr_t mutex, uint32_t mgen, uint32_t ugen, uint64_t tid, uint32_t flags, uint32_t * retval);
+int _psynch_mutexdrop(proc_t p, user_addr_t mutex, uint32_t mgen, uint32_t ugen, uint64_t tid, uint32_t flags, uint32_t * retval);
+int _psynch_cvbroad(proc_t p, user_addr_t cv, uint64_t cvlsgen, uint64_t cvudgen, uint32_t flags, user_addr_t mutex, uint64_t mugen, uint64_t tid, uint32_t *retval);
+int _psynch_cvsignal(proc_t p, user_addr_t cv, uint64_t cvlsgen, uint32_t cvugen, int thread_port, user_addr_t mutex, uint64_t mugen, uint64_t tid, uint32_t flags, uint32_t * retval);
+int _psynch_cvwait(proc_t p, user_addr_t cv, uint64_t cvlsgen, uint32_t cvugen, user_addr_t mutex, uint64_t mugen, uint32_t flags, int64_t sec, uint32_t nsec, uint32_t * retval);
+int _psynch_cvclrprepost(proc_t p, user_addr_t cv, uint32_t cvgen, uint32_t cvugen, uint32_t cvsgen, uint32_t prepocnt, uint32_t preposeq, uint32_t flags, int *retval);
+int _psynch_rw_longrdlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t * retval);
+int _psynch_rw_rdlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t *retval);
+int _psynch_rw_unlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t *retval);
+int _psynch_rw_wrlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t *retval);
+int _psynch_rw_yieldwrlock(proc_t p, user_addr_t rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags, uint32_t *retval);
+
+extern lck_grp_attr_t *pthread_lck_grp_attr;
+extern lck_grp_t *pthread_lck_grp;
+extern lck_attr_t *pthread_lck_attr;
+extern lck_mtx_t *pthread_list_mlock;
+extern thread_call_t psynch_thcall;
+
+struct uthread* current_uthread(void);
+
+#endif // KERNEL
+
+#endif /* _SYS_PTHREAD_INTERNAL_H_ */
+
--- /dev/null
+/*
+ * Copyright (c) 2013 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@
+ */
+
+#include "kern_internal.h"
+#include <kern/debug.h>
+
+pthread_priority_t
+pthread_qos_class_get_priority(int qos)
+{
+ /* Map the buckets we have in pthread_priority_t into a QoS tier. */
+ switch (qos) {
+ case THREAD_QOS_USER_INTERACTIVE: return _pthread_priority_make_newest(QOS_CLASS_USER_INTERACTIVE, 0, 0);
+ case THREAD_QOS_USER_INITIATED: return _pthread_priority_make_newest(QOS_CLASS_USER_INITIATED, 0, 0);
+ case THREAD_QOS_LEGACY: return _pthread_priority_make_newest(QOS_CLASS_DEFAULT, 0, 0);
+ case THREAD_QOS_UTILITY: return _pthread_priority_make_newest(QOS_CLASS_UTILITY, 0, 0);
+ case THREAD_QOS_BACKGROUND: return _pthread_priority_make_newest(QOS_CLASS_BACKGROUND, 0, 0);
+ case THREAD_QOS_MAINTENANCE: return _pthread_priority_make_newest(QOS_CLASS_MAINTENANCE, 0, 0);
+ default: return _pthread_priority_make_newest(QOS_CLASS_UNSPECIFIED, 0, 0);
+ }
+}
+
+int
+pthread_priority_get_qos_class(pthread_priority_t priority)
+{
+ /* Map the buckets we have in pthread_priority_t into a QoS tier. */
+ switch (_pthread_priority_get_qos_newest(priority)) {
+ case QOS_CLASS_USER_INTERACTIVE: return THREAD_QOS_USER_INTERACTIVE;
+ case QOS_CLASS_USER_INITIATED: return THREAD_QOS_USER_INITIATED;
+ case QOS_CLASS_DEFAULT: return THREAD_QOS_LEGACY;
+ case QOS_CLASS_UTILITY: return THREAD_QOS_UTILITY;
+ case QOS_CLASS_BACKGROUND: return THREAD_QOS_BACKGROUND;
+ case QOS_CLASS_MAINTENANCE: return THREAD_QOS_MAINTENANCE;
+ default: return THREAD_QOS_UNSPECIFIED;
+ }
+}
+
+pthread_priority_t
+pthread_priority_from_class_index(int index)
+{
+ qos_class_t qos;
+ switch (index) {
+ case 0: qos = QOS_CLASS_USER_INTERACTIVE; break;
+ case 1: qos = QOS_CLASS_USER_INITIATED; break;
+ case 2: qos = QOS_CLASS_DEFAULT; break;
+ case 3: qos = QOS_CLASS_UTILITY; break;
+ case 4: qos = QOS_CLASS_BACKGROUND; break;
+ case 5: qos = QOS_CLASS_MAINTENANCE; break;
+ default:
+ /* Return the utility band if we don't understand the input. */
+ qos = QOS_CLASS_UTILITY;
+ }
+
+ pthread_priority_t priority;
+ priority = _pthread_priority_make_newest(qos, 0, 0);
+
+ return priority;
+}
+
+int
+pthread_priority_get_class_index(pthread_priority_t priority)
+{
+ switch (_pthread_priority_get_qos_newest(priority)) {
+ case QOS_CLASS_USER_INTERACTIVE: return 0;
+ case QOS_CLASS_USER_INITIATED: return 1;
+ case QOS_CLASS_DEFAULT: return 2;
+ case QOS_CLASS_UTILITY: return 3;
+ case QOS_CLASS_BACKGROUND: return 4;
+ case QOS_CLASS_MAINTENANCE: return 5;
+ default:
+ /* Return the utility band if we don't understand the input. */
+ return 2;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2000-2012 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@
+ */
+/* Copyright (c) 1995-2005 Apple Computer, Inc. All Rights Reserved */
+/*
+ * pthread_synch.c
+ */
+
+#define _PTHREAD_CONDATTR_T
+#define _PTHREAD_COND_T
+#define _PTHREAD_MUTEXATTR_T
+#define _PTHREAD_MUTEX_T
+#define _PTHREAD_RWLOCKATTR_T
+#define _PTHREAD_RWLOCK_T
+
+#undef pthread_mutexattr_t
+#undef pthread_mutex_t
+#undef pthread_condattr_t
+#undef pthread_cond_t
+#undef pthread_rwlockattr_t
+#undef pthread_rwlock_t
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/resourcevar.h>
+//#include <sys/proc_internal.h>
+#include <sys/kauth.h>
+#include <sys/systm.h>
+#include <sys/timeb.h>
+#include <sys/times.h>
+#include <sys/acct.h>
+#include <sys/kernel.h>
+#include <sys/wait.h>
+#include <sys/signalvar.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/stat.h>
+#include <sys/lock.h>
+#include <sys/kdebug.h>
+//#include <sys/sysproto.h>
+#include <sys/vm.h>
+#include <sys/user.h> /* for coredump */
+#include <sys/proc_info.h> /* for fill_procworkqueue */
+
+
+#include <mach/mach_port.h>
+#include <mach/mach_types.h>
+#include <mach/semaphore.h>
+#include <mach/sync_policy.h>
+#include <mach/task.h>
+#include <mach/vm_prot.h>
+#include <kern/kern_types.h>
+#include <kern/task.h>
+#include <kern/clock.h>
+#include <mach/kern_return.h>
+#include <kern/thread.h>
+#include <kern/sched_prim.h>
+#include <kern/kalloc.h>
+#include <kern/sched_prim.h> /* for thread_exception_return */
+#include <kern/processor.h>
+#include <kern/assert.h>
+#include <mach/mach_vm.h>
+#include <mach/mach_param.h>
+#include <mach/thread_status.h>
+#include <mach/thread_policy.h>
+#include <mach/message.h>
+#include <mach/port.h>
+//#include <vm/vm_protos.h>
+#include <vm/vm_fault.h>
+#include <vm/vm_map.h>
+#include <mach/thread_act.h> /* for thread_resume */
+#include <machine/machine_routines.h>
+
+#include <libkern/OSAtomic.h>
+
+#include <sys/pthread_shims.h>
+#include "kern_internal.h"
+
+uint32_t pthread_debug_tracing = 0;
+
+SYSCTL_INT(_kern, OID_AUTO, pthread_debug_tracing, CTLFLAG_RW | CTLFLAG_LOCKED,
+ &pthread_debug_tracing, 0, "")
+
+// XXX: Dirty import for sys/signarvar.h that's wrapped in BSD_KERNEL_PRIVATE
+#define sigcantmask (sigmask(SIGKILL) | sigmask(SIGSTOP))
+
+lck_grp_attr_t *pthread_lck_grp_attr;
+lck_grp_t *pthread_lck_grp;
+lck_attr_t *pthread_lck_attr;
+
+extern void thread_set_cthreadself(thread_t thread, uint64_t pself, int isLP64);
+extern void workqueue_thread_yielded(void);
+
+static boolean_t workqueue_run_nextreq(proc_t p, struct workqueue *wq, thread_t th, boolean_t force_oc,
+ boolean_t overcommit, pthread_priority_t oc_prio);
+
+static boolean_t workqueue_run_one(proc_t p, struct workqueue *wq, boolean_t overcommit, pthread_priority_t priority);
+
+static void wq_runreq(proc_t p, boolean_t overcommit, pthread_priority_t priority, thread_t th, struct threadlist *tl,
+ int reuse_thread, int wake_thread, int return_directly);
+
+static int _setup_wqthread(proc_t p, thread_t th, boolean_t overcommit, pthread_priority_t priority, int reuse_thread, struct threadlist *tl);
+
+static void wq_unpark_continue(void);
+static void wq_unsuspend_continue(void);
+
+static boolean_t workqueue_addnewthread(struct workqueue *wq, boolean_t oc_thread);
+static void workqueue_removethread(struct threadlist *tl, int fromexit);
+static void workqueue_lock_spin(proc_t);
+static void workqueue_unlock(proc_t);
+
+int proc_settargetconc(pid_t pid, int queuenum, int32_t targetconc);
+int proc_setalltargetconc(pid_t pid, int32_t * targetconcp);
+
+#define WQ_MAXPRI_MIN 0 /* low prio queue num */
+#define WQ_MAXPRI_MAX 2 /* max prio queuenum */
+#define WQ_PRI_NUM 3 /* number of prio work queues */
+
+#define C_32_STK_ALIGN 16
+#define C_64_STK_ALIGN 16
+#define C_64_REDZONE_LEN 128
+#define TRUNC_DOWN32(a,c) ((((uint32_t)a)-(c)) & ((uint32_t)(-(c))))
+#define TRUNC_DOWN64(a,c) ((((uint64_t)a)-(c)) & ((uint64_t)(-(c))))
+
+/*
+ * Flags filed passed to bsdthread_create and back in pthread_start
+31 <---------------------------------> 0
+_________________________________________
+| flags(8) | policy(8) | importance(16) |
+-----------------------------------------
+*/
+
+#define PTHREAD_START_CUSTOM 0x01000000
+#define PTHREAD_START_SETSCHED 0x02000000
+#define PTHREAD_START_DETACHED 0x04000000
+#define PTHREAD_START_QOSCLASS 0x08000000
+#define PTHREAD_START_QOSCLASS_MASK 0xffffff
+#define PTHREAD_START_POLICY_BITSHIFT 16
+#define PTHREAD_START_POLICY_MASK 0xff
+#define PTHREAD_START_IMPORTANCE_MASK 0xffff
+
+#define SCHED_OTHER POLICY_TIMESHARE
+#define SCHED_FIFO POLICY_FIFO
+#define SCHED_RR POLICY_RR
+
+int
+_bsdthread_create(struct proc *p, user_addr_t user_func, user_addr_t user_funcarg, user_addr_t user_stack, user_addr_t user_pthread, uint32_t flags, user_addr_t *retval)
+{
+ kern_return_t kret;
+ void * sright;
+ int error = 0;
+ int allocated = 0;
+ mach_vm_offset_t stackaddr;
+ mach_vm_size_t th_allocsize = 0;
+ mach_vm_size_t user_stacksize;
+ mach_vm_size_t th_stacksize;
+ mach_vm_size_t th_guardsize;
+ mach_vm_offset_t th_stackaddr;
+ mach_vm_offset_t th_stack;
+ mach_vm_offset_t th_pthread;
+ mach_port_name_t th_thport;
+ thread_t th;
+ vm_map_t vmap = pthread_kern->current_map();
+ task_t ctask = current_task();
+ unsigned int policy, importance;
+
+ int isLP64 = 0;
+
+ if (pthread_kern->proc_get_register(p) == 0) {
+ return EINVAL;
+ }
+
+ PTHREAD_TRACE(TRACE_pthread_thread_create | DBG_FUNC_START, flags, 0, 0, 0, 0);
+
+ isLP64 = proc_is64bit(p);
+ th_guardsize = vm_map_page_size(vmap);
+
+#if defined(__i386__) || defined(__x86_64__)
+ stackaddr = 0xB0000000;
+#else
+#error Need to define a stack address hint for this architecture
+#endif
+ kret = pthread_kern->thread_create(ctask, &th);
+ if (kret != KERN_SUCCESS)
+ return(ENOMEM);
+ thread_reference(th);
+
+ sright = (void *)pthread_kern->convert_thread_to_port(th);
+ th_thport = pthread_kern->ipc_port_copyout_send(sright, pthread_kern->task_get_ipcspace(ctask));
+
+ if ((flags & PTHREAD_START_CUSTOM) == 0) {
+ th_stacksize = (mach_vm_size_t)user_stack; /* if it is custom them it is stacksize */
+ th_allocsize = th_stacksize + th_guardsize + pthread_kern->proc_get_pthsize(p);
+
+ kret = mach_vm_map(vmap, &stackaddr,
+ th_allocsize,
+ page_size-1,
+ VM_MAKE_TAG(VM_MEMORY_STACK)| VM_FLAGS_ANYWHERE , NULL,
+ 0, FALSE, VM_PROT_DEFAULT, VM_PROT_ALL,
+ VM_INHERIT_DEFAULT);
+ if (kret != KERN_SUCCESS)
+ kret = mach_vm_allocate(vmap,
+ &stackaddr, th_allocsize,
+ VM_MAKE_TAG(VM_MEMORY_STACK)| VM_FLAGS_ANYWHERE);
+ if (kret != KERN_SUCCESS) {
+ error = ENOMEM;
+ goto out;
+ }
+
+ PTHREAD_TRACE(TRACE_pthread_thread_create|DBG_FUNC_NONE, th_allocsize, stackaddr, 0, 2, 0);
+
+ th_stackaddr = stackaddr;
+ allocated = 1;
+ /*
+ * The guard page is at the lowest address
+ * The stack base is the highest address
+ */
+ kret = mach_vm_protect(vmap, stackaddr, th_guardsize, FALSE, VM_PROT_NONE);
+
+ if (kret != KERN_SUCCESS) {
+ error = ENOMEM;
+ goto out1;
+ }
+ th_stack = (stackaddr + th_stacksize + th_guardsize);
+ th_pthread = (stackaddr + th_stacksize + th_guardsize);
+ user_stacksize = th_stacksize;
+
+ /*
+ * Pre-fault the first page of the new thread's stack and the page that will
+ * contain the pthread_t structure.
+ */
+ vm_fault( vmap,
+ vm_map_trunc_page_mask(th_stack - PAGE_SIZE_64, vm_map_page_mask(vmap)),
+ VM_PROT_READ | VM_PROT_WRITE,
+ FALSE,
+ THREAD_UNINT, NULL, 0);
+
+ vm_fault( vmap,
+ vm_map_trunc_page_mask(th_pthread, vm_map_page_mask(vmap)),
+ VM_PROT_READ | VM_PROT_WRITE,
+ FALSE,
+ THREAD_UNINT, NULL, 0);
+ } else {
+ th_stack = user_stack;
+ user_stacksize = user_stack;
+ th_pthread = user_pthread;
+
+ PTHREAD_TRACE(TRACE_pthread_thread_create|DBG_FUNC_NONE, 0, 0, 0, 3, 0);
+ }
+
+#if defined(__i386__) || defined(__x86_64__)
+ /*
+ * Set up i386 registers & function call.
+ */
+ if (isLP64 == 0) {
+ x86_thread_state32_t state;
+ x86_thread_state32_t *ts = &state;
+
+ ts->eip = (unsigned int)pthread_kern->proc_get_threadstart(p);
+ ts->eax = (unsigned int)th_pthread;
+ ts->ebx = (unsigned int)th_thport;
+ ts->ecx = (unsigned int)user_func;
+ ts->edx = (unsigned int)user_funcarg;
+ ts->edi = (unsigned int)user_stacksize;
+ ts->esi = (unsigned int)flags;
+ /*
+ * set stack pointer
+ */
+ ts->esp = (int)((vm_offset_t)(th_stack-C_32_STK_ALIGN));
+
+ error = pthread_kern->thread_set_wq_state32(th, (thread_state_t)ts);
+ if (error != KERN_SUCCESS) {
+ error = EINVAL;
+ goto out;
+ }
+ } else {
+ x86_thread_state64_t state64;
+ x86_thread_state64_t *ts64 = &state64;
+
+ ts64->rip = (uint64_t)pthread_kern->proc_get_threadstart(p);
+ ts64->rdi = (uint64_t)th_pthread;
+ ts64->rsi = (uint64_t)(th_thport);
+ ts64->rdx = (uint64_t)user_func;
+ ts64->rcx = (uint64_t)user_funcarg;
+ ts64->r8 = (uint64_t)user_stacksize;
+ ts64->r9 = (uint64_t)flags;
+ /*
+ * set stack pointer aligned to 16 byte boundary
+ */
+ ts64->rsp = (uint64_t)(th_stack - C_64_REDZONE_LEN);
+
+ error = pthread_kern->thread_set_wq_state64(th, (thread_state_t)ts64);
+ if (error != KERN_SUCCESS) {
+ error = EINVAL;
+ goto out;
+ }
+
+ }
+#elif defined(__arm__)
+ arm_thread_state_t state;
+ arm_thread_state_t *ts = &state;
+
+ ts->pc = (int)pthread_kern->proc_get_threadstart(p);
+ ts->r[0] = (unsigned int)th_pthread;
+ ts->r[1] = (unsigned int)th_thport;
+ ts->r[2] = (unsigned int)user_func;
+ ts->r[3] = (unsigned int)user_funcarg;
+ ts->r[4] = (unsigned int)user_stacksize;
+ ts->r[5] = (unsigned int)flags;
+
+ /* Set r7 & lr to 0 for better back tracing */
+ ts->r[7] = 0;
+ ts->lr = 0;
+
+ /*
+ * set stack pointer
+ */
+ ts->sp = (int)((vm_offset_t)(th_stack-C_32_STK_ALIGN));
+
+ (void) pthread_kern->thread_set_wq_state32(th, (thread_state_t)ts);
+
+#else
+#error bsdthread_create not defined for this architecture
+#endif
+
+ if ((flags & PTHREAD_START_SETSCHED) != 0) {
+ /* Set scheduling parameters if needed */
+ thread_extended_policy_data_t extinfo;
+ thread_precedence_policy_data_t precedinfo;
+
+ importance = (flags & PTHREAD_START_IMPORTANCE_MASK);
+ policy = (flags >> PTHREAD_START_POLICY_BITSHIFT) & PTHREAD_START_POLICY_MASK;
+
+ if (policy == SCHED_OTHER) {
+ extinfo.timeshare = 1;
+ } else {
+ extinfo.timeshare = 0;
+ }
+
+ thread_policy_set(th, THREAD_EXTENDED_POLICY, (thread_policy_t)&extinfo, THREAD_EXTENDED_POLICY_COUNT);
+
+#define BASEPRI_DEFAULT 31
+ precedinfo.importance = (importance - BASEPRI_DEFAULT);
+ thread_policy_set(th, THREAD_PRECEDENCE_POLICY, (thread_policy_t)&precedinfo, THREAD_PRECEDENCE_POLICY_COUNT);
+ } else if ((flags & PTHREAD_START_QOSCLASS) != 0) {
+ /* Set thread QoS class if requested. */
+ pthread_priority_t priority = (pthread_priority_t)(flags & PTHREAD_START_QOSCLASS_MASK);
+
+ thread_qos_policy_data_t qos;
+ qos.qos_tier = pthread_priority_get_qos_class(priority);
+ qos.tier_importance = (qos.qos_tier == QOS_CLASS_UNSPECIFIED) ? 0 :
+ _pthread_priority_get_relpri(priority);
+
+ pthread_kern->thread_policy_set_internal(th, THREAD_QOS_POLICY, (thread_policy_t)&qos, THREAD_QOS_POLICY_COUNT);
+ }
+
+ kret = pthread_kern->thread_resume(th);
+ if (kret != KERN_SUCCESS) {
+ error = EINVAL;
+ goto out1;
+ }
+ thread_deallocate(th); /* drop the creator reference */
+
+ PTHREAD_TRACE(TRACE_pthread_thread_create|DBG_FUNC_END, error, th_pthread, 0, 0, 0);
+
+ *retval = th_pthread;
+
+ return(0);
+
+out1:
+ if (allocated != 0) {
+ (void)mach_vm_deallocate(vmap, stackaddr, th_allocsize);
+ }
+out:
+ (void)pthread_kern->mach_port_deallocate(pthread_kern->task_get_ipcspace(ctask), th_thport);
+ (void)thread_terminate(th);
+ (void)thread_deallocate(th);
+ return(error);
+}
+
+int
+_bsdthread_terminate(__unused struct proc *p,
+ user_addr_t stackaddr,
+ size_t size,
+ uint32_t kthport,
+ uint32_t sem,
+ __unused int32_t *retval)
+{
+ mach_vm_offset_t freeaddr;
+ mach_vm_size_t freesize;
+ kern_return_t kret;
+
+ freeaddr = (mach_vm_offset_t)stackaddr;
+ freesize = size;
+
+ PTHREAD_TRACE(TRACE_pthread_thread_terminate|DBG_FUNC_START, freeaddr, freesize, kthport, 0xff, 0);
+
+ if ((freesize != (mach_vm_size_t)0) && (freeaddr != (mach_vm_offset_t)0)) {
+ kret = mach_vm_deallocate(pthread_kern->current_map(), freeaddr, freesize);
+ if (kret != KERN_SUCCESS) {
+ PTHREAD_TRACE(TRACE_pthread_thread_terminate|DBG_FUNC_END, kret, 0, 0, 0, 0);
+ return(EINVAL);
+ }
+ }
+
+ (void) thread_terminate(current_thread());
+ if (sem != MACH_PORT_NULL) {
+ kret = pthread_kern->semaphore_signal_internal_trap(sem);
+ if (kret != KERN_SUCCESS) {
+ PTHREAD_TRACE(TRACE_pthread_thread_terminate|DBG_FUNC_END, kret, 0, 0, 0, 0);
+ return(EINVAL);
+ }
+ }
+
+ if (kthport != MACH_PORT_NULL) {
+ pthread_kern->mach_port_deallocate(pthread_kern->task_get_ipcspace(current_task()), kthport);
+ }
+
+ PTHREAD_TRACE(TRACE_pthread_thread_terminate|DBG_FUNC_END, 0, 0, 0, 0, 0);
+
+ pthread_kern->thread_exception_return();
+ panic("bsdthread_terminate: still running\n");
+
+ PTHREAD_TRACE(TRACE_pthread_thread_terminate|DBG_FUNC_END, 0, 0xff, 0, 0, 0);
+
+ return(0);
+}
+
+int
+_bsdthread_register(struct proc *p,
+ user_addr_t threadstart,
+ user_addr_t wqthread,
+ int pthsize,
+ user_addr_t pthread_init_data,
+ user_addr_t targetconc_ptr,
+ uint64_t dispatchqueue_offset,
+ int32_t *retval)
+{
+ /* prevent multiple registrations */
+ if (pthread_kern->proc_get_register(p) != 0) {
+ return(EINVAL);
+ }
+ /* syscall randomizer test can pass bogus values */
+ if (pthsize < 0 || pthsize > MAX_PTHREAD_SIZE) {
+ return(EINVAL);
+ }
+ pthread_kern->proc_set_threadstart(p, threadstart);
+ pthread_kern->proc_set_wqthread(p, wqthread);
+ pthread_kern->proc_set_pthsize(p, pthsize);
+ pthread_kern->proc_set_register(p);
+
+ /* if we have pthread_init_data, then we use that and target_concptr (which is an offset) get data. */
+ if (pthread_init_data != 0) {
+ thread_qos_policy_data_t qos;
+
+ struct _pthread_registration_data data;
+ size_t pthread_init_sz = MIN(sizeof(struct _pthread_registration_data), (size_t)targetconc_ptr);
+
+ kern_return_t kr = copyin(pthread_init_data, &data, pthread_init_sz);
+ if (kr != KERN_SUCCESS) {
+ return EINVAL;
+ }
+
+ /* Incoming data from the data structure */
+ pthread_kern->proc_set_dispatchqueue_offset(p, data.dispatch_queue_offset);
+
+ /* Outgoing data that userspace expects as a reply */
+ if (pthread_kern->qos_main_thread_active()) {
+ mach_msg_type_number_t nqos = THREAD_QOS_POLICY_COUNT;
+ boolean_t gd = FALSE;
+
+ kr = pthread_kern->thread_policy_get(current_thread(), THREAD_QOS_POLICY, (thread_policy_t)&qos, &nqos, &gd);
+ if (kr != KERN_SUCCESS || qos.qos_tier == THREAD_QOS_UNSPECIFIED) {
+ /* Unspecified threads means the kernel wants us to impose legacy upon the thread. */
+ qos.qos_tier = THREAD_QOS_LEGACY;
+ qos.tier_importance = 0;
+
+ kr = pthread_kern->thread_policy_set_internal(current_thread(), THREAD_QOS_POLICY, (thread_policy_t)&qos, THREAD_QOS_POLICY_COUNT);
+ }
+
+ if (kr == KERN_SUCCESS) {
+ data.main_qos = pthread_qos_class_get_priority(qos.qos_tier);
+ } else {
+ data.main_qos = _pthread_priority_make_newest(QOS_CLASS_UNSPECIFIED, 0, 0);
+ }
+ } else {
+ data.main_qos = _pthread_priority_make_newest(QOS_CLASS_UNSPECIFIED, 0, 0);
+ }
+
+ kr = copyout(&data, pthread_init_data, pthread_init_sz);
+ if (kr != KERN_SUCCESS) {
+ return EINVAL;
+ }
+ } else {
+ pthread_kern->proc_set_dispatchqueue_offset(p, dispatchqueue_offset);
+ pthread_kern->proc_set_targconc(p, targetconc_ptr);
+ }
+
+ /* return the supported feature set as the return value. */
+ *retval = PTHREAD_FEATURE_SUPPORTED;
+
+ return(0);
+}
+
+int
+_bsdthread_ctl_set_qos(struct proc *p, user_addr_t __unused cmd, mach_port_name_t kport, user_addr_t tsd_priority_addr, user_addr_t arg3, int *retval)
+{
+ kern_return_t kr;
+ thread_t th;
+
+ pthread_priority_t priority;
+
+ /* Unused parameters must be zero. */
+ if (arg3 != 0) {
+ return EINVAL;
+ }
+
+ /* QoS is stored in a given slot in the pthread TSD. We need to copy that in and set our QoS based on it. */
+ if (proc_is64bit(p)) {
+ uint64_t v;
+ kr = copyin(tsd_priority_addr, &v, sizeof(v));
+ if (kr != KERN_SUCCESS) {
+ return kr;
+ }
+ priority = (int)(v & 0xffffffff);
+ } else {
+ uint32_t v;
+ kr = copyin(tsd_priority_addr, &v, sizeof(v));
+ if (kr != KERN_SUCCESS) {
+ return kr;
+ }
+ priority = v;
+ }
+
+ if ((th = port_name_to_thread(kport)) == THREAD_NULL) {
+ return ESRCH;
+ }
+
+ /* <rdar://problem/16211829> Disable pthread_set_qos_class_np() on threads other than pthread_self */
+ if (th != current_thread()) {
+ thread_deallocate(th);
+ return EPERM;
+ }
+
+ int rv = _bsdthread_ctl_set_self(p, 0, priority, 0, _PTHREAD_SET_SELF_QOS_FLAG, retval);
+
+ /* Static param the thread, we just set QoS on it, so its stuck in QoS land now. */
+ /* pthread_kern->thread_static_param(th, TRUE); */ // see <rdar://problem/16433744>, for details
+
+ thread_deallocate(th);
+
+ return rv;
+}
+
+static inline struct threadlist *
+util_get_thread_threadlist_entry(thread_t th)
+{
+ struct uthread *uth = pthread_kern->get_bsdthread_info(th);
+ if (uth) {
+ struct threadlist *tl = pthread_kern->uthread_get_threadlist(uth);
+ return tl;
+ }
+ return NULL;
+}
+
+static inline void
+wq_thread_override_reset(thread_t th)
+{
+ struct uthread *uth = pthread_kern->get_bsdthread_info(th);
+ struct threadlist *tl = pthread_kern->uthread_get_threadlist(uth);
+
+ if (tl) {
+ /*
+ * Drop all outstanding overrides on this thread, done outside the wq lock
+ * because proc_usynch_thread_qos_remove_override takes a spinlock that
+ * could cause us to panic.
+ */
+ uint32_t count = tl->th_dispatch_override_count;
+ while (!OSCompareAndSwap(count, 0, &tl->th_dispatch_override_count)) {
+ count = tl->th_dispatch_override_count;
+ }
+
+ PTHREAD_TRACE(TRACE_wq_override_reset | DBG_FUNC_NONE, tl->th_workq, count, 0, 0, 0);
+
+ for (int i=count; i>0; i--) {
+ pthread_kern->proc_usynch_thread_qos_remove_override(uth, 0);
+ }
+ }
+}
+
+int
+_bsdthread_ctl_set_self(struct proc *p, user_addr_t __unused cmd, pthread_priority_t priority, mach_port_name_t voucher, _pthread_set_flags_t flags, int __unused *retval)
+{
+ thread_qos_policy_data_t qos;
+ mach_msg_type_number_t nqos = THREAD_QOS_POLICY_COUNT;
+ boolean_t gd = FALSE;
+
+ kern_return_t kr;
+ int qos_rv = 0, voucher_rv = 0, fixedpri_rv = 0;
+
+ if ((flags & _PTHREAD_SET_SELF_QOS_FLAG) != 0) {
+ kr = pthread_kern->thread_policy_get(current_thread(), THREAD_QOS_POLICY, (thread_policy_t)&qos, &nqos, &gd);
+ if (kr != KERN_SUCCESS) {
+ qos_rv = EINVAL;
+ goto voucher;
+ }
+
+ /* If we have main-thread QoS then we don't allow a thread to come out of QOS_CLASS_UNSPECIFIED. */
+ if (pthread_kern->qos_main_thread_active() && qos.qos_tier == THREAD_QOS_UNSPECIFIED) {
+ qos_rv = EPERM;
+ goto voucher;
+ }
+
+ /* Get the work queue for tracing, also the threadlist for bucket manipluation. */
+ struct workqueue *wq = NULL;
+ struct threadlist *tl = util_get_thread_threadlist_entry(current_thread());
+ if (tl) {
+ wq = tl->th_workq;
+ }
+
+ PTHREAD_TRACE(TRACE_pthread_set_qos_self | DBG_FUNC_START, wq, qos.qos_tier, qos.tier_importance, 0, 0);
+
+ qos.qos_tier = pthread_priority_get_qos_class(priority);
+ qos.tier_importance = (qos.qos_tier == QOS_CLASS_UNSPECIFIED) ? 0 : _pthread_priority_get_relpri(priority);
+
+ kr = pthread_kern->thread_policy_set_internal(current_thread(), THREAD_QOS_POLICY, (thread_policy_t)&qos, THREAD_QOS_POLICY_COUNT);
+ if (kr != KERN_SUCCESS) {
+ qos_rv = EINVAL;
+ goto voucher;
+ }
+
+ /* If we're a workqueue, the threadlist item priority needs adjusting, along with the bucket we were running in. */
+ if (tl) {
+ workqueue_lock_spin(p);
+
+ /* Fix up counters. */
+ uint8_t old_bucket = tl->th_priority;
+ uint8_t new_bucket = pthread_priority_get_class_index(priority);
+
+ uint32_t old_active = OSAddAtomic(-1, &wq->wq_thactive_count[old_bucket]);
+ OSAddAtomic(1, &wq->wq_thactive_count[new_bucket]);
+
+ wq->wq_thscheduled_count[old_bucket]--;
+ wq->wq_thscheduled_count[new_bucket]++;
+
+ tl->th_priority = new_bucket;
+
+ /* If we were at the ceiling of non-overcommitted threads for a given bucket, we have to
+ * reevaluate whether we should start more work.
+ */
+ if (old_active == wq->wq_reqconc[old_bucket]) {
+ /* workqueue_run_nextreq will drop the workqueue lock in all exit paths. */
+ (void)workqueue_run_nextreq(p, wq, THREAD_NULL, FALSE, FALSE, 0);
+ } else {
+ workqueue_unlock(p);
+ }
+ }
+
+ PTHREAD_TRACE(TRACE_pthread_set_qos_self | DBG_FUNC_END, wq, qos.qos_tier, qos.tier_importance, 0, 0);
+ }
+
+voucher:
+ if ((flags & _PTHREAD_SET_SELF_VOUCHER_FLAG) != 0) {
+ kr = pthread_kern->thread_set_voucher_name(voucher);
+ if (kr != KERN_SUCCESS) {
+ voucher_rv = ENOENT;
+ goto fixedpri;
+ }
+ }
+
+fixedpri:
+ if ((flags & _PTHREAD_SET_SELF_FIXEDPRIORITY_FLAG) != 0) {
+ thread_extended_policy_data_t extpol;
+ thread_t thread = current_thread();
+
+ extpol.timeshare = 0;
+
+ struct threadlist *tl = util_get_thread_threadlist_entry(thread);
+ if (tl) {
+ /* Not allowed on workqueue threads, since there is no symmetric clear function */
+ fixedpri_rv = ENOTSUP;
+ goto done;
+ }
+
+ kr = pthread_kern->thread_policy_set_internal(thread, THREAD_EXTENDED_POLICY, (thread_policy_t)&extpol, THREAD_EXTENDED_POLICY_COUNT);
+ if (kr != KERN_SUCCESS) {
+ fixedpri_rv = EINVAL;
+ goto done;
+ }
+ }
+
+done:
+ if (qos_rv && voucher_rv) {
+ /* Both failed, give that a unique error. */
+ return EBADMSG;
+ }
+
+ if (qos_rv) {
+ return qos_rv;
+ }
+
+ if (voucher_rv) {
+ return voucher_rv;
+ }
+
+ if (fixedpri_rv) {
+ return fixedpri_rv;
+ }
+
+ return 0;
+}
+
+int
+_bsdthread_ctl_qos_override_start(struct proc __unused *p, user_addr_t __unused cmd, mach_port_name_t kport, pthread_priority_t priority, user_addr_t arg3, int __unused *retval)
+{
+ thread_t th;
+ int rv = 0;
+
+ if (arg3 != 0) {
+ return EINVAL;
+ }
+
+ if ((th = port_name_to_thread(kport)) == THREAD_NULL) {
+ return ESRCH;
+ }
+
+ struct uthread *uth = pthread_kern->get_bsdthread_info(th);
+ int override_qos = pthread_priority_get_qos_class(priority);
+
+ struct threadlist *tl = util_get_thread_threadlist_entry(th);
+ if (tl) {
+ /* Workqueue threads count their overrides, so they can forcibly balance any outstanding
+ * overrides when they return to the kernel.
+ */
+ uint32_t o = OSAddAtomic(1, &tl->th_override_count);
+ PTHREAD_TRACE(TRACE_wq_override_start | DBG_FUNC_NONE, tl->th_workq, thread_tid(th), o+1, priority, 0);
+ }
+
+ /* The only failure case here is if we pass a tid and have it lookup the thread, we pass the uthread, so this all always succeeds. */
+ pthread_kern->proc_usynch_thread_qos_add_override(uth, 0, override_qos, TRUE);
+
+ thread_deallocate(th);
+ return rv;
+}
+
+int
+_bsdthread_ctl_qos_override_end(struct proc __unused *p, user_addr_t __unused cmd, mach_port_name_t kport, user_addr_t arg2, user_addr_t arg3, int __unused *retval)
+{
+ thread_t th;
+ int rv = 0;
+
+ if (arg2 != 0 || arg3 != 0) {
+ return EINVAL;
+ }
+
+ if ((th = port_name_to_thread(kport)) == THREAD_NULL) {
+ return ESRCH;
+ }
+
+ struct uthread *uth = pthread_kern->get_bsdthread_info(th);
+
+ struct threadlist *tl = util_get_thread_threadlist_entry(th);
+ if (tl) {
+ uint32_t o = OSAddAtomic(-1, &tl->th_override_count);
+
+ PTHREAD_TRACE(TRACE_wq_override_end | DBG_FUNC_NONE, tl->th_workq, thread_tid(th), o-1, 0, 0);
+
+ if (o == 0) {
+ /* underflow! */
+ thread_deallocate(th);
+ return EFAULT;
+ }
+ }
+
+ pthread_kern->proc_usynch_thread_qos_remove_override(uth, 0);
+
+ thread_deallocate(th);
+ return rv;
+}
+
+int
+_bsdthread_ctl_qos_override_dispatch(struct proc __unused *p, user_addr_t __unused cmd, mach_port_name_t kport, pthread_priority_t priority, user_addr_t arg3, int __unused *retval)
+{
+ thread_t th;
+ int rv = 0;
+
+ if (arg3 != 0) {
+ return EINVAL;
+ }
+
+ if ((th = port_name_to_thread(kport)) == THREAD_NULL) {
+ return ESRCH;
+ }
+
+ struct uthread *uth = pthread_kern->get_bsdthread_info(th);
+ int override_qos = pthread_priority_get_qos_class(priority);
+
+ struct threadlist *tl = util_get_thread_threadlist_entry(th);
+ if (!tl) {
+ thread_deallocate(th);
+ return EPERM;
+ }
+
+ /* Workqueue threads count their overrides, so they can forcibly balance any outstanding
+ * overrides when they return to the kernel.
+ */
+ uint32_t o = OSAddAtomic(1, &tl->th_dispatch_override_count);
+ PTHREAD_TRACE(TRACE_wq_override_dispatch | DBG_FUNC_NONE, tl->th_workq, thread_tid(th), o+1, priority, 0);
+
+ /* The only failure case here is if we pass a tid and have it lookup the thread, we pass the uthread, so this all always succeeds. */
+ pthread_kern->proc_usynch_thread_qos_add_override(uth, 0, override_qos, TRUE);
+
+ thread_deallocate(th);
+ return rv;
+}
+
+int
+_bsdthread_ctl_qos_override_reset(struct proc __unused *p, user_addr_t __unused cmd, user_addr_t arg1, user_addr_t arg2, user_addr_t arg3, int __unused *retval)
+{
+ thread_t th;
+ struct threadlist *tl;
+ int rv = 0;
+
+ if (arg1 != 0 || arg2 != 0 || arg3 != 0) {
+ return EINVAL;
+ }
+
+ th = current_thread();
+ tl = util_get_thread_threadlist_entry(th);
+
+ if (tl) {
+ wq_thread_override_reset(th);
+ } else {
+ rv = EPERM;
+ }
+
+ return rv;
+}
+
+int
+_bsdthread_ctl(struct proc *p, user_addr_t cmd, user_addr_t arg1, user_addr_t arg2, user_addr_t arg3, int *retval)
+{
+ switch (cmd) {
+ case BSDTHREAD_CTL_SET_QOS:
+ return _bsdthread_ctl_set_qos(p, cmd, (mach_port_name_t)arg1, arg2, arg3, retval);
+ case BSDTHREAD_CTL_QOS_OVERRIDE_START:
+ return _bsdthread_ctl_qos_override_start(p, cmd, (mach_port_name_t)arg1, (pthread_priority_t)arg2, arg3, retval);
+ case BSDTHREAD_CTL_QOS_OVERRIDE_END:
+ return _bsdthread_ctl_qos_override_end(p, cmd, (mach_port_name_t)arg1, arg2, arg3, retval);
+ case BSDTHREAD_CTL_QOS_OVERRIDE_RESET:
+ return _bsdthread_ctl_qos_override_reset(p, cmd, arg1, arg2, arg3, retval);
+ case BSDTHREAD_CTL_QOS_OVERRIDE_DISPATCH:
+ return _bsdthread_ctl_qos_override_dispatch(p, cmd, (mach_port_name_t)arg1, (pthread_priority_t)arg2, arg3, retval);
+ case BSDTHREAD_CTL_SET_SELF:
+ return _bsdthread_ctl_set_self(p, cmd, (pthread_priority_t)arg1, (mach_port_name_t)arg2, (_pthread_set_flags_t)arg3, retval);
+ default:
+ return EINVAL;
+ }
+}
+
+uint32_t wq_yielded_threshold = WQ_YIELDED_THRESHOLD;
+uint32_t wq_yielded_window_usecs = WQ_YIELDED_WINDOW_USECS;
+uint32_t wq_stalled_window_usecs = WQ_STALLED_WINDOW_USECS;
+uint32_t wq_reduce_pool_window_usecs = WQ_REDUCE_POOL_WINDOW_USECS;
+uint32_t wq_max_timer_interval_usecs = WQ_MAX_TIMER_INTERVAL_USECS;
+uint32_t wq_max_threads = WORKQUEUE_MAXTHREADS;
+uint32_t wq_max_constrained_threads = WORKQUEUE_MAXTHREADS / 8;
+
+
+SYSCTL_INT(_kern, OID_AUTO, wq_yielded_threshold, CTLFLAG_RW | CTLFLAG_LOCKED,
+ &wq_yielded_threshold, 0, "");
+
+SYSCTL_INT(_kern, OID_AUTO, wq_yielded_window_usecs, CTLFLAG_RW | CTLFLAG_LOCKED,
+ &wq_yielded_window_usecs, 0, "");
+
+SYSCTL_INT(_kern, OID_AUTO, wq_stalled_window_usecs, CTLFLAG_RW | CTLFLAG_LOCKED,
+ &wq_stalled_window_usecs, 0, "");
+
+SYSCTL_INT(_kern, OID_AUTO, wq_reduce_pool_window_usecs, CTLFLAG_RW | CTLFLAG_LOCKED,
+ &wq_reduce_pool_window_usecs, 0, "");
+
+SYSCTL_INT(_kern, OID_AUTO, wq_max_timer_interval_usecs, CTLFLAG_RW | CTLFLAG_LOCKED,
+ &wq_max_timer_interval_usecs, 0, "");
+
+SYSCTL_INT(_kern, OID_AUTO, wq_max_threads, CTLFLAG_RW | CTLFLAG_LOCKED,
+ &wq_max_threads, 0, "");
+
+SYSCTL_INT(_kern, OID_AUTO, wq_max_constrained_threads, CTLFLAG_RW | CTLFLAG_LOCKED,
+ &wq_max_constrained_threads, 0, "");
+
+
+static uint32_t wq_init_constrained_limit = 1;
+
+
+void
+_workqueue_init_lock(proc_t p)
+{
+ lck_spin_init(pthread_kern->proc_get_wqlockptr(p), pthread_lck_grp, pthread_lck_attr);
+ *(pthread_kern->proc_get_wqinitingptr(p)) = FALSE;
+}
+
+void
+_workqueue_destroy_lock(proc_t p)
+{
+ lck_spin_destroy(pthread_kern->proc_get_wqlockptr(p), pthread_lck_grp);
+}
+
+
+static void
+workqueue_lock_spin(proc_t p)
+{
+ lck_spin_lock(pthread_kern->proc_get_wqlockptr(p));
+}
+
+static void
+workqueue_unlock(proc_t p)
+{
+ lck_spin_unlock(pthread_kern->proc_get_wqlockptr(p));
+}
+
+
+static void
+workqueue_interval_timer_start(struct workqueue *wq)
+{
+ uint64_t deadline;
+
+ if (wq->wq_timer_interval == 0) {
+ wq->wq_timer_interval = wq_stalled_window_usecs;
+
+ } else {
+ wq->wq_timer_interval = wq->wq_timer_interval * 2;
+
+ if (wq->wq_timer_interval > wq_max_timer_interval_usecs) {
+ wq->wq_timer_interval = wq_max_timer_interval_usecs;
+ }
+ }
+ clock_interval_to_deadline(wq->wq_timer_interval, 1000, &deadline);
+
+ thread_call_enter_delayed(wq->wq_atimer_call, deadline);
+
+ PTHREAD_TRACE(TRACE_wq_start_add_timer, wq, wq->wq_reqcount, wq->wq_flags, wq->wq_timer_interval, 0);
+}
+
+
+static boolean_t
+wq_thread_is_busy(uint64_t cur_ts, uint64_t *lastblocked_tsp)
+{
+ clock_sec_t secs;
+ clock_usec_t usecs;
+ uint64_t lastblocked_ts;
+ uint64_t elapsed;
+
+ /*
+ * the timestamp is updated atomically w/o holding the workqueue lock
+ * so we need to do an atomic read of the 64 bits so that we don't see
+ * a mismatched pair of 32 bit reads... we accomplish this in an architecturally
+ * independent fashion by using OSCompareAndSwap64 to write back the
+ * value we grabbed... if it succeeds, then we have a good timestamp to
+ * evaluate... if it fails, we straddled grabbing the timestamp while it
+ * was being updated... treat a failed update as a busy thread since
+ * it implies we are about to see a really fresh timestamp anyway
+ */
+ lastblocked_ts = *lastblocked_tsp;
+
+ if ( !OSCompareAndSwap64((UInt64)lastblocked_ts, (UInt64)lastblocked_ts, lastblocked_tsp))
+ return (TRUE);
+
+ if (lastblocked_ts >= cur_ts) {
+ /*
+ * because the update of the timestamp when a thread blocks isn't
+ * serialized against us looking at it (i.e. we don't hold the workq lock)
+ * it's possible to have a timestamp that matches the current time or
+ * that even looks to be in the future relative to when we grabbed the current
+ * time... just treat this as a busy thread since it must have just blocked.
+ */
+ return (TRUE);
+ }
+ elapsed = cur_ts - lastblocked_ts;
+
+ pthread_kern->absolutetime_to_microtime(elapsed, &secs, &usecs);
+
+ if (secs == 0 && usecs < wq_stalled_window_usecs)
+ return (TRUE);
+ return (FALSE);
+}
+
+
+#define WQ_TIMER_NEEDED(wq, start_timer) do { \
+ int oldflags = wq->wq_flags; \
+ \
+ if ( !(oldflags & (WQ_EXITING | WQ_ATIMER_RUNNING))) { \
+ if (OSCompareAndSwap(oldflags, oldflags | WQ_ATIMER_RUNNING, (UInt32 *)&wq->wq_flags)) \
+ start_timer = TRUE; \
+ } \
+} while (0)
+
+
+
+static void
+workqueue_add_timer(struct workqueue *wq, __unused int param1)
+{
+ proc_t p;
+ boolean_t start_timer = FALSE;
+ boolean_t retval;
+ boolean_t add_thread;
+ uint32_t busycount;
+
+ PTHREAD_TRACE(TRACE_wq_add_timer | DBG_FUNC_START, wq, wq->wq_flags, wq->wq_nthreads, wq->wq_thidlecount, 0);
+
+ p = wq->wq_proc;
+
+ workqueue_lock_spin(p);
+
+ /*
+ * because workqueue_callback now runs w/o taking the workqueue lock
+ * we are unsynchronized w/r to a change in state of the running threads...
+ * to make sure we always evaluate that change, we allow it to start up
+ * a new timer if the current one is actively evalutating the state
+ * however, we do not need more than 2 timers fired up (1 active and 1 pending)
+ * and we certainly do not want 2 active timers evaluating the state
+ * simultaneously... so use WQL_ATIMER_BUSY to serialize the timers...
+ * note that WQL_ATIMER_BUSY is in a different flag word from WQ_ATIMER_RUNNING since
+ * it is always protected by the workq lock... WQ_ATIMER_RUNNING is evaluated
+ * and set atomimcally since the callback function needs to manipulate it
+ * w/o holding the workq lock...
+ *
+ * !WQ_ATIMER_RUNNING && !WQL_ATIMER_BUSY == no pending timer, no active timer
+ * !WQ_ATIMER_RUNNING && WQL_ATIMER_BUSY == no pending timer, 1 active timer
+ * WQ_ATIMER_RUNNING && !WQL_ATIMER_BUSY == 1 pending timer, no active timer
+ * WQ_ATIMER_RUNNING && WQL_ATIMER_BUSY == 1 pending timer, 1 active timer
+ */
+ while (wq->wq_lflags & WQL_ATIMER_BUSY) {
+ wq->wq_lflags |= WQL_ATIMER_WAITING;
+
+ assert_wait((caddr_t)wq, (THREAD_UNINT));
+ workqueue_unlock(p);
+
+ thread_block(THREAD_CONTINUE_NULL);
+
+ workqueue_lock_spin(p);
+ }
+ wq->wq_lflags |= WQL_ATIMER_BUSY;
+
+ /*
+ * the workq lock will protect us from seeing WQ_EXITING change state, but we
+ * still need to update this atomically in case someone else tries to start
+ * the timer just as we're releasing it
+ */
+ while ( !(OSCompareAndSwap(wq->wq_flags, (wq->wq_flags & ~WQ_ATIMER_RUNNING), (UInt32 *)&wq->wq_flags)));
+
+again:
+ retval = TRUE;
+ add_thread = FALSE;
+
+ if ( !(wq->wq_flags & WQ_EXITING)) {
+ /*
+ * check to see if the stall frequency was beyond our tolerance
+ * or we have work on the queue, but haven't scheduled any
+ * new work within our acceptable time interval because
+ * there were no idle threads left to schedule
+ */
+ if (wq->wq_reqcount) {
+ uint32_t priclass;
+ uint32_t thactive_count;
+ uint32_t i;
+ uint64_t curtime;
+
+ for (priclass = 0; priclass < WORKQUEUE_NUM_BUCKETS; priclass++) {
+ if (wq->wq_requests[priclass])
+ break;
+ }
+ assert(priclass < WORKQUEUE_NUM_BUCKETS);
+
+ curtime = mach_absolute_time();
+ busycount = 0;
+ thactive_count = 0;
+
+ /*
+ * check for conditions under which we would not add a thread, either
+ * a) we've got as many running threads as we want in this priority
+ * band and the priority bands above it
+ *
+ * b) check to see if the priority group has blocked threads, if the
+ * last blocked timestamp is old enough, we will have already passed
+ * (a) where we would have stopped if we had enough active threads.
+ */
+ for (i = 0; i <= priclass; i++) {
+
+ thactive_count += wq->wq_thactive_count[i];
+
+ if (wq->wq_thscheduled_count[i]) {
+ if (wq_thread_is_busy(curtime, &wq->wq_lastblocked_ts[i]))
+ busycount++;
+ }
+ }
+ if (thactive_count + busycount < wq->wq_max_concurrency) {
+
+ if (wq->wq_thidlecount == 0) {
+ /*
+ * if we have no idle threads, try to add one
+ */
+ retval = workqueue_addnewthread(wq, FALSE);
+ }
+ add_thread = TRUE;
+ }
+
+ if (wq->wq_reqcount) {
+ /*
+ * as long as we have threads to schedule, and we successfully
+ * scheduled new work, keep trying
+ */
+ while (wq->wq_thidlecount && !(wq->wq_flags & WQ_EXITING)) {
+ /*
+ * workqueue_run_nextreq is responsible for
+ * dropping the workqueue lock in all cases
+ */
+ retval = workqueue_run_nextreq(p, wq, THREAD_NULL, FALSE, FALSE, 0);
+ workqueue_lock_spin(p);
+
+ if (retval == FALSE)
+ break;
+ }
+ if ( !(wq->wq_flags & WQ_EXITING) && wq->wq_reqcount) {
+
+ if (wq->wq_thidlecount == 0 && retval == TRUE && add_thread == TRUE)
+ goto again;
+
+ if (wq->wq_thidlecount == 0 || busycount)
+ WQ_TIMER_NEEDED(wq, start_timer);
+
+ PTHREAD_TRACE(TRACE_wq_add_timer | DBG_FUNC_NONE, wq, wq->wq_reqcount, wq->wq_thidlecount, busycount, 0);
+ }
+ }
+ }
+ }
+ if ( !(wq->wq_flags & WQ_ATIMER_RUNNING))
+ wq->wq_timer_interval = 0;
+
+ wq->wq_lflags &= ~WQL_ATIMER_BUSY;
+
+ if ((wq->wq_flags & WQ_EXITING) || (wq->wq_lflags & WQL_ATIMER_WAITING)) {
+ /*
+ * wakeup the thread hung up in workqueue_exit or workqueue_add_timer waiting for this timer
+ * to finish getting out of the way
+ */
+ wq->wq_lflags &= ~WQL_ATIMER_WAITING;
+ wakeup(wq);
+ }
+
+ PTHREAD_TRACE(TRACE_wq_add_timer | DBG_FUNC_END, wq, start_timer, wq->wq_nthreads, wq->wq_thidlecount, 0);
+
+ workqueue_unlock(p);
+
+ if (start_timer == TRUE)
+ workqueue_interval_timer_start(wq);
+}
+
+
+void
+_workqueue_thread_yielded(void)
+{
+ struct workqueue *wq;
+ proc_t p;
+
+ p = current_proc();
+
+ if ((wq = pthread_kern->proc_get_wqptr(p)) == NULL || wq->wq_reqcount == 0)
+ return;
+
+ workqueue_lock_spin(p);
+
+ if (wq->wq_reqcount) {
+ uint64_t curtime;
+ uint64_t elapsed;
+ clock_sec_t secs;
+ clock_usec_t usecs;
+
+ if (wq->wq_thread_yielded_count++ == 0)
+ wq->wq_thread_yielded_timestamp = mach_absolute_time();
+
+ if (wq->wq_thread_yielded_count < wq_yielded_threshold) {
+ workqueue_unlock(p);
+ return;
+ }
+
+ PTHREAD_TRACE(TRACE_wq_thread_yielded | DBG_FUNC_START, wq, wq->wq_thread_yielded_count, wq->wq_reqcount, 0, 0);
+
+ wq->wq_thread_yielded_count = 0;
+
+ curtime = mach_absolute_time();
+ elapsed = curtime - wq->wq_thread_yielded_timestamp;
+ pthread_kern->absolutetime_to_microtime(elapsed, &secs, &usecs);
+
+ if (secs == 0 && usecs < wq_yielded_window_usecs) {
+
+ if (wq->wq_thidlecount == 0) {
+ workqueue_addnewthread(wq, TRUE);
+ /*
+ * 'workqueue_addnewthread' drops the workqueue lock
+ * when creating the new thread and then retakes it before
+ * returning... this window allows other threads to process
+ * requests, so we need to recheck for available work
+ * if none found, we just return... the newly created thread
+ * will eventually get used (if it hasn't already)...
+ */
+ if (wq->wq_reqcount == 0) {
+ workqueue_unlock(p);
+ return;
+ }
+ }
+ if (wq->wq_thidlecount) {
+ uint32_t priority;
+ boolean_t overcommit = FALSE;
+ boolean_t force_oc = FALSE;
+
+ for (priority = 0; priority < WORKQUEUE_NUM_BUCKETS; priority++) {
+ if (wq->wq_requests[priority]) {
+ break;
+ }
+ }
+ assert(priority < WORKQUEUE_NUM_BUCKETS);
+
+ wq->wq_reqcount--;
+ wq->wq_requests[priority]--;
+
+ if (wq->wq_ocrequests[priority]) {
+ wq->wq_ocrequests[priority]--;
+ overcommit = TRUE;
+ } else
+ force_oc = TRUE;
+
+ (void)workqueue_run_nextreq(p, wq, THREAD_NULL, force_oc, overcommit, pthread_priority_from_class_index(priority));
+ /*
+ * workqueue_run_nextreq is responsible for
+ * dropping the workqueue lock in all cases
+ */
+ PTHREAD_TRACE(TRACE_wq_thread_yielded | DBG_FUNC_END, wq, wq->wq_thread_yielded_count, wq->wq_reqcount, 1, 0);
+
+ return;
+ }
+ }
+ PTHREAD_TRACE(TRACE_wq_thread_yielded | DBG_FUNC_END, wq, wq->wq_thread_yielded_count, wq->wq_reqcount, 2, 0);
+ }
+ workqueue_unlock(p);
+}
+
+
+
+static void
+workqueue_callback(int type, thread_t thread)
+{
+ struct uthread *uth;
+ struct threadlist *tl;
+ struct workqueue *wq;
+
+ uth = pthread_kern->get_bsdthread_info(thread);
+ tl = pthread_kern->uthread_get_threadlist(uth);
+ wq = tl->th_workq;
+
+ switch (type) {
+ case SCHED_CALL_BLOCK: {
+ uint32_t old_activecount;
+ boolean_t start_timer = FALSE;
+
+ old_activecount = OSAddAtomic(-1, &wq->wq_thactive_count[tl->th_priority]);
+
+ if (old_activecount == wq->wq_reqconc[tl->th_priority]) {
+ uint64_t curtime;
+ UInt64 *lastblocked_ptr;
+
+ /*
+ * the number of active threads at this priority
+ * has fallen below the maximum number of concurrent
+ * threads that we're allowed to run
+ */
+ lastblocked_ptr = (UInt64 *)&wq->wq_lastblocked_ts[tl->th_priority];
+ curtime = mach_absolute_time();
+
+ /*
+ * if we collide with another thread trying to update the last_blocked (really unlikely
+ * since another thread would have to get scheduled and then block after we start down
+ * this path), it's not a problem. Either timestamp is adequate, so no need to retry
+ */
+
+ OSCompareAndSwap64(*lastblocked_ptr, (UInt64)curtime, lastblocked_ptr);
+
+ if (wq->wq_reqcount) {
+ /*
+ * we have work to do so start up the timer
+ * if it's not running... we'll let it sort
+ * out whether we really need to start up
+ * another thread
+ */
+ WQ_TIMER_NEEDED(wq, start_timer);
+ }
+
+ if (start_timer == TRUE) {
+ workqueue_interval_timer_start(wq);
+ }
+ }
+ PTHREAD_TRACE1(TRACE_wq_thread_block | DBG_FUNC_START, wq, old_activecount, tl->th_priority, start_timer, thread_tid(thread));
+ break;
+ }
+ case SCHED_CALL_UNBLOCK:
+ /*
+ * we cannot take the workqueue_lock here...
+ * an UNBLOCK can occur from a timer event which
+ * is run from an interrupt context... if the workqueue_lock
+ * is already held by this processor, we'll deadlock...
+ * the thread lock for the thread being UNBLOCKED
+ * is also held
+ */
+ OSAddAtomic(1, &wq->wq_thactive_count[tl->th_priority]);
+
+ PTHREAD_TRACE1(TRACE_wq_thread_block | DBG_FUNC_END, wq, wq->wq_threads_scheduled, tl->th_priority, 0, thread_tid(thread));
+
+ break;
+ }
+}
+
+sched_call_t
+_workqueue_get_sched_callback(void)
+{
+ return workqueue_callback;
+}
+
+static void
+workqueue_removethread(struct threadlist *tl, int fromexit)
+{
+ struct workqueue *wq;
+ struct uthread * uth;
+
+ /*
+ * If fromexit is set, the call is from workqueue_exit(,
+ * so some cleanups are to be avoided.
+ */
+ wq = tl->th_workq;
+
+ TAILQ_REMOVE(&wq->wq_thidlelist, tl, th_entry);
+
+ if (fromexit == 0) {
+ wq->wq_nthreads--;
+ wq->wq_thidlecount--;
+ }
+
+ /*
+ * Clear the threadlist pointer in uthread so
+ * blocked thread on wakeup for termination will
+ * not access the thread list as it is going to be
+ * freed.
+ */
+ pthread_kern->thread_sched_call(tl->th_thread, NULL);
+
+ uth = pthread_kern->get_bsdthread_info(tl->th_thread);
+ if (uth != (struct uthread *)0) {
+ pthread_kern->uthread_set_threadlist(uth, NULL);
+ }
+ if (fromexit == 0) {
+ /* during exit the lock is not held */
+ workqueue_unlock(wq->wq_proc);
+ }
+
+ if ( (tl->th_flags & TH_LIST_SUSPENDED) ) {
+ /*
+ * thread was created, but never used...
+ * need to clean up the stack and port ourselves
+ * since we're not going to spin up through the
+ * normal exit path triggered from Libc
+ */
+ if (fromexit == 0) {
+ /* vm map is already deallocated when this is called from exit */
+ (void)mach_vm_deallocate(wq->wq_map, tl->th_stackaddr, tl->th_allocsize);
+ }
+ (void)pthread_kern->mach_port_deallocate(pthread_kern->task_get_ipcspace(wq->wq_task), tl->th_thport);
+
+ PTHREAD_TRACE1(TRACE_wq_thread_suspend | DBG_FUNC_END, wq, (uintptr_t)thread_tid(current_thread()), wq->wq_nthreads, 0xdead, thread_tid(tl->th_thread));
+ } else {
+
+ PTHREAD_TRACE1(TRACE_wq_thread_park | DBG_FUNC_END, wq, (uintptr_t)thread_tid(current_thread()), wq->wq_nthreads, 0xdead, thread_tid(tl->th_thread));
+ }
+ /*
+ * drop our ref on the thread
+ */
+ thread_deallocate(tl->th_thread);
+
+ kfree(tl, sizeof(struct threadlist));
+}
+
+
+/*
+ * called with workq lock held
+ * dropped and retaken around thread creation
+ * return with workq lock held
+ */
+static boolean_t
+workqueue_addnewthread(struct workqueue *wq, boolean_t oc_thread)
+{
+ struct threadlist *tl;
+ struct uthread *uth;
+ kern_return_t kret;
+ thread_t th;
+ proc_t p;
+ void *sright;
+ mach_vm_offset_t stackaddr;
+ mach_vm_size_t guardsize;
+
+ if ((wq->wq_flags & WQ_EXITING) == WQ_EXITING)
+ return (FALSE);
+
+ if (wq->wq_nthreads >= wq_max_threads || wq->wq_nthreads >= (pthread_kern->config_thread_max - 20)) {
+ wq->wq_lflags |= WQL_EXCEEDED_TOTAL_THREAD_LIMIT;
+ return (FALSE);
+ }
+ wq->wq_lflags &= ~WQL_EXCEEDED_TOTAL_THREAD_LIMIT;
+
+ if (oc_thread == FALSE && wq->wq_constrained_threads_scheduled >= wq_max_constrained_threads) {
+ /*
+ * if we're not creating this thread to service an overcommit request,
+ * then check the size of the constrained thread pool... if we've already
+ * reached our max for threads scheduled from this pool, don't create a new
+ * one... the callers of this function are prepared for failure.
+ */
+ wq->wq_lflags |= WQL_EXCEEDED_CONSTRAINED_THREAD_LIMIT;
+ return (FALSE);
+ }
+ if (wq->wq_constrained_threads_scheduled < wq_max_constrained_threads)
+ wq->wq_lflags &= ~WQL_EXCEEDED_CONSTRAINED_THREAD_LIMIT;
+
+ wq->wq_nthreads++;
+
+ p = wq->wq_proc;
+ workqueue_unlock(p);
+
+ kret = pthread_kern->thread_create_workq(wq->wq_task, (thread_continue_t)wq_unsuspend_continue, &th);
+ if (kret != KERN_SUCCESS) {
+ goto failed;
+ }
+
+ tl = kalloc(sizeof(struct threadlist));
+ bzero(tl, sizeof(struct threadlist));
+
+#if defined(__i386__) || defined(__x86_64__)
+ stackaddr = 0xB0000000;
+#else
+#error Need to define a stack address hint for this architecture
+#endif
+
+ guardsize = vm_map_page_size(wq->wq_map);
+ tl->th_allocsize = PTH_DEFAULT_STACKSIZE + guardsize + pthread_kern->proc_get_pthsize(p);
+
+ kret = mach_vm_map(wq->wq_map, &stackaddr,
+ tl->th_allocsize,
+ page_size-1,
+ VM_MAKE_TAG(VM_MEMORY_STACK)| VM_FLAGS_ANYWHERE , NULL,
+ 0, FALSE, VM_PROT_DEFAULT, VM_PROT_ALL,
+ VM_INHERIT_DEFAULT);
+
+ if (kret != KERN_SUCCESS) {
+ kret = mach_vm_allocate(wq->wq_map,
+ &stackaddr, tl->th_allocsize,
+ VM_MAKE_TAG(VM_MEMORY_STACK) | VM_FLAGS_ANYWHERE);
+ }
+ if (kret == KERN_SUCCESS) {
+ /*
+ * The guard page is at the lowest address
+ * The stack base is the highest address
+ */
+ kret = mach_vm_protect(wq->wq_map, stackaddr, guardsize, FALSE, VM_PROT_NONE);
+
+ if (kret != KERN_SUCCESS)
+ (void) mach_vm_deallocate(wq->wq_map, stackaddr, tl->th_allocsize);
+ }
+ if (kret != KERN_SUCCESS) {
+ (void) thread_terminate(th);
+ thread_deallocate(th);
+
+ kfree(tl, sizeof(struct threadlist));
+ goto failed;
+ }
+ thread_reference(th);
+
+ sright = (void *)pthread_kern->convert_thread_to_port(th);
+ tl->th_thport = pthread_kern->ipc_port_copyout_send(sright, pthread_kern->task_get_ipcspace(wq->wq_task));
+
+ pthread_kern->thread_static_param(th, TRUE);
+
+ tl->th_flags = TH_LIST_INITED | TH_LIST_SUSPENDED;
+
+ tl->th_thread = th;
+ tl->th_workq = wq;
+ tl->th_stackaddr = stackaddr;
+ tl->th_priority = WORKQUEUE_NUM_BUCKETS;
+ tl->th_policy = -1;
+
+ uth = pthread_kern->get_bsdthread_info(tl->th_thread);
+
+ workqueue_lock_spin(p);
+
+ pthread_kern->uthread_set_threadlist(uth, tl);
+ TAILQ_INSERT_TAIL(&wq->wq_thidlelist, tl, th_entry);
+
+ wq->wq_thidlecount++;
+
+ PTHREAD_TRACE1(TRACE_wq_thread_suspend | DBG_FUNC_START, wq, wq->wq_nthreads, 0, thread_tid(current_thread()), thread_tid(tl->th_thread));
+
+ return (TRUE);
+
+failed:
+ workqueue_lock_spin(p);
+ wq->wq_nthreads--;
+
+ return (FALSE);
+}
+
+
+int
+_workq_open(struct proc *p, __unused int32_t *retval)
+{
+ struct workqueue * wq;
+ int wq_size;
+ char * ptr;
+ uint32_t i;
+ uint32_t num_cpus;
+ int error = 0;
+ boolean_t need_wakeup = FALSE;
+
+ if (pthread_kern->proc_get_register(p) == 0) {
+ return EINVAL;
+ }
+
+ num_cpus = pthread_kern->ml_get_max_cpus();
+
+ if (wq_init_constrained_limit) {
+ uint32_t limit;
+ /*
+ * set up the limit for the constrained pool
+ * this is a virtual pool in that we don't
+ * maintain it on a separate idle and run list
+ */
+ limit = num_cpus * WORKQUEUE_CONSTRAINED_FACTOR;
+
+ if (limit > wq_max_constrained_threads)
+ wq_max_constrained_threads = limit;
+
+ wq_init_constrained_limit = 0;
+ }
+ workqueue_lock_spin(p);
+
+ if (pthread_kern->proc_get_wqptr(p) == NULL) {
+
+ while (*pthread_kern->proc_get_wqinitingptr(p) == TRUE) {
+
+ assert_wait((caddr_t)pthread_kern->proc_get_wqinitingptr(p), THREAD_UNINT);
+ workqueue_unlock(p);
+
+ thread_block(THREAD_CONTINUE_NULL);
+
+ workqueue_lock_spin(p);
+ }
+ if (pthread_kern->proc_get_wqptr(p) != NULL) {
+ goto out;
+ }
+
+ *(pthread_kern->proc_get_wqinitingptr(p)) = TRUE;
+
+ workqueue_unlock(p);
+
+ wq_size = sizeof(struct workqueue);
+
+ ptr = (char *)kalloc(wq_size);
+ bzero(ptr, wq_size);
+
+ wq = (struct workqueue *)ptr;
+ wq->wq_flags = WQ_LIST_INITED;
+ wq->wq_proc = p;
+ wq->wq_max_concurrency = num_cpus;
+ wq->wq_task = current_task();
+ wq->wq_map = pthread_kern->current_map();
+
+ for (i = 0; i < WORKQUEUE_NUM_BUCKETS; i++)
+ wq->wq_reqconc[i] = (uint16_t)wq->wq_max_concurrency;
+
+ TAILQ_INIT(&wq->wq_thrunlist);
+ TAILQ_INIT(&wq->wq_thidlelist);
+
+ wq->wq_atimer_call = thread_call_allocate((thread_call_func_t)workqueue_add_timer, (thread_call_param_t)wq);
+
+ workqueue_lock_spin(p);
+
+ pthread_kern->proc_set_wqptr(p, wq);
+ pthread_kern->proc_set_wqsize(p, wq_size);
+
+ *(pthread_kern->proc_get_wqinitingptr(p)) = FALSE;
+ need_wakeup = TRUE;
+ }
+out:
+ workqueue_unlock(p);
+
+ if (need_wakeup == TRUE) {
+ wakeup(pthread_kern->proc_get_wqinitingptr(p));
+ }
+ return(error);
+}
+
+
+int
+_workq_kernreturn(struct proc *p,
+ int options,
+ __unused user_addr_t item,
+ int arg2,
+ int arg3,
+ __unused int32_t *retval)
+{
+ struct workqueue *wq;
+ int error = 0;
+
+ if (pthread_kern->proc_get_register(p) == 0) {
+ return EINVAL;
+ }
+
+ switch (options) {
+ case WQOPS_QUEUE_NEWSPISUPP: {
+ /*
+ * arg2 = offset of serialno into dispatch queue
+ */
+ int offset = arg2;
+
+ pthread_kern->proc_set_dispatchqueue_serialno_offset(p, (uint64_t)offset);
+ break;
+ }
+ case WQOPS_QUEUE_REQTHREADS: {
+ /*
+ * arg2 = number of threads to start
+ * arg3 = priority
+ */
+ boolean_t overcommit = FALSE;
+ int reqcount = arg2;
+ pthread_priority_t priority = arg3;
+ int class;
+
+ overcommit = (_pthread_priority_get_flags(priority) & _PTHREAD_PRIORITY_OVERCOMMIT_FLAG) != 0;
+ class = pthread_priority_get_class_index(priority);
+
+ if ((reqcount <= 0) || (class < 0) || (class >= WORKQUEUE_NUM_BUCKETS)) {
+ error = EINVAL;
+ break;
+ }
+
+ workqueue_lock_spin(p);
+
+ if ((wq = (struct workqueue *)pthread_kern->proc_get_wqptr(p)) == NULL) {
+ workqueue_unlock(p);
+
+ error = EINVAL;
+ break;
+ }
+
+ if (!overcommit) {
+ wq->wq_reqcount += reqcount;
+ wq->wq_requests[class] += reqcount;
+
+ PTHREAD_TRACE(TRACE_wq_req_threads | DBG_FUNC_NONE, wq, priority, wq->wq_requests[class], reqcount, 0);
+
+ while (wq->wq_reqcount) {
+ if (!workqueue_run_one(p, wq, overcommit, priority))
+ break;
+ }
+ } else {
+ PTHREAD_TRACE(TRACE_wq_req_octhreads | DBG_FUNC_NONE, wq, priority, wq->wq_requests[class], reqcount, 0);
+
+ while (reqcount) {
+ if (!workqueue_run_one(p, wq, overcommit, priority))
+ break;
+ reqcount--;
+ }
+ if (reqcount) {
+ /*
+ * we need to delay starting some of the overcommit requests...
+ * we should only fail to create the overcommit threads if
+ * we're at the max thread limit... as existing threads
+ * return to the kernel, we'll notice the ocrequests
+ * and spin them back to user space as the overcommit variety
+ */
+ wq->wq_reqcount += reqcount;
+ wq->wq_requests[class] += reqcount;
+ wq->wq_ocrequests[class] += reqcount;
+
+ PTHREAD_TRACE(TRACE_wq_delay_octhreads | DBG_FUNC_NONE, wq, priority, wq->wq_requests[class], reqcount, 0);
+ }
+ }
+ workqueue_unlock(p);
+ break;
+ }
+
+ case WQOPS_THREAD_RETURN: {
+ thread_t th = current_thread();
+ struct uthread *uth = pthread_kern->get_bsdthread_info(th);
+ struct threadlist *tl = util_get_thread_threadlist_entry(th);
+
+ /* reset signal mask on the workqueue thread to default state */
+ if (pthread_kern->uthread_get_sigmask(uth) != (sigset_t)(~workq_threadmask)) {
+ pthread_kern->proc_lock(p);
+ pthread_kern->uthread_set_sigmask(uth, ~workq_threadmask);
+ pthread_kern->proc_unlock(p);
+ }
+
+ /* dropping WQ override counts has to be done outside the wq lock. */
+ wq_thread_override_reset(th);
+
+ workqueue_lock_spin(p);
+
+ if ((wq = (struct workqueue *)pthread_kern->proc_get_wqptr(p)) == NULL || !tl) {
+ workqueue_unlock(p);
+
+ error = EINVAL;
+ break;
+ }
+ PTHREAD_TRACE(TRACE_wq_runitem | DBG_FUNC_END, wq, 0, 0, 0, 0);
+
+
+ (void)workqueue_run_nextreq(p, wq, th, FALSE, FALSE, 0);
+ /*
+ * workqueue_run_nextreq is responsible for
+ * dropping the workqueue lock in all cases
+ */
+ break;
+ }
+
+ default:
+ error = EINVAL;
+ break;
+ }
+ return (error);
+}
+
+/*
+ * Routine: workqueue_mark_exiting
+ *
+ * Function: Mark the work queue such that new threads will not be added to the
+ * work queue after we return.
+ *
+ * Conditions: Called against the current process.
+ */
+void
+_workqueue_mark_exiting(struct proc *p)
+{
+ struct workqueue *wq = pthread_kern->proc_get_wqptr(p);
+
+ if (wq != NULL) {
+
+ PTHREAD_TRACE(TRACE_wq_pthread_exit|DBG_FUNC_START, wq, 0, 0, 0, 0);
+
+ workqueue_lock_spin(p);
+
+ /*
+ * we now arm the timer in the callback function w/o holding the workq lock...
+ * we do this by setting WQ_ATIMER_RUNNING via OSCompareAndSwap in order to
+ * insure only a single timer if running and to notice that WQ_EXITING has
+ * been set (we don't want to start a timer once WQ_EXITING is posted)
+ *
+ * so once we have successfully set WQ_EXITING, we cannot fire up a new timer...
+ * therefor no need to clear the timer state atomically from the flags
+ *
+ * since we always hold the workq lock when dropping WQ_ATIMER_RUNNING
+ * the check for and sleep until clear is protected
+ */
+ while (!(OSCompareAndSwap(wq->wq_flags, (wq->wq_flags | WQ_EXITING), (UInt32 *)&wq->wq_flags)));
+
+ if (wq->wq_flags & WQ_ATIMER_RUNNING) {
+ if (thread_call_cancel(wq->wq_atimer_call) == TRUE) {
+ wq->wq_flags &= ~WQ_ATIMER_RUNNING;
+ }
+ }
+ while ((wq->wq_flags & WQ_ATIMER_RUNNING) || (wq->wq_lflags & WQL_ATIMER_BUSY)) {
+ assert_wait((caddr_t)wq, (THREAD_UNINT));
+ workqueue_unlock(p);
+
+ thread_block(THREAD_CONTINUE_NULL);
+
+ workqueue_lock_spin(p);
+ }
+ workqueue_unlock(p);
+
+ PTHREAD_TRACE(TRACE_wq_pthread_exit|DBG_FUNC_END, 0, 0, 0, 0, 0);
+ }
+}
+
+/*
+ * Routine: workqueue_exit
+ *
+ * Function: clean up the work queue structure(s) now that there are no threads
+ * left running inside the work queue (except possibly current_thread).
+ *
+ * Conditions: Called by the last thread in the process.
+ * Called against current process.
+ */
+void
+_workqueue_exit(struct proc *p)
+{
+ struct workqueue * wq;
+ struct threadlist * tl, *tlist;
+ struct uthread *uth;
+ int wq_size = 0;
+
+ wq = pthread_kern->proc_get_wqptr(p);
+ if (wq != NULL) {
+
+ PTHREAD_TRACE(TRACE_wq_workqueue_exit|DBG_FUNC_START, wq, 0, 0, 0, 0);
+
+ wq_size = pthread_kern->proc_get_wqsize(p);
+ pthread_kern->proc_set_wqptr(p, NULL);
+ pthread_kern->proc_set_wqsize(p, 0);
+
+ /*
+ * Clean up workqueue data structures for threads that exited and
+ * didn't get a chance to clean up after themselves.
+ */
+ TAILQ_FOREACH_SAFE(tl, &wq->wq_thrunlist, th_entry, tlist) {
+ pthread_kern->thread_sched_call(tl->th_thread, NULL);
+
+ uth = pthread_kern->get_bsdthread_info(tl->th_thread);
+ if (uth != (struct uthread *)0) {
+ pthread_kern->uthread_set_threadlist(uth, NULL);
+ }
+ TAILQ_REMOVE(&wq->wq_thrunlist, tl, th_entry);
+
+ /*
+ * drop our last ref on the thread
+ */
+ thread_deallocate(tl->th_thread);
+
+ kfree(tl, sizeof(struct threadlist));
+ }
+ TAILQ_FOREACH_SAFE(tl, &wq->wq_thidlelist, th_entry, tlist) {
+ workqueue_removethread(tl, 1);
+ }
+ thread_call_free(wq->wq_atimer_call);
+
+ kfree(wq, wq_size);
+
+ PTHREAD_TRACE(TRACE_wq_workqueue_exit|DBG_FUNC_END, 0, 0, 0, 0, 0);
+ }
+}
+
+
+static boolean_t
+workqueue_run_one(proc_t p, struct workqueue *wq, boolean_t overcommit, pthread_priority_t priority)
+{
+ boolean_t ran_one;
+
+ if (wq->wq_thidlecount == 0) {
+ if (overcommit == FALSE) {
+ if (wq->wq_constrained_threads_scheduled < wq->wq_max_concurrency)
+ workqueue_addnewthread(wq, overcommit);
+ } else {
+ workqueue_addnewthread(wq, overcommit);
+
+ if (wq->wq_thidlecount == 0)
+ return (FALSE);
+ }
+ }
+ ran_one = workqueue_run_nextreq(p, wq, THREAD_NULL, FALSE, overcommit, priority);
+ /*
+ * workqueue_run_nextreq is responsible for
+ * dropping the workqueue lock in all cases
+ */
+ workqueue_lock_spin(p);
+
+ return (ran_one);
+}
+
+
+
+/*
+ * workqueue_run_nextreq:
+ * called with the workqueue lock held...
+ * responsible for dropping it in all cases
+ */
+static boolean_t
+workqueue_run_nextreq(proc_t p, struct workqueue *wq, thread_t thread,
+ boolean_t force_oc, boolean_t overcommit, pthread_priority_t oc_prio)
+{
+ thread_t th_to_run = THREAD_NULL;
+ thread_t th_to_park = THREAD_NULL;
+ int wake_thread = 0;
+ int reuse_thread = WQ_FLAG_THREAD_REUSE;
+ uint32_t priclass, orig_class;
+ uint32_t us_to_wait;
+ struct threadlist *tl = NULL;
+ struct uthread *uth = NULL;
+ boolean_t start_timer = FALSE;
+ boolean_t adjust_counters = TRUE;
+ uint64_t curtime;
+ uint32_t thactive_count;
+ uint32_t busycount;
+
+ PTHREAD_TRACE(TRACE_wq_run_nextitem|DBG_FUNC_START, wq, thread, wq->wq_thidlecount, wq->wq_reqcount, 0);
+
+ if (thread != THREAD_NULL) {
+ uth = pthread_kern->get_bsdthread_info(thread);
+
+ if ((tl = pthread_kern->uthread_get_threadlist(uth)) == NULL) {
+ panic("wq thread with no threadlist");
+ }
+ }
+
+ /*
+ * from here until we drop the workq lock
+ * we can't be pre-empted since we hold
+ * the lock in spin mode... this is important
+ * since we have to independently update the priority that
+ * the thread is associated with and the priorty based
+ * counters that "workqueue_callback" also changes and bases
+ * decisons on.
+ */
+dispatch_overcommit:
+
+ if (overcommit || force_oc) {
+ priclass = pthread_priority_get_class_index(oc_prio);
+
+ if (thread != THREAD_NULL) {
+ th_to_run = thread;
+ goto pick_up_work;
+ }
+ goto grab_idle_thread;
+ }
+ if (wq->wq_reqcount) {
+ for (priclass = 0; priclass < WORKQUEUE_NUM_BUCKETS; priclass++) {
+ if (wq->wq_requests[priclass])
+ break;
+ }
+ assert(priclass < WORKQUEUE_NUM_BUCKETS);
+
+ if (wq->wq_ocrequests[priclass] && (thread != THREAD_NULL || wq->wq_thidlecount)) {
+ /*
+ * handle delayed overcommit request...
+ * they have priority over normal requests
+ * within a given priority level
+ */
+ wq->wq_reqcount--;
+ wq->wq_requests[priclass]--;
+ wq->wq_ocrequests[priclass]--;
+
+ oc_prio = pthread_priority_from_class_index(priclass);
+ overcommit = TRUE;
+
+ goto dispatch_overcommit;
+ }
+ }
+ /*
+ * if we get here, the work should be handled by a constrained thread
+ */
+ if (wq->wq_reqcount == 0 || wq->wq_constrained_threads_scheduled >= wq_max_constrained_threads) {
+ /*
+ * no work to do, or we're already at or over the scheduling limit for
+ * constrained threads... just return or park the thread...
+ * do not start the timer for this condition... if we don't have any work,
+ * we'll check again when new work arrives... if we're over the limit, we need 1 or more
+ * constrained threads to return to the kernel before we can dispatch additional work
+ */
+ if ((th_to_park = thread) == THREAD_NULL)
+ goto out_of_work;
+ goto parkit;
+ }
+
+ thactive_count = 0;
+ busycount = 0;
+
+ curtime = mach_absolute_time();
+
+ thactive_count += wq->wq_thactive_count[priclass];
+
+ if (wq->wq_thscheduled_count[priclass]) {
+ if (wq_thread_is_busy(curtime, &wq->wq_lastblocked_ts[priclass])) {
+ busycount++;
+ }
+ }
+
+ if (thread != THREAD_NULL) {
+ if (tl->th_priority == priclass) {
+ /*
+ * dont't count this thread as currently active
+ */
+ thactive_count--;
+ }
+ }
+ if (thactive_count + busycount >= wq->wq_max_concurrency) {
+ if (busycount) {
+ /*
+ * we found at least 1 thread in the
+ * 'busy' state... make sure we start
+ * the timer because if they are the only
+ * threads keeping us from scheduling
+ * this work request, we won't get a callback
+ * to kick off the timer... we need to
+ * start it now...
+ */
+ WQ_TIMER_NEEDED(wq, start_timer);
+ }
+
+ PTHREAD_TRACE(TRACE_wq_overcommitted|DBG_FUNC_NONE, wq, (start_timer ? 1<<7 : 0) | pthread_priority_from_class_index(priclass), thactive_count, busycount, 0);
+
+ if ((th_to_park = thread) == THREAD_NULL) {
+ goto out_of_work;
+ }
+
+ goto parkit;
+ }
+
+ if (thread != THREAD_NULL) {
+ /*
+ * thread is non-NULL here when we return from userspace
+ * in workq_kernreturn, rather than trying to find a thread
+ * we pick up new work for this specific thread.
+ */
+ th_to_run = thread;
+ goto pick_up_work;
+ }
+
+grab_idle_thread:
+ if (wq->wq_thidlecount == 0) {
+ /*
+ * we have no additional threads waiting to pick up
+ * work, however, there is additional work to do.
+ */
+ WQ_TIMER_NEEDED(wq, start_timer);
+
+ PTHREAD_TRACE(TRACE_wq_stalled, wq, wq->wq_nthreads, start_timer, 0, 0);
+
+ goto no_thread_to_run;
+ }
+
+ /*
+ * we already know there is both work available
+ * and an idle thread, so activate a thread and then
+ * fall into the code that pulls a new work request...
+ */
+ tl = TAILQ_FIRST(&wq->wq_thidlelist);
+ TAILQ_REMOVE(&wq->wq_thidlelist, tl, th_entry);
+ wq->wq_thidlecount--;
+
+ TAILQ_INSERT_TAIL(&wq->wq_thrunlist, tl, th_entry);
+
+ if ((tl->th_flags & TH_LIST_SUSPENDED) == TH_LIST_SUSPENDED) {
+ tl->th_flags &= ~TH_LIST_SUSPENDED;
+ reuse_thread = 0;
+
+ } else if ((tl->th_flags & TH_LIST_BLOCKED) == TH_LIST_BLOCKED) {
+ tl->th_flags &= ~TH_LIST_BLOCKED;
+ wake_thread = 1;
+ }
+ tl->th_flags |= TH_LIST_RUNNING | TH_LIST_BUSY;
+
+ wq->wq_threads_scheduled++;
+ wq->wq_thscheduled_count[priclass]++;
+ OSAddAtomic(1, &wq->wq_thactive_count[priclass]);
+
+ adjust_counters = FALSE;
+ th_to_run = tl->th_thread;
+
+pick_up_work:
+ if (!overcommit && !force_oc) {
+ wq->wq_reqcount--;
+ wq->wq_requests[priclass]--;
+
+ if ( !(tl->th_flags & TH_LIST_CONSTRAINED)) {
+ wq->wq_constrained_threads_scheduled++;
+ tl->th_flags |= TH_LIST_CONSTRAINED;
+ }
+ } else {
+ if (tl->th_flags & TH_LIST_CONSTRAINED) {
+ wq->wq_constrained_threads_scheduled--;
+ tl->th_flags &= ~TH_LIST_CONSTRAINED;
+ }
+ }
+
+ orig_class = tl->th_priority;
+ tl->th_priority = (uint8_t)priclass;
+
+ if (adjust_counters && (orig_class != priclass)) {
+ /*
+ * we need to adjust these counters based on this
+ * thread's new disposition w/r to priority
+ */
+ OSAddAtomic(-1, &wq->wq_thactive_count[orig_class]);
+ OSAddAtomic(1, &wq->wq_thactive_count[priclass]);
+
+ wq->wq_thscheduled_count[orig_class]--;
+ wq->wq_thscheduled_count[priclass]++;
+ }
+ wq->wq_thread_yielded_count = 0;
+
+ workqueue_unlock(p);
+
+ if (orig_class != priclass) {
+ pthread_priority_t pri = pthread_priority_from_class_index(priclass);
+
+ thread_qos_policy_data_t qosinfo;
+
+ /* Set the QoS tier on the thread, along with the ceiling of max importance for this class. */
+ qosinfo.qos_tier = pthread_priority_get_qos_class(pri);
+ qosinfo.tier_importance = 0;
+
+ PTHREAD_TRACE(TRACE_wq_reset_priority | DBG_FUNC_START, wq, thread_tid(tl->th_thread), pthread_priority_from_class_index(orig_class), 0, 0);
+
+ /* All the previous implementation here now boils down to setting the QoS policy on the thread. */
+ pthread_kern->thread_policy_set_internal(th_to_run, THREAD_QOS_POLICY, (thread_policy_t)&qosinfo, THREAD_QOS_POLICY_COUNT);
+
+ PTHREAD_TRACE(TRACE_wq_reset_priority | DBG_FUNC_END, wq, thread_tid(tl->th_thread), pthread_priority_from_class_index(priclass), qosinfo.qos_tier, 0);
+ }
+
+ /*
+ * if current thread is reused for work request, does not return via unix_syscall
+ */
+ wq_runreq(p, overcommit, pthread_priority_from_class_index(priclass), th_to_run, tl, reuse_thread, wake_thread, (thread == th_to_run));
+
+ PTHREAD_TRACE(TRACE_wq_run_nextitem|DBG_FUNC_END, wq, thread_tid(th_to_run), overcommit, 1, 0);
+
+ return (TRUE);
+
+out_of_work:
+ /*
+ * we have no work to do or we are fully booked
+ * w/r to running threads...
+ */
+no_thread_to_run:
+ workqueue_unlock(p);
+
+ if (start_timer)
+ workqueue_interval_timer_start(wq);
+
+ PTHREAD_TRACE(TRACE_wq_run_nextitem|DBG_FUNC_END, wq, thread_tid(thread), start_timer, 2, 0);
+
+ return (FALSE);
+
+parkit:
+ /*
+ * this is a workqueue thread with no more
+ * work to do... park it for now
+ */
+ TAILQ_REMOVE(&wq->wq_thrunlist, tl, th_entry);
+ tl->th_flags &= ~TH_LIST_RUNNING;
+
+ tl->th_flags |= TH_LIST_BLOCKED;
+ TAILQ_INSERT_HEAD(&wq->wq_thidlelist, tl, th_entry);
+
+ pthread_kern->thread_sched_call(th_to_park, NULL);
+
+ OSAddAtomic(-1, &wq->wq_thactive_count[tl->th_priority]);
+ wq->wq_thscheduled_count[tl->th_priority]--;
+ wq->wq_threads_scheduled--;
+
+ if (tl->th_flags & TH_LIST_CONSTRAINED) {
+ wq->wq_constrained_threads_scheduled--;
+ wq->wq_lflags &= ~WQL_EXCEEDED_CONSTRAINED_THREAD_LIMIT;
+ tl->th_flags &= ~TH_LIST_CONSTRAINED;
+ }
+ if (wq->wq_thidlecount < 100)
+ us_to_wait = wq_reduce_pool_window_usecs - (wq->wq_thidlecount * (wq_reduce_pool_window_usecs / 100));
+ else
+ us_to_wait = wq_reduce_pool_window_usecs / 100;
+
+ wq->wq_thidlecount++;
+ wq->wq_lflags &= ~WQL_EXCEEDED_TOTAL_THREAD_LIMIT;
+
+ assert_wait_timeout_with_leeway((caddr_t)tl, (THREAD_INTERRUPTIBLE),
+ TIMEOUT_URGENCY_SYS_BACKGROUND|TIMEOUT_URGENCY_LEEWAY, us_to_wait,
+ wq_reduce_pool_window_usecs, NSEC_PER_USEC);
+
+ workqueue_unlock(p);
+
+ if (start_timer)
+ workqueue_interval_timer_start(wq);
+
+ PTHREAD_TRACE1(TRACE_wq_thread_park | DBG_FUNC_START, wq, wq->wq_threads_scheduled, wq->wq_thidlecount, us_to_wait, thread_tid(th_to_park));
+ PTHREAD_TRACE(TRACE_wq_run_nextitem | DBG_FUNC_END, wq, thread_tid(thread), 0, 3, 0);
+
+ thread_block((thread_continue_t)wq_unpark_continue);
+ /* NOT REACHED */
+
+ return (FALSE);
+}
+
+
+static void
+wq_unsuspend_continue(void)
+{
+ struct uthread *uth = NULL;
+ thread_t th_to_unsuspend;
+ struct threadlist *tl;
+ proc_t p;
+
+ th_to_unsuspend = current_thread();
+ uth = pthread_kern->get_bsdthread_info(th_to_unsuspend);
+
+ if (uth != NULL && (tl = pthread_kern->uthread_get_threadlist(uth)) != NULL) {
+
+ if ((tl->th_flags & (TH_LIST_RUNNING | TH_LIST_BUSY)) == TH_LIST_RUNNING) {
+ /*
+ * most likely a normal resume of this thread occurred...
+ * it's also possible that the thread was aborted after we
+ * finished setting it up so that it could be dispatched... if
+ * so, thread_bootstrap_return will notice the abort and put
+ * the thread on the path to self-destruction
+ */
+normal_resume_to_user:
+ pthread_kern->thread_sched_call(th_to_unsuspend, workqueue_callback);
+ pthread_kern->thread_bootstrap_return();
+ }
+ /*
+ * if we get here, it's because we've been resumed due to
+ * an abort of this thread (process is crashing)
+ */
+ p = current_proc();
+
+ workqueue_lock_spin(p);
+
+ if (tl->th_flags & TH_LIST_SUSPENDED) {
+ /*
+ * thread has been aborted while still on our idle
+ * queue... remove it from our domain...
+ * workqueue_removethread consumes the lock
+ */
+ workqueue_removethread(tl, 0);
+ pthread_kern->thread_bootstrap_return();
+ }
+ while ((tl->th_flags & TH_LIST_BUSY)) {
+ /*
+ * this thread was aborted after we started making
+ * it runnable, but before we finished dispatching it...
+ * we need to wait for that process to finish,
+ * and we need to ask for a wakeup instead of a
+ * thread_resume since the abort has already resumed us
+ */
+ tl->th_flags |= TH_LIST_NEED_WAKEUP;
+
+ assert_wait((caddr_t)tl, (THREAD_UNINT));
+
+ workqueue_unlock(p);
+ thread_block(THREAD_CONTINUE_NULL);
+ workqueue_lock_spin(p);
+ }
+ workqueue_unlock(p);
+ /*
+ * we have finished setting up the thread's context...
+ * thread_bootstrap_return will take us through the abort path
+ * where the thread will self destruct
+ */
+ goto normal_resume_to_user;
+ }
+ pthread_kern->thread_bootstrap_return();
+}
+
+
+static void
+wq_unpark_continue(void)
+{
+ struct uthread *uth = NULL;
+ struct threadlist *tl;
+ thread_t th_to_unpark;
+ proc_t p;
+
+ th_to_unpark = current_thread();
+ uth = pthread_kern->get_bsdthread_info(th_to_unpark);
+
+ if (uth != NULL) {
+ if ((tl = pthread_kern->uthread_get_threadlist(uth)) != NULL) {
+
+ if ((tl->th_flags & (TH_LIST_RUNNING | TH_LIST_BUSY)) == TH_LIST_RUNNING) {
+ /*
+ * a normal wakeup of this thread occurred... no need
+ * for any synchronization with the timer and wq_runreq
+ */
+normal_return_to_user:
+ pthread_kern->thread_sched_call(th_to_unpark, workqueue_callback);
+
+ PTHREAD_TRACE(0xefffd018 | DBG_FUNC_END, tl->th_workq, 0, 0, 0, 0);
+
+ pthread_kern->thread_exception_return();
+ }
+ p = current_proc();
+
+ workqueue_lock_spin(p);
+
+ if ( !(tl->th_flags & TH_LIST_RUNNING)) {
+ /*
+ * the timer popped us out and we've not
+ * been moved off of the idle list
+ * so we should now self-destruct
+ *
+ * workqueue_removethread consumes the lock
+ */
+ workqueue_removethread(tl, 0);
+ pthread_kern->thread_exception_return();
+ }
+ /*
+ * the timer woke us up, but we have already
+ * started to make this a runnable thread,
+ * but have not yet finished that process...
+ * so wait for the normal wakeup
+ */
+ while ((tl->th_flags & TH_LIST_BUSY)) {
+
+ assert_wait((caddr_t)tl, (THREAD_UNINT));
+
+ workqueue_unlock(p);
+
+ thread_block(THREAD_CONTINUE_NULL);
+
+ workqueue_lock_spin(p);
+ }
+ /*
+ * we have finished setting up the thread's context
+ * now we can return as if we got a normal wakeup
+ */
+ workqueue_unlock(p);
+
+ goto normal_return_to_user;
+ }
+ }
+ pthread_kern->thread_exception_return();
+}
+
+
+
+static void
+wq_runreq(proc_t p, boolean_t overcommit, pthread_priority_t priority, thread_t th, struct threadlist *tl,
+ int reuse_thread, int wake_thread, int return_directly)
+{
+ int ret = 0;
+ boolean_t need_resume = FALSE;
+
+ PTHREAD_TRACE1(TRACE_wq_runitem | DBG_FUNC_START, tl->th_workq, overcommit, priority, thread_tid(current_thread()), thread_tid(th));
+
+ ret = _setup_wqthread(p, th, overcommit, priority, reuse_thread, tl);
+
+ if (ret != 0)
+ panic("setup_wqthread failed %x\n", ret);
+
+ if (return_directly) {
+ PTHREAD_TRACE(TRACE_wq_run_nextitem|DBG_FUNC_END, tl->th_workq, 0, 0, 4, 0);
+
+ pthread_kern->thread_exception_return();
+ panic("wq_runreq: thread_exception_return returned ...\n");
+ }
+ if (wake_thread) {
+ workqueue_lock_spin(p);
+
+ tl->th_flags &= ~TH_LIST_BUSY;
+ wakeup(tl);
+
+ workqueue_unlock(p);
+ } else {
+ PTHREAD_TRACE1(TRACE_wq_thread_suspend | DBG_FUNC_END, tl->th_workq, 0, 0, thread_tid(current_thread()), thread_tid(th));
+
+ workqueue_lock_spin(p);
+
+ if (tl->th_flags & TH_LIST_NEED_WAKEUP) {
+ wakeup(tl);
+ } else {
+ need_resume = TRUE;
+ }
+
+ tl->th_flags &= ~(TH_LIST_BUSY | TH_LIST_NEED_WAKEUP);
+
+ workqueue_unlock(p);
+
+ if (need_resume) {
+ /*
+ * need to do this outside of the workqueue spin lock
+ * since thread_resume locks the thread via a full mutex
+ */
+ pthread_kern->thread_resume(th);
+ }
+ }
+}
+
+
+int
+_setup_wqthread(proc_t p, thread_t th, boolean_t overcommit, pthread_priority_t priority, int reuse_thread, struct threadlist *tl)
+{
+ uint32_t flags = reuse_thread | WQ_FLAG_THREAD_NEWSPI;
+ mach_vm_size_t guardsize = vm_map_page_size(tl->th_workq->wq_map);
+ int error = 0;
+
+ if (overcommit) {
+ flags |= WQ_FLAG_THREAD_OVERCOMMIT;
+ }
+
+ /* Put the QoS class value into the lower bits of the reuse_thread register, this is where
+ * the thread priority used to be stored anyway.
+ */
+ flags |= (_pthread_priority_get_qos_newest(priority) & WQ_FLAG_THREAD_PRIOMASK);
+
+#if defined(__i386__) || defined(__x86_64__)
+ int isLP64 = proc_is64bit(p);
+
+ /*
+ * Set up i386 registers & function call.
+ */
+ if (isLP64 == 0) {
+ x86_thread_state32_t state;
+ x86_thread_state32_t *ts = &state;
+
+ ts->eip = (unsigned int)pthread_kern->proc_get_wqthread(p);
+ ts->eax = (unsigned int)(tl->th_stackaddr + PTH_DEFAULT_STACKSIZE + guardsize);
+ ts->ebx = (unsigned int)tl->th_thport;
+ ts->ecx = (unsigned int)(tl->th_stackaddr + guardsize);
+ ts->edx = (unsigned int)0;
+ ts->edi = (unsigned int)flags;
+ ts->esi = (unsigned int)0;
+ /*
+ * set stack pointer
+ */
+ ts->esp = (int)((vm_offset_t)((tl->th_stackaddr + PTH_DEFAULT_STACKSIZE + guardsize) - C_32_STK_ALIGN));
+
+ (void)pthread_kern->thread_set_wq_state32(th, (thread_state_t)ts);
+
+ } else {
+ x86_thread_state64_t state64;
+ x86_thread_state64_t *ts64 = &state64;
+
+ ts64->rip = (uint64_t)pthread_kern->proc_get_wqthread(p);
+ ts64->rdi = (uint64_t)(tl->th_stackaddr + PTH_DEFAULT_STACKSIZE + guardsize);
+ ts64->rsi = (uint64_t)(tl->th_thport);
+ ts64->rdx = (uint64_t)(tl->th_stackaddr + guardsize);
+ ts64->rcx = (uint64_t)0;
+ ts64->r8 = (uint64_t)flags;
+ ts64->r9 = (uint64_t)0;
+
+ /*
+ * set stack pointer aligned to 16 byte boundary
+ */
+ ts64->rsp = (uint64_t)((tl->th_stackaddr + PTH_DEFAULT_STACKSIZE + guardsize) - C_64_REDZONE_LEN);
+
+ error = pthread_kern->thread_set_wq_state64(th, (thread_state_t)ts64);
+ if (error != KERN_SUCCESS) {
+ error = EINVAL;
+ }
+ }
+#else
+#error setup_wqthread not defined for this architecture
+#endif
+
+ return error;
+}
+
+int
+_fill_procworkqueue(proc_t p, struct proc_workqueueinfo * pwqinfo)
+{
+ struct workqueue * wq;
+ int error = 0;
+ int activecount;
+ uint32_t pri;
+
+ workqueue_lock_spin(p);
+ if ((wq = pthread_kern->proc_get_wqptr(p)) == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+ activecount = 0;
+
+ for (pri = 0; pri < WORKQUEUE_NUM_BUCKETS; pri++) {
+ activecount += wq->wq_thactive_count[pri];
+ }
+ pwqinfo->pwq_nthreads = wq->wq_nthreads;
+ pwqinfo->pwq_runthreads = activecount;
+ pwqinfo->pwq_blockedthreads = wq->wq_threads_scheduled - activecount;
+ pwqinfo->pwq_state = 0;
+
+ if (wq->wq_lflags & WQL_EXCEEDED_CONSTRAINED_THREAD_LIMIT) {
+ pwqinfo->pwq_state |= WQ_EXCEEDED_CONSTRAINED_THREAD_LIMIT;
+ }
+
+ if (wq->wq_lflags & WQL_EXCEEDED_TOTAL_THREAD_LIMIT) {
+ pwqinfo->pwq_state |= WQ_EXCEEDED_TOTAL_THREAD_LIMIT;
+ }
+
+out:
+ workqueue_unlock(p);
+ return(error);
+}
+
+int
+_thread_selfid(__unused struct proc *p, uint64_t *retval)
+{
+ thread_t thread = current_thread();
+ *retval = thread_tid(thread);
+ return KERN_SUCCESS;
+}
+
+void
+_pthread_init(void)
+{
+ pthread_lck_grp_attr = lck_grp_attr_alloc_init();
+ pthread_lck_grp = lck_grp_alloc_init("pthread", pthread_lck_grp_attr);
+
+ /*
+ * allocate the lock attribute for pthread synchronizers
+ */
+ pthread_lck_attr = lck_attr_alloc_init();
+
+ _workqueue_init_lock((proc_t)get_bsdtask_info(kernel_task));
+ pthread_list_mlock = lck_mtx_alloc_init(pthread_lck_grp, pthread_lck_attr);
+
+ pth_global_hashinit();
+ psynch_thcall = thread_call_allocate(psynch_wq_cleanup, NULL);
+ psynch_zoneinit();
+
+ /*
+ * register sysctls
+ */
+ sysctl_register_oid(&sysctl__kern_wq_yielded_threshold);
+ sysctl_register_oid(&sysctl__kern_wq_yielded_window_usecs);
+ sysctl_register_oid(&sysctl__kern_wq_stalled_window_usecs);
+ sysctl_register_oid(&sysctl__kern_wq_reduce_pool_window_usecs);
+ sysctl_register_oid(&sysctl__kern_wq_max_timer_interval_usecs);
+ sysctl_register_oid(&sysctl__kern_wq_max_threads);
+ sysctl_register_oid(&sysctl__kern_wq_max_constrained_threads);
+ sysctl_register_oid(&sysctl__kern_pthread_debug_tracing);
+}
--- /dev/null
+/*
+ * Copyright (c) 2000-2012 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@
+ */
+/* Copyright (c) 1995-2005 Apple Computer, Inc. All Rights Reserved */
+/*
+ * pthread_support.c
+ */
+
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/resourcevar.h>
+//#include <sys/proc_internal.h>
+#include <sys/kauth.h>
+#include <sys/systm.h>
+#include <sys/timeb.h>
+#include <sys/times.h>
+#include <sys/time.h>
+#include <sys/acct.h>
+#include <sys/kernel.h>
+#include <sys/wait.h>
+#include <sys/signalvar.h>
+#include <sys/syslog.h>
+#include <sys/stat.h>
+#include <sys/lock.h>
+#include <sys/kdebug.h>
+//#include <sys/sysproto.h>
+//#include <sys/pthread_internal.h>
+#include <sys/vm.h>
+#include <sys/user.h>
+
+#include <mach/mach_types.h>
+#include <mach/vm_prot.h>
+#include <mach/semaphore.h>
+#include <mach/sync_policy.h>
+#include <mach/task.h>
+#include <kern/kern_types.h>
+#include <kern/task.h>
+#include <kern/clock.h>
+#include <mach/kern_return.h>
+#include <kern/thread.h>
+#include <kern/sched_prim.h>
+#include <kern/thread_call.h>
+#include <kern/kalloc.h>
+#include <kern/zalloc.h>
+#include <kern/sched_prim.h>
+#include <kern/processor.h>
+#include <kern/wait_queue.h>
+//#include <kern/mach_param.h>
+#include <mach/mach_vm.h>
+#include <mach/mach_param.h>
+#include <mach/thread_policy.h>
+#include <mach/message.h>
+#include <mach/port.h>
+//#include <vm/vm_protos.h>
+#include <vm/vm_map.h>
+#include <mach/vm_region.h>
+
+#include <libkern/OSAtomic.h>
+
+#include <pexpert/pexpert.h>
+#include <sys/pthread_shims.h>
+
+#include "kern_internal.h"
+#include "synch_internal.h"
+#include "kern_trace.h"
+
+typedef struct uthread *uthread_t;
+
+//#define __FAILEDUSERTEST__(s) do { panic(s); } while (0)
+#define __FAILEDUSERTEST__(s) do { printf("PSYNCH: pid[%d]: %s\n", proc_pid(current_proc()), s); } while (0)
+
+#define ECVCERORR 256
+#define ECVPERORR 512
+
+lck_mtx_t *pthread_list_mlock;
+
+#define PTH_HASHSIZE 100
+
+static LIST_HEAD(pthhashhead, ksyn_wait_queue) *pth_glob_hashtbl;
+static unsigned long pthhash;
+
+static LIST_HEAD(, ksyn_wait_queue) pth_free_list;
+
+static zone_t kwq_zone; /* zone for allocation of ksyn_queue */
+static zone_t kwe_zone; /* zone for allocation of ksyn_waitq_element */
+
+#define SEQFIT 0
+#define FIRSTFIT 1
+
+struct ksyn_queue {
+ TAILQ_HEAD(ksynq_kwelist_head, ksyn_waitq_element) ksynq_kwelist;
+ uint32_t ksynq_count; /* number of entries in queue */
+ uint32_t ksynq_firstnum; /* lowest seq in queue */
+ uint32_t ksynq_lastnum; /* highest seq in queue */
+};
+typedef struct ksyn_queue *ksyn_queue_t;
+
+enum {
+ KSYN_QUEUE_READ = 0,
+ KSYN_QUEUE_WRITER,
+ KSYN_QUEUE_MAX,
+};
+
+struct ksyn_wait_queue {
+ LIST_ENTRY(ksyn_wait_queue) kw_hash;
+ LIST_ENTRY(ksyn_wait_queue) kw_list;
+ user_addr_t kw_addr;
+ uint64_t kw_owner;
+ uint64_t kw_object; /* object backing in shared mode */
+ uint64_t kw_offset; /* offset inside the object in shared mode */
+ int kw_pflags; /* flags under listlock protection */
+ struct timeval kw_ts; /* timeval need for upkeep before free */
+ int kw_iocount; /* inuse reference */
+ int kw_dropcount; /* current users unlocking... */
+
+ int kw_type; /* queue type like mutex, cvar, etc */
+ uint32_t kw_inqueue; /* num of waiters held */
+ uint32_t kw_fakecount; /* number of error/prepost fakes */
+ uint32_t kw_highseq; /* highest seq in the queue */
+ uint32_t kw_lowseq; /* lowest seq in the queue */
+ uint32_t kw_lword; /* L value from userland */
+ uint32_t kw_uword; /* U world value from userland */
+ uint32_t kw_sword; /* S word value from userland */
+ uint32_t kw_lastunlockseq; /* the last seq that unlocked */
+ /* for CV to be used as the seq kernel has seen so far */
+#define kw_cvkernelseq kw_lastunlockseq
+ uint32_t kw_lastseqword; /* the last seq that unlocked */
+ /* for mutex and cvar we need to track I bit values */
+ uint32_t kw_nextseqword; /* the last seq that unlocked; with num of waiters */
+ uint32_t kw_overlapwatch; /* chance for overlaps */
+ uint32_t kw_pre_rwwc; /* prepost count */
+ uint32_t kw_pre_lockseq; /* prepost target seq */
+ uint32_t kw_pre_sseq; /* prepost target sword, in cvar used for mutexowned */
+ uint32_t kw_pre_intrcount; /* prepost of missed wakeup due to intrs */
+ uint32_t kw_pre_intrseq; /* prepost of missed wakeup limit seq */
+ uint32_t kw_pre_intrretbits; /* return bits value for missed wakeup threads */
+ uint32_t kw_pre_intrtype; /* type of failed wakueps*/
+
+ int kw_kflags;
+ int kw_qos_override; /* QoS of max waiter during contention period */
+ struct ksyn_queue kw_ksynqueues[KSYN_QUEUE_MAX]; /* queues to hold threads */
+ lck_mtx_t kw_lock; /* mutex lock protecting this structure */
+};
+typedef struct ksyn_wait_queue * ksyn_wait_queue_t;
+
+#define TID_ZERO (uint64_t)0
+
+/* bits needed in handling the rwlock unlock */
+#define PTH_RW_TYPE_READ 0x01
+#define PTH_RW_TYPE_WRITE 0x04
+#define PTH_RW_TYPE_MASK 0xff
+#define PTH_RW_TYPE_SHIFT 8
+
+#define PTH_RWSHFT_TYPE_READ 0x0100
+#define PTH_RWSHFT_TYPE_WRITE 0x0400
+#define PTH_RWSHFT_TYPE_MASK 0xff00
+
+/*
+ * Mutex pshared attributes
+ */
+#define PTHREAD_PROCESS_SHARED _PTHREAD_MTX_OPT_PSHARED
+#define PTHREAD_PROCESS_PRIVATE 0x20
+#define PTHREAD_PSHARED_FLAGS_MASK 0x30
+
+/*
+ * Mutex policy attributes
+ */
+#define _PTHREAD_MUTEX_POLICY_NONE 0
+#define _PTHREAD_MUTEX_POLICY_FAIRSHARE 0x040 /* 1 */
+#define _PTHREAD_MUTEX_POLICY_FIRSTFIT 0x080 /* 2 */
+#define _PTHREAD_MUTEX_POLICY_REALTIME 0x0c0 /* 3 */
+#define _PTHREAD_MUTEX_POLICY_ADAPTIVE 0x100 /* 4 */
+#define _PTHREAD_MUTEX_POLICY_PRIPROTECT 0x140 /* 5 */
+#define _PTHREAD_MUTEX_POLICY_PRIINHERIT 0x180 /* 6 */
+#define PTHREAD_POLICY_FLAGS_MASK 0x1c0
+
+/* pflags */
+#define KSYN_WQ_INHASH 2
+#define KSYN_WQ_SHARED 4
+#define KSYN_WQ_WAITING 8 /* threads waiting for this wq to be available */
+#define KSYN_WQ_FLIST 0X10 /* in free list to be freed after a short delay */
+
+/* kflags */
+#define KSYN_KWF_INITCLEARED 1 /* the init status found and preposts cleared */
+#define KSYN_KWF_ZEROEDOUT 2 /* the lword, etc are inited to 0 */
+#define KSYN_KWF_QOS_APPLIED 4 /* QoS override applied to owner */
+
+#define KSYN_CLEANUP_DEADLINE 10
+static int psynch_cleanupset;
+thread_call_t psynch_thcall;
+
+#define KSYN_WQTYPE_INWAIT 0x1000
+#define KSYN_WQTYPE_INDROP 0x2000
+#define KSYN_WQTYPE_MTX 0x01
+#define KSYN_WQTYPE_CVAR 0x02
+#define KSYN_WQTYPE_RWLOCK 0x04
+#define KSYN_WQTYPE_SEMA 0x08
+#define KSYN_WQTYPE_MASK 0xff
+
+#define KSYN_WQTYPE_MUTEXDROP (KSYN_WQTYPE_INDROP | KSYN_WQTYPE_MTX)
+
+#define KW_UNLOCK_PREPOST 0x01
+#define KW_UNLOCK_PREPOST_READLOCK 0x08
+#define KW_UNLOCK_PREPOST_WRLOCK 0x20
+
+static void
+CLEAR_PREPOST_BITS(ksyn_wait_queue_t kwq)
+{
+ kwq->kw_pre_lockseq = 0;
+ kwq->kw_pre_sseq = PTHRW_RWS_INIT;
+ kwq->kw_pre_rwwc = 0;
+}
+
+static void
+CLEAR_INTR_PREPOST_BITS(ksyn_wait_queue_t kwq)
+{
+ kwq->kw_pre_intrcount = 0;
+ kwq->kw_pre_intrseq = 0;
+ kwq->kw_pre_intrretbits = 0;
+ kwq->kw_pre_intrtype = 0;
+}
+
+static void
+CLEAR_REINIT_BITS(ksyn_wait_queue_t kwq)
+{
+ if ((kwq->kw_type & KSYN_WQTYPE_MASK) == KSYN_WQTYPE_CVAR) {
+ if (kwq->kw_inqueue != 0 && kwq->kw_inqueue != kwq->kw_fakecount) {
+ panic("CV:entries in queue durinmg reinit %d:%d\n",kwq->kw_inqueue, kwq->kw_fakecount);
+ }
+ };
+ if ((kwq->kw_type & KSYN_WQTYPE_MASK) == KSYN_WQTYPE_RWLOCK) {
+ kwq->kw_nextseqword = PTHRW_RWS_INIT;
+ kwq->kw_overlapwatch = 0;
+ };
+ CLEAR_PREPOST_BITS(kwq);
+ kwq->kw_lastunlockseq = PTHRW_RWL_INIT;
+ kwq->kw_lastseqword = PTHRW_RWS_INIT;
+ CLEAR_INTR_PREPOST_BITS(kwq);
+ kwq->kw_lword = 0;
+ kwq->kw_uword = 0;
+ kwq->kw_sword = PTHRW_RWS_INIT;
+}
+
+static int ksyn_wq_hash_lookup(user_addr_t uaddr, proc_t p, int flags, ksyn_wait_queue_t *kwq, struct pthhashhead **hashptr, uint64_t *object, uint64_t *offset);
+static int ksyn_wqfind(user_addr_t mutex, uint32_t mgen, uint32_t ugen, uint32_t rw_wc, int flags, int wqtype , ksyn_wait_queue_t *wq);
+static void ksyn_wqrelease(ksyn_wait_queue_t mkwq, int qfreenow, int wqtype);
+static int ksyn_findobj(user_addr_t uaddr, uint64_t *objectp, uint64_t *offsetp);
+
+static int _wait_result_to_errno(wait_result_t result);
+
+static int ksyn_wait(ksyn_wait_queue_t, int, uint32_t, int, uint64_t, thread_continue_t);
+static kern_return_t ksyn_signal(ksyn_wait_queue_t, int, ksyn_waitq_element_t, uint32_t);
+static void ksyn_freeallkwe(ksyn_queue_t kq);
+
+static kern_return_t ksyn_mtxsignal(ksyn_wait_queue_t, ksyn_waitq_element_t kwe, uint32_t);
+static void ksyn_mtx_update_owner_qos_override(ksyn_wait_queue_t, uint64_t tid, boolean_t prepost);
+static void ksyn_mtx_transfer_qos_override(ksyn_wait_queue_t, ksyn_waitq_element_t);
+static void ksyn_mtx_drop_qos_override(ksyn_wait_queue_t);
+
+static int kwq_handle_unlock(ksyn_wait_queue_t, uint32_t mgen, uint32_t rw_wc, uint32_t *updatep, int flags, int *blockp, uint32_t premgen);
+
+static void ksyn_queue_init(ksyn_queue_t kq);
+static int ksyn_queue_insert(ksyn_wait_queue_t kwq, int kqi, ksyn_waitq_element_t kwe, uint32_t mgen, int firstfit);
+static void ksyn_queue_remove_item(ksyn_wait_queue_t kwq, ksyn_queue_t kq, ksyn_waitq_element_t kwe);
+static void ksyn_queue_free_items(ksyn_wait_queue_t kwq, int kqi, uint32_t upto, int all);
+
+static void update_low_high(ksyn_wait_queue_t kwq, uint32_t lockseq);
+static uint32_t find_nextlowseq(ksyn_wait_queue_t kwq);
+static uint32_t find_nexthighseq(ksyn_wait_queue_t kwq);
+static int find_seq_till(ksyn_wait_queue_t kwq, uint32_t upto, uint32_t nwaiters, uint32_t *countp);
+
+static uint32_t ksyn_queue_count_tolowest(ksyn_queue_t kq, uint32_t upto);
+
+static ksyn_waitq_element_t ksyn_queue_find_cvpreposeq(ksyn_queue_t kq, uint32_t cgen);
+static void ksyn_handle_cvbroad(ksyn_wait_queue_t ckwq, uint32_t upto, uint32_t *updatep);
+static void ksyn_cvupdate_fixup(ksyn_wait_queue_t ckwq, uint32_t *updatep);
+static ksyn_waitq_element_t ksyn_queue_find_signalseq(ksyn_wait_queue_t kwq, ksyn_queue_t kq, uint32_t toseq, uint32_t lockseq);
+
+static void psynch_cvcontinue(void *, wait_result_t);
+static void psynch_mtxcontinue(void *, wait_result_t);
+
+static int ksyn_wakeupreaders(ksyn_wait_queue_t kwq, uint32_t limitread, int allreaders, uint32_t updatebits, int *wokenp);
+static int kwq_find_rw_lowest(ksyn_wait_queue_t kwq, int flags, uint32_t premgen, int *type, uint32_t lowest[]);
+static ksyn_waitq_element_t ksyn_queue_find_seq(ksyn_wait_queue_t kwq, ksyn_queue_t kq, uint32_t seq);
+
+static void
+UPDATE_CVKWQ(ksyn_wait_queue_t kwq, uint32_t mgen, uint32_t ugen, uint32_t rw_wc)
+{
+ int sinit = ((rw_wc & PTH_RWS_CV_CBIT) != 0);
+
+ // assert((kwq->kw_type & KSYN_WQTYPE_MASK) == KSYN_WQTYPE_CVAR);
+
+ if ((kwq->kw_kflags & KSYN_KWF_ZEROEDOUT) != 0) {
+ /* the values of L,U and S are cleared out due to L==S in previous transition */
+ kwq->kw_lword = mgen;
+ kwq->kw_uword = ugen;
+ kwq->kw_sword = rw_wc;
+ kwq->kw_kflags &= ~KSYN_KWF_ZEROEDOUT;
+ } else {
+ if (is_seqhigher(mgen, kwq->kw_lword)) {
+ kwq->kw_lword = mgen;
+ }
+ if (is_seqhigher(ugen, kwq->kw_uword)) {
+ kwq->kw_uword = ugen;
+ }
+ if (sinit && is_seqhigher(rw_wc, kwq->kw_sword)) {
+ kwq->kw_sword = rw_wc;
+ }
+ }
+ if (sinit && is_seqlower(kwq->kw_cvkernelseq, rw_wc)) {
+ kwq->kw_cvkernelseq = (rw_wc & PTHRW_COUNT_MASK);
+ }
+}
+
+static void
+pthread_list_lock(void)
+{
+ lck_mtx_lock(pthread_list_mlock);
+}
+
+static void
+pthread_list_unlock(void)
+{
+ lck_mtx_unlock(pthread_list_mlock);
+}
+
+static void
+ksyn_wqlock(ksyn_wait_queue_t kwq)
+{
+
+ lck_mtx_lock(&kwq->kw_lock);
+}
+
+static void
+ksyn_wqunlock(ksyn_wait_queue_t kwq)
+{
+ lck_mtx_unlock(&kwq->kw_lock);
+}
+
+
+/* routine to drop the mutex unlocks , used both for mutexunlock system call and drop during cond wait */
+static uint32_t
+_psynch_mutexdrop_internal(ksyn_wait_queue_t kwq, uint32_t mgen, uint32_t ugen, int flags)
+{
+ kern_return_t ret;
+ uint32_t returnbits = 0;
+ int firstfit = (flags & PTHREAD_POLICY_FLAGS_MASK) == _PTHREAD_MUTEX_POLICY_FIRSTFIT;
+ uint32_t nextgen = (ugen + PTHRW_INC);
+
+ ksyn_wqlock(kwq);
+ kwq->kw_lastunlockseq = (ugen & PTHRW_COUNT_MASK);
+ uint32_t updatebits = (kwq->kw_highseq & PTHRW_COUNT_MASK) | (PTH_RWL_EBIT | PTH_RWL_KBIT);
+
+redrive:
+ if (firstfit) {
+ if (kwq->kw_inqueue == 0) {
+ // not set or the new lock sequence is higher
+ if (kwq->kw_pre_rwwc == 0 || is_seqhigher(mgen, kwq->kw_pre_lockseq)) {
+ kwq->kw_pre_lockseq = (mgen & PTHRW_COUNT_MASK);
+ }
+ kwq->kw_pre_rwwc = 1;
+ ksyn_mtx_drop_qos_override(kwq);
+ kwq->kw_owner = 0;
+ // indicate prepost content in kernel
+ returnbits = mgen | PTH_RWL_PBIT;
+ } else {
+ // signal first waiter
+ ret = ksyn_mtxsignal(kwq, NULL, updatebits);
+ if (ret == KERN_NOT_WAITING) {
+ goto redrive;
+ }
+ }
+ } else {
+ int prepost = 0;
+ if (kwq->kw_inqueue == 0) {
+ // No waiters in the queue.
+ prepost = 1;
+ } else {
+ uint32_t low_writer = (kwq->kw_ksynqueues[KSYN_QUEUE_WRITER].ksynq_firstnum & PTHRW_COUNT_MASK);
+ if (low_writer == nextgen) {
+ /* next seq to be granted found */
+ /* since the grant could be cv, make sure mutex wait is set incase the thread interrupted out */
+ ret = ksyn_mtxsignal(kwq, NULL, updatebits | PTH_RWL_MTX_WAIT);
+ if (ret == KERN_NOT_WAITING) {
+ /* interrupt post */
+ kwq->kw_pre_intrcount = 1;
+ kwq->kw_pre_intrseq = nextgen;
+ kwq->kw_pre_intrretbits = updatebits;
+ kwq->kw_pre_intrtype = PTH_RW_TYPE_WRITE;
+ }
+
+ } else if (is_seqhigher(low_writer, nextgen)) {
+ prepost = 1;
+ } else {
+ //__FAILEDUSERTEST__("psynch_mutexdrop_internal: FS mutex unlock sequence higher than the lowest one is queue\n");
+ ksyn_waitq_element_t kwe;
+ kwe = ksyn_queue_find_seq(kwq, &kwq->kw_ksynqueues[KSYN_QUEUE_WRITER], nextgen);
+ if (kwe != NULL) {
+ /* next seq to be granted found */
+ /* since the grant could be cv, make sure mutex wait is set incase the thread interrupted out */
+ ret = ksyn_mtxsignal(kwq, kwe, updatebits | PTH_RWL_MTX_WAIT);
+ if (ret == KERN_NOT_WAITING) {
+ goto redrive;
+ }
+ } else {
+ prepost = 1;
+ }
+ }
+ }
+ if (prepost) {
+ ksyn_mtx_drop_qos_override(kwq);
+ kwq->kw_owner = 0;
+ if (++kwq->kw_pre_rwwc > 1) {
+ __FAILEDUSERTEST__("_psynch_mutexdrop_internal: multiple preposts\n");
+ } else {
+ kwq->kw_pre_lockseq = (nextgen & PTHRW_COUNT_MASK);
+ }
+ }
+ }
+
+ ksyn_wqunlock(kwq);
+ ksyn_wqrelease(kwq, 1, KSYN_WQTYPE_MUTEXDROP);
+ return returnbits;
+}
+
+static int
+_ksyn_check_init(ksyn_wait_queue_t kwq, uint32_t lgenval)
+{
+ int res = (lgenval & PTHRW_RWL_INIT) != 0;
+ if (res) {
+ if ((kwq->kw_kflags & KSYN_KWF_INITCLEARED) == 0) {
+ /* first to notice the reset of the lock, clear preposts */
+ CLEAR_REINIT_BITS(kwq);
+ kwq->kw_kflags |= KSYN_KWF_INITCLEARED;
+ }
+ }
+ return res;
+}
+
+static int
+_ksyn_handle_missed_wakeups(ksyn_wait_queue_t kwq,
+ uint32_t type,
+ uint32_t lockseq,
+ uint32_t *retval)
+{
+ int res = 0;
+ if (kwq->kw_pre_intrcount != 0 &&
+ kwq->kw_pre_intrtype == type &&
+ is_seqlower_eq(lockseq, kwq->kw_pre_intrseq)) {
+ kwq->kw_pre_intrcount--;
+ *retval = kwq->kw_pre_intrretbits;
+ if (kwq->kw_pre_intrcount == 0) {
+ CLEAR_INTR_PREPOST_BITS(kwq);
+ }
+ res = 1;
+ }
+ return res;
+}
+
+static int
+_ksyn_handle_overlap(ksyn_wait_queue_t kwq,
+ uint32_t lgenval,
+ uint32_t rw_wc,
+ uint32_t *retval)
+{
+ int res = 0;
+
+ // check for overlap and no pending W bit (indicates writers)
+ if (kwq->kw_overlapwatch != 0 &&
+ (rw_wc & PTHRW_RWS_SAVEMASK) == 0 &&
+ (lgenval & PTH_RWL_WBIT) == 0) {
+ /* overlap is set, so no need to check for valid state for overlap */
+
+ if (is_seqlower_eq(rw_wc, kwq->kw_nextseqword) || is_seqhigher_eq(kwq->kw_lastseqword, rw_wc)) {
+ /* increase the next expected seq by one */
+ kwq->kw_nextseqword += PTHRW_INC;
+ /* set count by one & bits from the nextseq and add M bit */
+ *retval = PTHRW_INC | ((kwq->kw_nextseqword & PTHRW_BIT_MASK) | PTH_RWL_MBIT);
+ res = 1;
+ }
+ }
+ return res;
+}
+
+static int
+_ksyn_handle_prepost(ksyn_wait_queue_t kwq,
+ uint32_t type,
+ uint32_t lockseq,
+ uint32_t *retval)
+{
+ int res = 0;
+ if (kwq->kw_pre_rwwc != 0 && is_seqlower_eq(lockseq, kwq->kw_pre_lockseq)) {
+ kwq->kw_pre_rwwc--;
+ if (kwq->kw_pre_rwwc == 0) {
+ uint32_t preseq = kwq->kw_pre_lockseq;
+ uint32_t prerw_wc = kwq->kw_pre_sseq;
+ CLEAR_PREPOST_BITS(kwq);
+ if ((kwq->kw_kflags & KSYN_KWF_INITCLEARED) != 0){
+ kwq->kw_kflags &= ~KSYN_KWF_INITCLEARED;
+ }
+
+ int error, block;
+ uint32_t updatebits;
+ error = kwq_handle_unlock(kwq, preseq, prerw_wc, &updatebits, (type|KW_UNLOCK_PREPOST), &block, lockseq);
+ if (error != 0) {
+ panic("kwq_handle_unlock failed %d\n", error);
+ }
+
+ if (block == 0) {
+ *retval = updatebits;
+ res = 1;
+ }
+ }
+ }
+ return res;
+}
+
+/* Helpers for QoS override management. Only applies to mutexes */
+static void ksyn_mtx_update_owner_qos_override(ksyn_wait_queue_t kwq, uint64_t tid, boolean_t prepost)
+{
+ if (!(kwq->kw_pflags & KSYN_WQ_SHARED)) {
+ boolean_t wasboosted = (kwq->kw_kflags & KSYN_KWF_QOS_APPLIED) ? TRUE : FALSE;
+ int waiter_qos = pthread_kern->proc_usynch_get_requested_thread_qos(current_uthread());
+
+ kwq->kw_qos_override = MAX(waiter_qos, kwq->kw_qos_override);
+
+ if (prepost && kwq->kw_inqueue == 0) {
+ // if there are no more waiters in the queue after the new (prepost-receiving) owner, we do not set an
+ // override, because the receiving owner may not re-enter the kernel to signal someone else if it is
+ // the last one to unlock. If other waiters end up entering the kernel, they will boost the owner
+ tid = 0;
+ }
+
+ if (tid != 0) {
+ if ((tid == kwq->kw_owner) && (kwq->kw_kflags & KSYN_KWF_QOS_APPLIED)) {
+ // hint continues to be accurate, and a boost was already applied
+ pthread_kern->proc_usynch_thread_qos_add_override(NULL, tid, kwq->kw_qos_override, FALSE);
+ } else {
+ // either hint did not match previous owner, or hint was accurate but mutex was not contended enough for a boost previously
+ boolean_t boostsucceded;
+
+ boostsucceded = pthread_kern->proc_usynch_thread_qos_add_override(NULL, tid, kwq->kw_qos_override, TRUE);
+
+ if (boostsucceded) {
+ kwq->kw_kflags |= KSYN_KWF_QOS_APPLIED;
+ }
+
+ if (wasboosted && (tid != kwq->kw_owner) && (kwq->kw_owner != 0)) {
+ // the hint did not match the previous owner, so drop overrides
+ PTHREAD_TRACE(TRACE_psynch_ksyn_incorrect_owner, kwq->kw_owner, 0, 0, 0, 0);
+ pthread_kern->proc_usynch_thread_qos_remove_override(NULL, kwq->kw_owner);
+ }
+ }
+ } else {
+ // new hint tells us that we don't know the owner, so drop any existing overrides
+ kwq->kw_kflags &= ~KSYN_KWF_QOS_APPLIED;
+ kwq->kw_qos_override = THREAD_QOS_UNSPECIFIED;
+
+ if (wasboosted && (kwq->kw_owner != 0)) {
+ // the hint did not match the previous owner, so drop overrides
+ PTHREAD_TRACE(TRACE_psynch_ksyn_incorrect_owner, kwq->kw_owner, 0, 0, 0, 0);
+ pthread_kern->proc_usynch_thread_qos_remove_override(NULL, kwq->kw_owner);
+ }
+ }
+ }
+}
+
+static void ksyn_mtx_transfer_qos_override(ksyn_wait_queue_t kwq, ksyn_waitq_element_t kwe)
+{
+ if (!(kwq->kw_pflags & KSYN_WQ_SHARED)) {
+ boolean_t wasboosted = (kwq->kw_kflags & KSYN_KWF_QOS_APPLIED) ? TRUE : FALSE;
+
+ if (kwq->kw_inqueue > 1) {
+ boolean_t boostsucceeded;
+
+ // More than one waiter, so resource will still be contended after handing off ownership
+ boostsucceeded = pthread_kern->proc_usynch_thread_qos_add_override(kwe->kwe_uth, 0, kwq->kw_qos_override, TRUE);
+
+ if (boostsucceeded) {
+ kwq->kw_kflags |= KSYN_KWF_QOS_APPLIED;
+ }
+ } else {
+ // kw_inqueue == 1 to get to this point, which means there will be no contention after this point
+ kwq->kw_kflags &= ~KSYN_KWF_QOS_APPLIED;
+ kwq->kw_qos_override = THREAD_QOS_UNSPECIFIED;
+ }
+
+ // Remove the override that was applied to kw_owner. There may have been a race,
+ // in which case it may not match the current thread
+ if (wasboosted) {
+ if (kwq->kw_owner == 0) {
+ PTHREAD_TRACE(TRACE_psynch_ksyn_incorrect_owner, 0, 0, 0, 0, 0);
+ } else if (thread_tid(current_thread()) != kwq->kw_owner) {
+ PTHREAD_TRACE(TRACE_psynch_ksyn_incorrect_owner, kwq->kw_owner, 0, 0, 0, 0);
+ pthread_kern->proc_usynch_thread_qos_remove_override(NULL, kwq->kw_owner);
+ } else {
+ pthread_kern->proc_usynch_thread_qos_remove_override(current_uthread(), 0);
+ }
+ }
+ }
+}
+
+static void ksyn_mtx_drop_qos_override(ksyn_wait_queue_t kwq)
+{
+ if (!(kwq->kw_pflags & KSYN_WQ_SHARED)) {
+ boolean_t wasboosted = (kwq->kw_kflags & KSYN_KWF_QOS_APPLIED) ? TRUE : FALSE;
+
+ // assume nobody else in queue if this routine was called
+ kwq->kw_kflags &= ~KSYN_KWF_QOS_APPLIED;
+ kwq->kw_qos_override = THREAD_QOS_UNSPECIFIED;
+
+ // Remove the override that was applied to kw_owner. There may have been a race,
+ // in which case it may not match the current thread
+ if (wasboosted) {
+ if (kwq->kw_owner == 0) {
+ PTHREAD_TRACE(TRACE_psynch_ksyn_incorrect_owner, 0, 0, 0, 0, 0);
+ } else if (thread_tid(current_thread()) != kwq->kw_owner) {
+ PTHREAD_TRACE(TRACE_psynch_ksyn_incorrect_owner, kwq->kw_owner, 0, 0, 0, 0);
+ pthread_kern->proc_usynch_thread_qos_remove_override(NULL, kwq->kw_owner);
+ } else {
+ pthread_kern->proc_usynch_thread_qos_remove_override(current_uthread(), 0);
+ }
+ }
+ }
+}
+
+/*
+ * psynch_mutexwait: This system call is used for contended psynch mutexes to block.
+ */
+
+int
+_psynch_mutexwait(__unused proc_t p,
+ user_addr_t mutex,
+ uint32_t mgen,
+ uint32_t ugen,
+ uint64_t tid,
+ uint32_t flags,
+ uint32_t *retval)
+{
+ ksyn_wait_queue_t kwq;
+ int error=0;
+ int ins_flags;
+
+ int firstfit = (flags & PTHREAD_POLICY_FLAGS_MASK) == _PTHREAD_MUTEX_POLICY_FIRSTFIT;
+ uint32_t updatebits = 0;
+
+ uint32_t lockseq = (mgen & PTHRW_COUNT_MASK);
+
+ if (firstfit == 0) {
+ ins_flags = SEQFIT;
+ } else {
+ /* first fit */
+ ins_flags = FIRSTFIT;
+ }
+
+ error = ksyn_wqfind(mutex, mgen, ugen, 0, flags, (KSYN_WQTYPE_INWAIT|KSYN_WQTYPE_MTX), &kwq);
+ if (error != 0) {
+ return(error);
+ }
+
+ ksyn_wqlock(kwq);
+
+ // mutexwait passes in an owner hint at the time userspace contended for the mutex, however, the
+ // owner tid in the userspace data structure may be unset or SWITCHING (-1), or it may correspond
+ // to a stale snapshot after the lock has subsequently been unlocked by another thread.
+ if (tid == 0) {
+ // contender came in before owner could write TID
+ tid = 0;
+ } else if (kwq->kw_lastunlockseq != PTHRW_RWL_INIT && is_seqlower(ugen, kwq->kw_lastunlockseq)) {
+ // owner is stale, someone has come in and unlocked since this contended read the TID, so
+ // assume what is known in the kernel is accurate
+ tid = kwq->kw_owner;
+ } else if (tid == PTHREAD_MTX_TID_SWITCHING) {
+ // userspace didn't know the owner because it was being unlocked, but that unlocker hasn't
+ // reached the kernel yet. So assume what is known in the kernel is accurate
+ tid = kwq->kw_owner;
+ } else {
+ // hint is being passed in for a specific thread, and we have no reason not to trust
+ // it (like the kernel unlock sequence being higher
+ }
+
+
+ if (_ksyn_handle_missed_wakeups(kwq, PTH_RW_TYPE_WRITE, lockseq, retval)) {
+ ksyn_mtx_update_owner_qos_override(kwq, thread_tid(current_thread()), TRUE);
+ kwq->kw_owner = thread_tid(current_thread());
+
+ ksyn_wqunlock(kwq);
+ goto out;
+ }
+
+ if ((kwq->kw_pre_rwwc != 0) && ((ins_flags == FIRSTFIT) || ((lockseq & PTHRW_COUNT_MASK) == (kwq->kw_pre_lockseq & PTHRW_COUNT_MASK) ))) {
+ /* got preposted lock */
+ kwq->kw_pre_rwwc--;
+ if (kwq->kw_pre_rwwc == 0) {
+ CLEAR_PREPOST_BITS(kwq);
+ if (kwq->kw_inqueue == 0) {
+ updatebits = lockseq | (PTH_RWL_KBIT | PTH_RWL_EBIT);
+ } else {
+ updatebits = (kwq->kw_highseq & PTHRW_COUNT_MASK) | (PTH_RWL_KBIT | PTH_RWL_EBIT);
+ }
+ updatebits &= ~PTH_RWL_MTX_WAIT;
+
+ if (updatebits == 0) {
+ __FAILEDUSERTEST__("psynch_mutexwait(prepost): returning 0 lseq in mutexwait with no EBIT \n");
+ }
+
+ ksyn_mtx_update_owner_qos_override(kwq, thread_tid(current_thread()), TRUE);
+ kwq->kw_owner = thread_tid(current_thread());
+
+ ksyn_wqunlock(kwq);
+ *retval = updatebits;
+ goto out;
+ } else {
+ __FAILEDUSERTEST__("psynch_mutexwait: more than one prepost\n");
+ kwq->kw_pre_lockseq += PTHRW_INC; /* look for next one */
+ ksyn_wqunlock(kwq);
+ error = EINVAL;
+ goto out;
+ }
+ }
+
+ ksyn_mtx_update_owner_qos_override(kwq, tid, FALSE);
+ kwq->kw_owner = tid;
+
+ error = ksyn_wait(kwq, KSYN_QUEUE_WRITER, mgen, ins_flags, 0, psynch_mtxcontinue);
+ // ksyn_wait drops wait queue lock
+out:
+ ksyn_wqrelease(kwq, 1, (KSYN_WQTYPE_INWAIT|KSYN_WQTYPE_MTX));
+ return error;
+}
+
+void
+psynch_mtxcontinue(void *parameter, wait_result_t result)
+{
+ uthread_t uth = current_uthread();
+ ksyn_wait_queue_t kwq = parameter;
+ ksyn_waitq_element_t kwe = pthread_kern->uthread_get_uukwe(uth);
+
+ int error = _wait_result_to_errno(result);
+ if (error != 0) {
+ ksyn_wqlock(kwq);
+ if (kwe->kwe_kwqqueue) {
+ ksyn_queue_remove_item(kwq, &kwq->kw_ksynqueues[KSYN_QUEUE_WRITER], kwe);
+ }
+ ksyn_wqunlock(kwq);
+ } else {
+ uint32_t updatebits = kwe->kwe_psynchretval & ~PTH_RWL_MTX_WAIT;
+ pthread_kern->uthread_set_returnval(uth, updatebits);
+
+ if (updatebits == 0)
+ __FAILEDUSERTEST__("psynch_mutexwait: returning 0 lseq in mutexwait with no EBIT \n");
+ }
+ ksyn_wqrelease(kwq, 1, (KSYN_WQTYPE_INWAIT|KSYN_WQTYPE_MTX));
+ pthread_kern->unix_syscall_return(error);
+}
+
+/*
+ * psynch_mutexdrop: This system call is used for unlock postings on contended psynch mutexes.
+ */
+int
+_psynch_mutexdrop(__unused proc_t p,
+ user_addr_t mutex,
+ uint32_t mgen,
+ uint32_t ugen,
+ uint64_t tid __unused,
+ uint32_t flags,
+ uint32_t *retval)
+{
+ int res;
+ ksyn_wait_queue_t kwq;
+
+ res = ksyn_wqfind(mutex, mgen, ugen, 0, flags, KSYN_WQTYPE_MUTEXDROP, &kwq);
+ if (res == 0) {
+ uint32_t updateval = _psynch_mutexdrop_internal(kwq, mgen, ugen, flags);
+ /* drops the kwq reference */
+ if (retval) {
+ *retval = updateval;
+ }
+ }
+
+ return res;
+}
+
+static kern_return_t
+ksyn_mtxsignal(ksyn_wait_queue_t kwq, ksyn_waitq_element_t kwe, uint32_t updateval)
+{
+ kern_return_t ret;
+
+ if (!kwe) {
+ kwe = TAILQ_FIRST(&kwq->kw_ksynqueues[KSYN_QUEUE_WRITER].ksynq_kwelist);
+ if (!kwe) {
+ panic("ksyn_mtxsignal: panic signaling empty queue");
+ }
+ }
+
+ ksyn_mtx_transfer_qos_override(kwq, kwe);
+ kwq->kw_owner = kwe->kwe_tid;
+
+ ret = ksyn_signal(kwq, KSYN_QUEUE_WRITER, kwe, updateval);
+
+ // if waking the new owner failed, remove any overrides
+ if (ret != KERN_SUCCESS) {
+ ksyn_mtx_drop_qos_override(kwq);
+ kwq->kw_owner = 0;
+ }
+
+ return ret;
+}
+
+
+static void
+ksyn_prepost(ksyn_wait_queue_t kwq,
+ ksyn_waitq_element_t kwe,
+ uint32_t state,
+ uint32_t lockseq)
+{
+ bzero(kwe, sizeof(*kwe));
+ kwe->kwe_state = state;
+ kwe->kwe_lockseq = lockseq;
+ kwe->kwe_count = 1;
+
+ (void)ksyn_queue_insert(kwq, KSYN_QUEUE_WRITER, kwe, lockseq, SEQFIT);
+ kwq->kw_fakecount++;
+}
+
+static void
+ksyn_cvsignal(ksyn_wait_queue_t ckwq,
+ thread_t th,
+ uint32_t uptoseq,
+ uint32_t signalseq,
+ uint32_t *updatebits,
+ int *broadcast,
+ ksyn_waitq_element_t *nkwep)
+{
+ ksyn_waitq_element_t kwe = NULL;
+ ksyn_waitq_element_t nkwe = NULL;
+ ksyn_queue_t kq = &ckwq->kw_ksynqueues[KSYN_QUEUE_WRITER];
+
+ uptoseq &= PTHRW_COUNT_MASK;
+
+ // Find the specified thread to wake.
+ if (th != THREAD_NULL) {
+ uthread_t uth = pthread_kern->get_bsdthread_info(th);
+ kwe = pthread_kern->uthread_get_uukwe(uth);
+ if (kwe->kwe_kwqqueue != ckwq ||
+ is_seqhigher(kwe->kwe_lockseq, uptoseq)) {
+ // Unless it's no longer waiting on this CV...
+ kwe = NULL;
+ // ...in which case we post a broadcast instead.
+ *broadcast = 1;
+ return;
+ }
+ }
+
+ // If no thread was specified, find any thread to wake (with the right
+ // sequence number).
+ while (th == THREAD_NULL) {
+ if (kwe == NULL) {
+ kwe = ksyn_queue_find_signalseq(ckwq, kq, uptoseq, signalseq);
+ }
+ if (kwe == NULL && nkwe == NULL) {
+ // No eligible entries; need to allocate a new
+ // entry to prepost. Loop to rescan after
+ // reacquiring the lock after allocation in
+ // case anything new shows up.
+ ksyn_wqunlock(ckwq);
+ nkwe = (ksyn_waitq_element_t)pthread_kern->zalloc(kwe_zone);
+ ksyn_wqlock(ckwq);
+ } else {
+ break;
+ }
+ }
+
+ if (kwe != NULL) {
+ // If we found a thread to wake...
+ if (kwe->kwe_state == KWE_THREAD_INWAIT) {
+ if (is_seqlower(kwe->kwe_lockseq, signalseq)) {
+ /*
+ * A valid thread in our range, but lower than our signal.
+ * Matching it may leave our match with nobody to wake it if/when
+ * it arrives (the signal originally meant for this thread might
+ * not successfully wake it).
+ *
+ * Convert to broadcast - may cause some spurious wakeups
+ * (allowed by spec), but avoids starvation (better choice).
+ */
+ *broadcast = 1;
+ } else {
+ (void)ksyn_signal(ckwq, KSYN_QUEUE_WRITER, kwe, PTH_RWL_MTX_WAIT);
+ *updatebits += PTHRW_INC;
+ }
+ } else if (kwe->kwe_state == KWE_THREAD_PREPOST) {
+ // Merge with existing prepost at same uptoseq.
+ kwe->kwe_count += 1;
+ } else if (kwe->kwe_state == KWE_THREAD_BROADCAST) {
+ // Existing broadcasts subsume this signal.
+ } else {
+ panic("unknown kwe state\n");
+ }
+ if (nkwe) {
+ /*
+ * If we allocated a new kwe above but then found a different kwe to
+ * use then we need to deallocate the spare one.
+ */
+ pthread_kern->zfree(kwe_zone, nkwe);
+ nkwe = NULL;
+ }
+ } else if (nkwe != NULL) {
+ // ... otherwise, insert the newly allocated prepost.
+ ksyn_prepost(ckwq, nkwe, KWE_THREAD_PREPOST, uptoseq);
+ nkwe = NULL;
+ } else {
+ panic("failed to allocate kwe\n");
+ }
+
+ *nkwep = nkwe;
+}
+
+static int
+__psynch_cvsignal(user_addr_t cv,
+ uint32_t cgen,
+ uint32_t cugen,
+ uint32_t csgen,
+ uint32_t flags,
+ int broadcast,
+ mach_port_name_t threadport,
+ uint32_t *retval)
+{
+ int error = 0;
+ thread_t th = THREAD_NULL;
+ ksyn_wait_queue_t kwq;
+
+ uint32_t uptoseq = cgen & PTHRW_COUNT_MASK;
+ uint32_t fromseq = (cugen & PTHRW_COUNT_MASK) + PTHRW_INC;
+
+ // validate sane L, U, and S values
+ if ((threadport == 0 && is_seqhigher(fromseq, uptoseq)) || is_seqhigher(csgen, uptoseq)) {
+ __FAILEDUSERTEST__("cvbroad: invalid L, U and S values\n");
+ return EINVAL;
+ }
+
+ if (threadport != 0) {
+ th = port_name_to_thread((mach_port_name_t)threadport);
+ if (th == THREAD_NULL) {
+ return ESRCH;
+ }
+ }
+
+ error = ksyn_wqfind(cv, cgen, cugen, csgen, flags, (KSYN_WQTYPE_CVAR | KSYN_WQTYPE_INDROP), &kwq);
+ if (error == 0) {
+ uint32_t updatebits = 0;
+ ksyn_waitq_element_t nkwe = NULL;
+
+ ksyn_wqlock(kwq);
+
+ // update L, U and S...
+ UPDATE_CVKWQ(kwq, cgen, cugen, csgen);
+
+ if (!broadcast) {
+ // No need to signal if the CV is already balanced.
+ if (diff_genseq(kwq->kw_lword, kwq->kw_sword)) {
+ ksyn_cvsignal(kwq, th, uptoseq, fromseq, &updatebits, &broadcast, &nkwe);
+ }
+ }
+
+ if (broadcast) {
+ ksyn_handle_cvbroad(kwq, uptoseq, &updatebits);
+ }
+
+ kwq->kw_sword += (updatebits & PTHRW_COUNT_MASK);
+ // set C or P bits and free if needed
+ ksyn_cvupdate_fixup(kwq, &updatebits);
+ *retval = updatebits;
+
+ ksyn_wqunlock(kwq);
+
+ if (nkwe != NULL) {
+ pthread_kern->zfree(kwe_zone, nkwe);
+ }
+
+ ksyn_wqrelease(kwq, 1, (KSYN_WQTYPE_INDROP | KSYN_WQTYPE_CVAR));
+ }
+
+ if (th != NULL) {
+ thread_deallocate(th);
+ }
+
+ return error;
+}
+
+/*
+ * psynch_cvbroad: This system call is used for broadcast posting on blocked waiters of psynch cvars.
+ */
+int
+_psynch_cvbroad(__unused proc_t p,
+ user_addr_t cv,
+ uint64_t cvlsgen,
+ uint64_t cvudgen,
+ uint32_t flags,
+ __unused user_addr_t mutex,
+ __unused uint64_t mugen,
+ __unused uint64_t tid,
+ uint32_t *retval)
+{
+ uint32_t diffgen = cvudgen & 0xffffffff;
+ uint32_t count = diffgen >> PTHRW_COUNT_SHIFT;
+ if (count > pthread_kern->get_task_threadmax()) {
+ __FAILEDUSERTEST__("cvbroad: difference greater than maximum possible thread count\n");
+ return EBUSY;
+ }
+
+ uint32_t csgen = (cvlsgen >> 32) & 0xffffffff;
+ uint32_t cgen = cvlsgen & 0xffffffff;
+ uint32_t cugen = (cvudgen >> 32) & 0xffffffff;
+
+ return __psynch_cvsignal(cv, cgen, cugen, csgen, flags, 1, 0, retval);
+}
+
+/*
+ * psynch_cvsignal: This system call is used for signalling the blocked waiters of psynch cvars.
+ */
+int
+_psynch_cvsignal(__unused proc_t p,
+ user_addr_t cv,
+ uint64_t cvlsgen,
+ uint32_t cvugen,
+ int threadport,
+ __unused user_addr_t mutex,
+ __unused uint64_t mugen,
+ __unused uint64_t tid,
+ uint32_t flags,
+ uint32_t *retval)
+{
+ uint32_t csgen = (cvlsgen >> 32) & 0xffffffff;
+ uint32_t cgen = cvlsgen & 0xffffffff;
+
+ return __psynch_cvsignal(cv, cgen, cvugen, csgen, flags, 0, threadport, retval);
+}
+
+/*
+ * psynch_cvwait: This system call is used for psynch cvar waiters to block in kernel.
+ */
+int
+_psynch_cvwait(__unused proc_t p,
+ user_addr_t cv,
+ uint64_t cvlsgen,
+ uint32_t cvugen,
+ user_addr_t mutex,
+ uint64_t mugen,
+ uint32_t flags,
+ int64_t sec,
+ uint32_t nsec,
+ uint32_t *retval)
+{
+ int error = 0;
+ uint32_t updatebits = 0;
+ ksyn_wait_queue_t ckwq = NULL;
+ ksyn_waitq_element_t kwe, nkwe = NULL;
+
+ /* for conformance reasons */
+ pthread_kern->__pthread_testcancel(0);
+
+ uint32_t csgen = (cvlsgen >> 32) & 0xffffffff;
+ uint32_t cgen = cvlsgen & 0xffffffff;
+ uint32_t ugen = (mugen >> 32) & 0xffffffff;
+ uint32_t mgen = mugen & 0xffffffff;
+
+ uint32_t lockseq = (cgen & PTHRW_COUNT_MASK);
+
+ /*
+ * In cvwait U word can be out of range as cv could be used only for
+ * timeouts. However S word needs to be within bounds and validated at
+ * user level as well.
+ */
+ if (is_seqhigher_eq(csgen, lockseq) != 0) {
+ __FAILEDUSERTEST__("psync_cvwait; invalid sequence numbers\n");
+ return EINVAL;
+ }
+
+ error = ksyn_wqfind(cv, cgen, cvugen, csgen, flags, KSYN_WQTYPE_CVAR | KSYN_WQTYPE_INWAIT, &ckwq);
+ if (error != 0) {
+ return error;
+ }
+
+ if (mutex != 0) {
+ error = _psynch_mutexdrop(NULL, mutex, mgen, ugen, 0, flags, NULL);
+ if (error != 0) {
+ goto out;
+ }
+ }
+
+ ksyn_wqlock(ckwq);
+
+ // update L, U and S...
+ UPDATE_CVKWQ(ckwq, cgen, cvugen, csgen);
+
+ /* Look for the sequence for prepost (or conflicting thread */
+ ksyn_queue_t kq = &ckwq->kw_ksynqueues[KSYN_QUEUE_WRITER];
+ kwe = ksyn_queue_find_cvpreposeq(kq, lockseq);
+ if (kwe != NULL) {
+ if (kwe->kwe_state == KWE_THREAD_PREPOST) {
+ if ((kwe->kwe_lockseq & PTHRW_COUNT_MASK) == lockseq) {
+ /* we can safely consume a reference, so do so */
+ if (--kwe->kwe_count == 0) {
+ ksyn_queue_remove_item(ckwq, kq, kwe);
+ ckwq->kw_fakecount--;
+ nkwe = kwe;
+ }
+ } else {
+ /*
+ * consuming a prepost higher than our lock sequence is valid, but
+ * can leave the higher thread without a match. Convert the entry
+ * to a broadcast to compensate for this.
+ */
+ ksyn_handle_cvbroad(ckwq, kwe->kwe_lockseq, &updatebits);
+#if __TESTPANICS__
+ if (updatebits != 0)
+ panic("psync_cvwait: convert pre-post to broadcast: woke up %d threads that shouldn't be there\n", updatebits);
+#endif /* __TESTPANICS__ */
+ }
+ } else if (kwe->kwe_state == KWE_THREAD_BROADCAST) {
+ // XXX
+ // Nothing to do.
+ } else if (kwe->kwe_state == KWE_THREAD_INWAIT) {
+ __FAILEDUSERTEST__("cvwait: thread entry with same sequence already present\n");
+ error = EBUSY;
+ } else {
+ panic("psync_cvwait: unexpected wait queue element type\n");
+ }
+
+ if (error == 0) {
+ updatebits = PTHRW_INC;
+ ckwq->kw_sword += PTHRW_INC;
+
+ /* set C or P bits and free if needed */
+ ksyn_cvupdate_fixup(ckwq, &updatebits);
+ *retval = updatebits;
+ }
+ } else {
+ uint64_t abstime = 0;
+
+ if (sec != 0 || (nsec & 0x3fffffff) != 0) {
+ struct timespec ts;
+ ts.tv_sec = (__darwin_time_t)sec;
+ ts.tv_nsec = (nsec & 0x3fffffff);
+ nanoseconds_to_absolutetime((uint64_t)ts.tv_sec * NSEC_PER_SEC + ts.tv_nsec, &abstime);
+ clock_absolutetime_interval_to_deadline(abstime, &abstime);
+ }
+
+ error = ksyn_wait(ckwq, KSYN_QUEUE_WRITER, cgen, SEQFIT, abstime, psynch_cvcontinue);
+ // ksyn_wait drops wait queue lock
+ }
+
+ ksyn_wqunlock(ckwq);
+
+ if (nkwe != NULL) {
+ pthread_kern->zfree(kwe_zone, nkwe);
+ }
+out:
+ ksyn_wqrelease(ckwq, 1, (KSYN_WQTYPE_INWAIT | KSYN_WQTYPE_CVAR));
+ return error;
+}
+
+
+void
+psynch_cvcontinue(void *parameter, wait_result_t result)
+{
+ uthread_t uth = current_uthread();
+ ksyn_wait_queue_t ckwq = parameter;
+ ksyn_waitq_element_t kwe = pthread_kern->uthread_get_uukwe(uth);
+
+ int error = _wait_result_to_errno(result);
+ if (error != 0) {
+ ksyn_wqlock(ckwq);
+ /* just in case it got woken up as we were granting */
+ pthread_kern->uthread_set_returnval(uth, kwe->kwe_psynchretval);
+
+ if (kwe->kwe_kwqqueue) {
+ ksyn_queue_remove_item(ckwq, &ckwq->kw_ksynqueues[KSYN_QUEUE_WRITER], kwe);
+ }
+ if ((kwe->kwe_psynchretval & PTH_RWL_MTX_WAIT) != 0) {
+ /* the condition var granted.
+ * reset the error so that the thread returns back.
+ */
+ error = 0;
+ /* no need to set any bits just return as cvsig/broad covers this */
+ } else {
+ ckwq->kw_sword += PTHRW_INC;
+
+ /* set C and P bits, in the local error */
+ if ((ckwq->kw_lword & PTHRW_COUNT_MASK) == (ckwq->kw_sword & PTHRW_COUNT_MASK)) {
+ error |= ECVCERORR;
+ if (ckwq->kw_inqueue != 0) {
+ ksyn_queue_free_items(ckwq, KSYN_QUEUE_WRITER, ckwq->kw_lword, 1);
+ }
+ ckwq->kw_lword = ckwq->kw_uword = ckwq->kw_sword = 0;
+ ckwq->kw_kflags |= KSYN_KWF_ZEROEDOUT;
+ } else {
+ /* everythig in the queue is a fake entry ? */
+ if (ckwq->kw_inqueue != 0 && ckwq->kw_fakecount == ckwq->kw_inqueue) {
+ error |= ECVPERORR;
+ }
+ }
+ }
+ ksyn_wqunlock(ckwq);
+ } else {
+ int val = 0;
+ // PTH_RWL_MTX_WAIT is removed
+ if ((kwe->kwe_psynchretval & PTH_RWS_CV_MBIT) != 0) {
+ val = PTHRW_INC | PTH_RWS_CV_CBIT;
+ }
+ pthread_kern->uthread_set_returnval(uth, val);
+ }
+
+ ksyn_wqrelease(ckwq, 1, (KSYN_WQTYPE_INWAIT | KSYN_WQTYPE_CVAR));
+ pthread_kern->unix_syscall_return(error);
+}
+
+/*
+ * psynch_cvclrprepost: This system call clears pending prepost if present.
+ */
+int
+_psynch_cvclrprepost(__unused proc_t p,
+ user_addr_t cv,
+ uint32_t cvgen,
+ uint32_t cvugen,
+ uint32_t cvsgen,
+ __unused uint32_t prepocnt,
+ uint32_t preposeq,
+ uint32_t flags,
+ int *retval)
+{
+ int error = 0;
+ int mutex = (flags & _PTHREAD_MTX_OPT_MUTEX);
+ int wqtype = (mutex ? KSYN_WQTYPE_MTX : KSYN_WQTYPE_CVAR) | KSYN_WQTYPE_INDROP;
+ ksyn_wait_queue_t kwq = NULL;
+
+ *retval = 0;
+
+ error = ksyn_wqfind(cv, cvgen, cvugen, mutex ? 0 : cvsgen, flags, wqtype, &kwq);
+ if (error != 0) {
+ return error;
+ }
+
+ ksyn_wqlock(kwq);
+
+ if (mutex) {
+ int firstfit = (flags & PTHREAD_POLICY_FLAGS_MASK) == _PTHREAD_MUTEX_POLICY_FIRSTFIT;
+ if (firstfit && kwq->kw_pre_rwwc != 0) {
+ if (is_seqlower_eq(kwq->kw_pre_lockseq, cvgen)) {
+ // clear prepost
+ kwq->kw_pre_rwwc = 0;
+ kwq->kw_pre_lockseq = 0;
+ }
+ }
+ } else {
+ ksyn_queue_free_items(kwq, KSYN_QUEUE_WRITER, preposeq, 0);
+ }
+
+ ksyn_wqunlock(kwq);
+ ksyn_wqrelease(kwq, 1, wqtype);
+ return error;
+}
+
+/* ***************** pthread_rwlock ************************ */
+
+static int
+__psynch_rw_lock(int type,
+ user_addr_t rwlock,
+ uint32_t lgenval,
+ uint32_t ugenval,
+ uint32_t rw_wc,
+ int flags,
+ uint32_t *retval)
+{
+ int prepost_type, kqi;
+
+ if (type == PTH_RW_TYPE_READ) {
+ prepost_type = KW_UNLOCK_PREPOST_READLOCK;
+ kqi = KSYN_QUEUE_READ;
+ } else {
+ prepost_type = KW_UNLOCK_PREPOST_WRLOCK;
+ kqi = KSYN_QUEUE_WRITER;
+ }
+
+ uint32_t lockseq = lgenval & PTHRW_COUNT_MASK;
+
+ int error;
+ ksyn_wait_queue_t kwq;
+ error = ksyn_wqfind(rwlock, lgenval, ugenval, rw_wc, flags, (KSYN_WQTYPE_INWAIT|KSYN_WQTYPE_RWLOCK), &kwq);
+ if (error == 0) {
+ ksyn_wqlock(kwq);
+ _ksyn_check_init(kwq, lgenval);
+ if (_ksyn_handle_missed_wakeups(kwq, type, lockseq, retval) ||
+ // handle overlap first as they are not counted against pre_rwwc
+ (type == PTH_RW_TYPE_READ && _ksyn_handle_overlap(kwq, lgenval, rw_wc, retval)) ||
+ _ksyn_handle_prepost(kwq, prepost_type, lockseq, retval)) {
+ ksyn_wqunlock(kwq);
+ } else {
+ error = ksyn_wait(kwq, kqi, lgenval, SEQFIT, 0, THREAD_CONTINUE_NULL);
+ // ksyn_wait drops wait queue lock
+ if (error == 0) {
+ uthread_t uth = current_uthread();
+ ksyn_waitq_element_t kwe = pthread_kern->uthread_get_uukwe(uth);
+ *retval = kwe->kwe_psynchretval;
+ }
+ }
+ ksyn_wqrelease(kwq, 0, (KSYN_WQTYPE_INWAIT|KSYN_WQTYPE_RWLOCK));
+ }
+ return error;
+}
+
+/*
+ * psynch_rw_rdlock: This system call is used for psync rwlock readers to block.
+ */
+int
+_psynch_rw_rdlock(__unused proc_t p,
+ user_addr_t rwlock,
+ uint32_t lgenval,
+ uint32_t ugenval,
+ uint32_t rw_wc,
+ int flags,
+ uint32_t *retval)
+{
+ return __psynch_rw_lock(PTH_RW_TYPE_READ, rwlock, lgenval, ugenval, rw_wc, flags, retval);
+}
+
+/*
+ * psynch_rw_longrdlock: This system call is used for psync rwlock long readers to block.
+ */
+int
+_psynch_rw_longrdlock(__unused proc_t p,
+ __unused user_addr_t rwlock,
+ __unused uint32_t lgenval,
+ __unused uint32_t ugenval,
+ __unused uint32_t rw_wc,
+ __unused int flags,
+ __unused uint32_t *retval)
+{
+ return ESRCH;
+}
+
+
+/*
+ * psynch_rw_wrlock: This system call is used for psync rwlock writers to block.
+ */
+int
+_psynch_rw_wrlock(__unused proc_t p,
+ user_addr_t rwlock,
+ uint32_t lgenval,
+ uint32_t ugenval,
+ uint32_t rw_wc,
+ int flags,
+ uint32_t *retval)
+{
+ return __psynch_rw_lock(PTH_RW_TYPE_WRITE, rwlock, lgenval, ugenval, rw_wc, flags, retval);
+}
+
+/*
+ * psynch_rw_yieldwrlock: This system call is used for psync rwlock yielding writers to block.
+ */
+int
+_psynch_rw_yieldwrlock(__unused proc_t p,
+ __unused user_addr_t rwlock,
+ __unused uint32_t lgenval,
+ __unused uint32_t ugenval,
+ __unused uint32_t rw_wc,
+ __unused int flags,
+ __unused uint32_t *retval)
+{
+ return ESRCH;
+}
+
+/*
+ * psynch_rw_unlock: This system call is used for unlock state postings. This will grant appropriate
+ * reader/writer variety lock.
+ */
+int
+_psynch_rw_unlock(__unused proc_t p,
+ user_addr_t rwlock,
+ uint32_t lgenval,
+ uint32_t ugenval,
+ uint32_t rw_wc,
+ int flags,
+ uint32_t *retval)
+{
+ int error = 0;
+ ksyn_wait_queue_t kwq;
+ uint32_t updatebits = 0;
+ int diff;
+ uint32_t count = 0;
+ uint32_t curgen = lgenval & PTHRW_COUNT_MASK;
+
+ error = ksyn_wqfind(rwlock, lgenval, ugenval, rw_wc, flags, (KSYN_WQTYPE_INDROP | KSYN_WQTYPE_RWLOCK), &kwq);
+ if (error != 0) {
+ return(error);
+ }
+
+ ksyn_wqlock(kwq);
+ int isinit = _ksyn_check_init(kwq, lgenval);
+
+ /* if lastunlock seq is set, ensure the current one is not lower than that, as it would be spurious */
+ if ((kwq->kw_lastunlockseq != PTHRW_RWL_INIT) && (is_seqlower(ugenval, kwq->kw_lastunlockseq)!= 0)) {
+ error = 0;
+ goto out;
+ }
+
+ /* If L-U != num of waiters, then it needs to be preposted or spr */
+ diff = find_diff(lgenval, ugenval);
+
+ if (find_seq_till(kwq, curgen, diff, &count) == 0) {
+ if ((count == 0) || (count < (uint32_t)diff))
+ goto prepost;
+ }
+
+ /* no prepost and all threads are in place, reset the bit */
+ if ((isinit != 0) && ((kwq->kw_kflags & KSYN_KWF_INITCLEARED) != 0)){
+ kwq->kw_kflags &= ~KSYN_KWF_INITCLEARED;
+ }
+
+ /* can handle unlock now */
+
+ CLEAR_PREPOST_BITS(kwq);
+
+ error = kwq_handle_unlock(kwq, lgenval, rw_wc, &updatebits, 0, NULL, 0);
+#if __TESTPANICS__
+ if (error != 0)
+ panic("psynch_rw_unlock: kwq_handle_unlock failed %d\n",error);
+#endif /* __TESTPANICS__ */
+out:
+ if (error == 0) {
+ /* update bits?? */
+ *retval = updatebits;
+ }
+
+
+ ksyn_wqunlock(kwq);
+ ksyn_wqrelease(kwq, 0, (KSYN_WQTYPE_INDROP | KSYN_WQTYPE_RWLOCK));
+
+ return(error);
+
+prepost:
+ /* update if the new seq is higher than prev prepost, or first set */
+ if (is_rws_setseq(kwq->kw_pre_sseq) ||
+ is_seqhigher_eq(rw_wc, kwq->kw_pre_sseq)) {
+ kwq->kw_pre_rwwc = (diff - count);
+ kwq->kw_pre_lockseq = curgen;
+ kwq->kw_pre_sseq = rw_wc;
+ updatebits = lgenval; /* let this not do unlock handling */
+ }
+ error = 0;
+ goto out;
+}
+
+
+/* ************************************************************************** */
+void
+pth_global_hashinit(void)
+{
+ pth_glob_hashtbl = hashinit(PTH_HASHSIZE * 4, M_PROC, &pthhash);
+}
+
+void
+_pth_proc_hashinit(proc_t p)
+{
+ void *ptr = hashinit(PTH_HASHSIZE, M_PCB, &pthhash);
+ if (ptr == NULL) {
+ panic("pth_proc_hashinit: hash init returned 0\n");
+ }
+
+ pthread_kern->proc_set_pthhash(p, ptr);
+}
+
+
+static int
+ksyn_wq_hash_lookup(user_addr_t uaddr,
+ proc_t p,
+ int flags,
+ ksyn_wait_queue_t *out_kwq,
+ struct pthhashhead **out_hashptr,
+ uint64_t *out_object,
+ uint64_t *out_offset)
+{
+ int res = 0;
+ ksyn_wait_queue_t kwq;
+ uint64_t object = 0, offset = 0;
+ struct pthhashhead *hashptr;
+ if ((flags & PTHREAD_PSHARED_FLAGS_MASK) == PTHREAD_PROCESS_SHARED) {
+ hashptr = pth_glob_hashtbl;
+ res = ksyn_findobj(uaddr, &object, &offset);
+ if (res == 0) {
+ LIST_FOREACH(kwq, &hashptr[object & pthhash], kw_hash) {
+ if (kwq->kw_object == object && kwq->kw_offset == offset) {
+ break;
+ }
+ }
+ } else {
+ kwq = NULL;
+ }
+ } else {
+ hashptr = pthread_kern->proc_get_pthhash(p);
+ LIST_FOREACH(kwq, &hashptr[uaddr & pthhash], kw_hash) {
+ if (kwq->kw_addr == uaddr) {
+ break;
+ }
+ }
+ }
+ *out_kwq = kwq;
+ *out_object = object;
+ *out_offset = offset;
+ *out_hashptr = hashptr;
+ return res;
+}
+
+void
+_pth_proc_hashdelete(proc_t p)
+{
+ struct pthhashhead * hashptr;
+ ksyn_wait_queue_t kwq;
+ unsigned long hashsize = pthhash + 1;
+ unsigned long i;
+
+ hashptr = pthread_kern->proc_get_pthhash(p);
+ pthread_kern->proc_set_pthhash(p, NULL);
+ if (hashptr == NULL) {
+ return;
+ }
+
+ pthread_list_lock();
+ for(i= 0; i < hashsize; i++) {
+ while ((kwq = LIST_FIRST(&hashptr[i])) != NULL) {
+ if ((kwq->kw_pflags & KSYN_WQ_INHASH) != 0) {
+ kwq->kw_pflags &= ~KSYN_WQ_INHASH;
+ LIST_REMOVE(kwq, kw_hash);
+ }
+ if ((kwq->kw_pflags & KSYN_WQ_FLIST) != 0) {
+ kwq->kw_pflags &= ~KSYN_WQ_FLIST;
+ LIST_REMOVE(kwq, kw_list);
+ }
+ pthread_list_unlock();
+ /* release fake entries if present for cvars */
+ if (((kwq->kw_type & KSYN_WQTYPE_MASK) == KSYN_WQTYPE_CVAR) && (kwq->kw_inqueue != 0))
+ ksyn_freeallkwe(&kwq->kw_ksynqueues[KSYN_QUEUE_WRITER]);
+ lck_mtx_destroy(&kwq->kw_lock, pthread_lck_grp);
+ pthread_kern->zfree(kwq_zone, kwq);
+ pthread_list_lock();
+ }
+ }
+ pthread_list_unlock();
+ FREE(hashptr, M_PROC);
+}
+
+/* no lock held for this as the waitqueue is getting freed */
+void
+ksyn_freeallkwe(ksyn_queue_t kq)
+{
+ ksyn_waitq_element_t kwe;
+ while ((kwe = TAILQ_FIRST(&kq->ksynq_kwelist)) != NULL) {
+ TAILQ_REMOVE(&kq->ksynq_kwelist, kwe, kwe_list);
+ if (kwe->kwe_state != KWE_THREAD_INWAIT) {
+ pthread_kern->zfree(kwe_zone, kwe);
+ }
+ }
+}
+
+/* find kernel waitqueue, if not present create one. Grants a reference */
+int
+ksyn_wqfind(user_addr_t uaddr, uint32_t mgen, uint32_t ugen, uint32_t sgen, int flags, int wqtype, ksyn_wait_queue_t *kwqp)
+{
+ int res = 0;
+ ksyn_wait_queue_t kwq = NULL;
+ ksyn_wait_queue_t nkwq = NULL;
+ struct pthhashhead *hashptr;
+ proc_t p = current_proc();
+
+ uint64_t object = 0, offset = 0;
+ if ((flags & PTHREAD_PSHARED_FLAGS_MASK) == PTHREAD_PROCESS_SHARED) {
+ res = ksyn_findobj(uaddr, &object, &offset);
+ hashptr = pth_glob_hashtbl;
+ } else {
+ hashptr = pthread_kern->proc_get_pthhash(p);
+ }
+
+ while (res == 0) {
+ pthread_list_lock();
+ res = ksyn_wq_hash_lookup(uaddr, current_proc(), flags, &kwq, &hashptr, &object, &offset);
+ if (res != 0) {
+ break;
+ }
+ if (kwq == NULL && nkwq == NULL) {
+ // Drop the lock to allocate a new kwq and retry.
+ pthread_list_unlock();
+
+ nkwq = (ksyn_wait_queue_t)pthread_kern->zalloc(kwq_zone);
+ bzero(nkwq, sizeof(struct ksyn_wait_queue));
+ int i;
+ for (i = 0; i < KSYN_QUEUE_MAX; i++) {
+ ksyn_queue_init(&nkwq->kw_ksynqueues[i]);
+ }
+ lck_mtx_init(&nkwq->kw_lock, pthread_lck_grp, pthread_lck_attr);
+ continue;
+ } else if (kwq == NULL && nkwq != NULL) {
+ // Still not found, add the new kwq to the hash.
+ kwq = nkwq;
+ nkwq = NULL; // Don't free.
+ if ((flags & PTHREAD_PSHARED_FLAGS_MASK) == PTHREAD_PROCESS_SHARED) {
+ kwq->kw_pflags |= KSYN_WQ_SHARED;
+ LIST_INSERT_HEAD(&hashptr[object & pthhash], kwq, kw_hash);
+ } else {
+ LIST_INSERT_HEAD(&hashptr[uaddr & pthhash], kwq, kw_hash);
+ }
+ kwq->kw_pflags |= KSYN_WQ_INHASH;
+ } else if (kwq != NULL) {
+ // Found an existing kwq, use it.
+ if ((kwq->kw_pflags & KSYN_WQ_FLIST) != 0) {
+ LIST_REMOVE(kwq, kw_list);
+ kwq->kw_pflags &= ~KSYN_WQ_FLIST;
+ }
+ if ((kwq->kw_type & KSYN_WQTYPE_MASK) != (wqtype & KSYN_WQTYPE_MASK)) {
+ if (kwq->kw_inqueue == 0 && kwq->kw_pre_rwwc == 0 && kwq->kw_pre_intrcount == 0) {
+ if (kwq->kw_iocount == 0) {
+ kwq->kw_type = 0; // mark for reinitialization
+ } else if (kwq->kw_iocount == 1 && kwq->kw_dropcount == kwq->kw_iocount) {
+ /* if all users are unlockers then wait for it to finish */
+ kwq->kw_pflags |= KSYN_WQ_WAITING;
+ // Drop the lock and wait for the kwq to be free.
+ (void)msleep(&kwq->kw_pflags, pthread_list_mlock, PDROP, "ksyn_wqfind", 0);
+ continue;
+ } else {
+ __FAILEDUSERTEST__("address already known to kernel for another [busy] synchronizer type\n");
+ res = EINVAL;
+ }
+ } else {
+ __FAILEDUSERTEST__("address already known to kernel for another [busy] synchronizer type\n");
+ res = EINVAL;
+ }
+ }
+ }
+ if (res == 0) {
+ if (kwq->kw_type == 0) {
+ kwq->kw_addr = uaddr;
+ kwq->kw_object = object;
+ kwq->kw_offset = offset;
+ kwq->kw_type = (wqtype & KSYN_WQTYPE_MASK);
+ CLEAR_REINIT_BITS(kwq);
+ kwq->kw_lword = mgen;
+ kwq->kw_uword = ugen;
+ kwq->kw_sword = sgen;
+ kwq->kw_owner = 0;
+ kwq->kw_kflags = 0;
+ kwq->kw_qos_override = THREAD_QOS_UNSPECIFIED;
+ }
+ kwq->kw_iocount++;
+ if (wqtype == KSYN_WQTYPE_MUTEXDROP) {
+ kwq->kw_dropcount++;
+ }
+ }
+ break;
+ }
+ pthread_list_unlock();
+ if (kwqp != NULL) {
+ *kwqp = kwq;
+ }
+ if (nkwq) {
+ lck_mtx_destroy(&nkwq->kw_lock, pthread_lck_grp);
+ pthread_kern->zfree(kwq_zone, nkwq);
+ }
+ return res;
+}
+
+/* Reference from find is dropped here. Starts the free process if needed */
+void
+ksyn_wqrelease(ksyn_wait_queue_t kwq, int qfreenow, int wqtype)
+{
+ uint64_t deadline;
+ ksyn_wait_queue_t free_elem = NULL;
+
+ pthread_list_lock();
+ if (wqtype == KSYN_WQTYPE_MUTEXDROP) {
+ kwq->kw_dropcount--;
+ }
+ if (--kwq->kw_iocount == 0) {
+ if ((kwq->kw_pflags & KSYN_WQ_WAITING) != 0) {
+ /* some one is waiting for the waitqueue, wake them up */
+ kwq->kw_pflags &= ~KSYN_WQ_WAITING;
+ wakeup(&kwq->kw_pflags);
+ }
+
+ if (kwq->kw_pre_rwwc == 0 && kwq->kw_inqueue == 0 && kwq->kw_pre_intrcount == 0) {
+ if (qfreenow == 0) {
+ microuptime(&kwq->kw_ts);
+ LIST_INSERT_HEAD(&pth_free_list, kwq, kw_list);
+ kwq->kw_pflags |= KSYN_WQ_FLIST;
+ if (psynch_cleanupset == 0) {
+ struct timeval t;
+ microuptime(&t);
+ t.tv_sec += KSYN_CLEANUP_DEADLINE;
+ deadline = tvtoabstime(&t);
+ thread_call_enter_delayed(psynch_thcall, deadline);
+ psynch_cleanupset = 1;
+ }
+ } else {
+ kwq->kw_pflags &= ~KSYN_WQ_INHASH;
+ LIST_REMOVE(kwq, kw_hash);
+ free_elem = kwq;
+ }
+ }
+ }
+ pthread_list_unlock();
+ if (free_elem != NULL) {
+ lck_mtx_destroy(&free_elem->kw_lock, pthread_lck_grp);
+ pthread_kern->zfree(kwq_zone, free_elem);
+ }
+}
+
+/* responsible to free the waitqueues */
+void
+psynch_wq_cleanup(__unused void *param, __unused void * param1)
+{
+ ksyn_wait_queue_t kwq;
+ struct timeval t;
+ int reschedule = 0;
+ uint64_t deadline = 0;
+ LIST_HEAD(, ksyn_wait_queue) freelist;
+ LIST_INIT(&freelist);
+
+ pthread_list_lock();
+
+ microuptime(&t);
+
+ LIST_FOREACH(kwq, &pth_free_list, kw_list) {
+ if (kwq->kw_iocount != 0 || kwq->kw_pre_rwwc != 0 || kwq->kw_inqueue != 0 || kwq->kw_pre_intrcount != 0) {
+ // still in use
+ continue;
+ }
+ __darwin_time_t diff = t.tv_sec - kwq->kw_ts.tv_sec;
+ if (diff < 0)
+ diff *= -1;
+ if (diff >= KSYN_CLEANUP_DEADLINE) {
+ kwq->kw_pflags &= ~(KSYN_WQ_FLIST | KSYN_WQ_INHASH);
+ LIST_REMOVE(kwq, kw_hash);
+ LIST_REMOVE(kwq, kw_list);
+ LIST_INSERT_HEAD(&freelist, kwq, kw_list);
+ } else {
+ reschedule = 1;
+ }
+
+ }
+ if (reschedule != 0) {
+ t.tv_sec += KSYN_CLEANUP_DEADLINE;
+ deadline = tvtoabstime(&t);
+ thread_call_enter_delayed(psynch_thcall, deadline);
+ psynch_cleanupset = 1;
+ } else {
+ psynch_cleanupset = 0;
+ }
+ pthread_list_unlock();
+
+ while ((kwq = LIST_FIRST(&freelist)) != NULL) {
+ LIST_REMOVE(kwq, kw_list);
+ lck_mtx_destroy(&kwq->kw_lock, pthread_lck_grp);
+ pthread_kern->zfree(kwq_zone, kwq);
+ }
+}
+
+static int
+_wait_result_to_errno(wait_result_t result)
+{
+ int res = 0;
+ switch (result) {
+ case THREAD_TIMED_OUT:
+ res = ETIMEDOUT;
+ break;
+ case THREAD_INTERRUPTED:
+ res = EINTR;
+ break;
+ }
+ return res;
+}
+
+int
+ksyn_wait(ksyn_wait_queue_t kwq,
+ int kqi,
+ uint32_t lockseq,
+ int fit,
+ uint64_t abstime,
+ thread_continue_t continuation)
+{
+ int res;
+
+ thread_t th = current_thread();
+ uthread_t uth = pthread_kern->get_bsdthread_info(th);
+ ksyn_waitq_element_t kwe = pthread_kern->uthread_get_uukwe(uth);
+ bzero(kwe, sizeof(*kwe));
+ kwe->kwe_count = 1;
+ kwe->kwe_lockseq = lockseq & PTHRW_COUNT_MASK;
+ kwe->kwe_state = KWE_THREAD_INWAIT;
+ kwe->kwe_uth = uth;
+ kwe->kwe_tid = thread_tid(th);
+
+ res = ksyn_queue_insert(kwq, kqi, kwe, lockseq, fit);
+ if (res != 0) {
+ //panic("psynch_rw_wrlock: failed to enqueue\n"); // XXX
+ ksyn_wqunlock(kwq);
+ return res;
+ }
+
+ assert_wait_deadline_with_leeway(&kwe->kwe_psynchretval, THREAD_ABORTSAFE, TIMEOUT_URGENCY_USER_NORMAL, abstime, 0);
+ ksyn_wqunlock(kwq);
+
+ kern_return_t ret;
+ if (continuation == THREAD_CONTINUE_NULL) {
+ ret = thread_block(NULL);
+ } else {
+ ret = thread_block_parameter(continuation, kwq);
+
+ // If thread_block_parameter returns (interrupted) call the
+ // continuation manually to clean up.
+ continuation(kwq, ret);
+
+ // NOT REACHED
+ panic("ksyn_wait continuation returned");
+ }
+
+ res = _wait_result_to_errno(ret);
+ if (res != 0) {
+ ksyn_wqlock(kwq);
+ if (kwe->kwe_kwqqueue) {
+ ksyn_queue_remove_item(kwq, &kwq->kw_ksynqueues[kqi], kwe);
+ }
+ ksyn_wqunlock(kwq);
+ }
+ return res;
+}
+
+kern_return_t
+ksyn_signal(ksyn_wait_queue_t kwq,
+ int kqi,
+ ksyn_waitq_element_t kwe,
+ uint32_t updateval)
+{
+ kern_return_t ret;
+
+ // If no wait element was specified, wake the first.
+ if (!kwe) {
+ kwe = TAILQ_FIRST(&kwq->kw_ksynqueues[kqi].ksynq_kwelist);
+ if (!kwe) {
+ panic("ksyn_signal: panic signaling empty queue");
+ }
+ }
+
+ if (kwe->kwe_state != KWE_THREAD_INWAIT) {
+ panic("ksyn_signal: panic signaling non-waiting element");
+ }
+
+ ksyn_queue_remove_item(kwq, &kwq->kw_ksynqueues[kqi], kwe);
+ kwe->kwe_psynchretval = updateval;
+
+ ret = thread_wakeup_one((caddr_t)&kwe->kwe_psynchretval);
+ if (ret != KERN_SUCCESS && ret != KERN_NOT_WAITING) {
+ panic("ksyn_signal: panic waking up thread %x\n", ret);
+ }
+ return ret;
+}
+
+int
+ksyn_findobj(user_addr_t uaddr, uint64_t *objectp, uint64_t *offsetp)
+{
+ kern_return_t ret;
+ vm_page_info_basic_data_t info;
+ mach_msg_type_number_t count = VM_PAGE_INFO_BASIC_COUNT;
+ ret = pthread_kern->vm_map_page_info(pthread_kern->current_map(), uaddr, VM_PAGE_INFO_BASIC, (vm_page_info_t)&info, &count);
+ if (ret != KERN_SUCCESS) {
+ return EINVAL;
+ }
+
+ if (objectp != NULL) {
+ *objectp = (uint64_t)info.object_id;
+ }
+ if (offsetp != NULL) {
+ *offsetp = (uint64_t)info.offset;
+ }
+
+ return(0);
+}
+
+
+/* lowest of kw_fr, kw_flr, kw_fwr, kw_fywr */
+int
+kwq_find_rw_lowest(ksyn_wait_queue_t kwq, int flags, uint32_t premgen, int *typep, uint32_t lowest[])
+{
+ uint32_t kw_fr, kw_fwr, low;
+ int type = 0, lowtype, typenum[2] = { 0 };
+ uint32_t numbers[2] = { 0 };
+ int count = 0, i;
+
+
+ if ((kwq->kw_ksynqueues[KSYN_QUEUE_READ].ksynq_count != 0) || ((flags & KW_UNLOCK_PREPOST_READLOCK) != 0)) {
+ type |= PTH_RWSHFT_TYPE_READ;
+ /* read entries are present */
+ if (kwq->kw_ksynqueues[KSYN_QUEUE_READ].ksynq_count != 0) {
+ kw_fr = kwq->kw_ksynqueues[KSYN_QUEUE_READ].ksynq_firstnum;
+ if (((flags & KW_UNLOCK_PREPOST_READLOCK) != 0) && (is_seqlower(premgen, kw_fr) != 0))
+ kw_fr = premgen;
+ } else
+ kw_fr = premgen;
+
+ lowest[KSYN_QUEUE_READ] = kw_fr;
+ numbers[count]= kw_fr;
+ typenum[count] = PTH_RW_TYPE_READ;
+ count++;
+ } else
+ lowest[KSYN_QUEUE_READ] = 0;
+
+ if ((kwq->kw_ksynqueues[KSYN_QUEUE_WRITER].ksynq_count != 0) || ((flags & KW_UNLOCK_PREPOST_WRLOCK) != 0)) {
+ type |= PTH_RWSHFT_TYPE_WRITE;
+ /* read entries are present */
+ if (kwq->kw_ksynqueues[KSYN_QUEUE_WRITER].ksynq_count != 0) {
+ kw_fwr = kwq->kw_ksynqueues[KSYN_QUEUE_WRITER].ksynq_firstnum;
+ if (((flags & KW_UNLOCK_PREPOST_WRLOCK) != 0) && (is_seqlower(premgen, kw_fwr) != 0))
+ kw_fwr = premgen;
+ } else
+ kw_fwr = premgen;
+
+ lowest[KSYN_QUEUE_WRITER] = kw_fwr;
+ numbers[count]= kw_fwr;
+ typenum[count] = PTH_RW_TYPE_WRITE;
+ count++;
+ } else
+ lowest[KSYN_QUEUE_WRITER] = 0;
+
+#if __TESTPANICS__
+ if (count == 0)
+ panic("nothing in the queue???\n");
+#endif /* __TESTPANICS__ */
+
+ low = numbers[0];
+ lowtype = typenum[0];
+ if (count > 1) {
+ for (i = 1; i< count; i++) {
+ if (is_seqlower(numbers[i] , low) != 0) {
+ low = numbers[i];
+ lowtype = typenum[i];
+ }
+ }
+ }
+ type |= lowtype;
+
+ if (typep != 0)
+ *typep = type;
+ return(0);
+}
+
+/* wakeup readers to upto the writer limits */
+int
+ksyn_wakeupreaders(ksyn_wait_queue_t kwq, uint32_t limitread, int allreaders, uint32_t updatebits, int *wokenp)
+{
+ ksyn_queue_t kq;
+ int failedwakeup = 0;
+ int numwoken = 0;
+ kern_return_t kret = KERN_SUCCESS;
+ uint32_t lbits = 0;
+
+ lbits = updatebits;
+
+ kq = &kwq->kw_ksynqueues[KSYN_QUEUE_READ];
+ while ((kq->ksynq_count != 0) && (allreaders || (is_seqlower(kq->ksynq_firstnum, limitread) != 0))) {
+ kret = ksyn_signal(kwq, KSYN_QUEUE_READ, NULL, lbits);
+ if (kret == KERN_NOT_WAITING) {
+ failedwakeup++;
+ }
+ numwoken++;
+ }
+
+ if (wokenp != NULL)
+ *wokenp = numwoken;
+ return(failedwakeup);
+}
+
+
+/* This handles the unlock grants for next set on rw_unlock() or on arrival of all preposted waiters */
+int
+kwq_handle_unlock(ksyn_wait_queue_t kwq,
+ __unused uint32_t mgen,
+ uint32_t rw_wc,
+ uint32_t *updatep,
+ int flags,
+ int *blockp,
+ uint32_t premgen)
+{
+ uint32_t low_writer, limitrdnum;
+ int rwtype, error=0;
+ int allreaders, failed;
+ uint32_t updatebits=0, numneeded = 0;;
+ int prepost = flags & KW_UNLOCK_PREPOST;
+ thread_t preth = THREAD_NULL;
+ ksyn_waitq_element_t kwe;
+ uthread_t uth;
+ thread_t th;
+ int woken = 0;
+ int block = 1;
+ uint32_t lowest[KSYN_QUEUE_MAX]; /* np need for upgrade as it is handled separately */
+ kern_return_t kret = KERN_SUCCESS;
+ ksyn_queue_t kq;
+ int curthreturns = 0;
+
+ if (prepost != 0) {
+ preth = current_thread();
+ }
+
+ kq = &kwq->kw_ksynqueues[KSYN_QUEUE_READ];
+ kwq->kw_lastseqword = rw_wc;
+ kwq->kw_lastunlockseq = (rw_wc & PTHRW_COUNT_MASK);
+ kwq->kw_overlapwatch = 0;
+
+ error = kwq_find_rw_lowest(kwq, flags, premgen, &rwtype, lowest);
+#if __TESTPANICS__
+ if (error != 0)
+ panic("rwunlock: cannot fails to slot next round of threads");
+#endif /* __TESTPANICS__ */
+
+ low_writer = lowest[KSYN_QUEUE_WRITER];
+
+ allreaders = 0;
+ updatebits = 0;
+
+ switch (rwtype & PTH_RW_TYPE_MASK) {
+ case PTH_RW_TYPE_READ: {
+ // XXX
+ /* what about the preflight which is LREAD or READ ?? */
+ if ((rwtype & PTH_RWSHFT_TYPE_MASK) != 0) {
+ if (rwtype & PTH_RWSHFT_TYPE_WRITE) {
+ updatebits |= (PTH_RWL_WBIT | PTH_RWL_KBIT);
+ }
+ }
+ limitrdnum = 0;
+ if ((rwtype & PTH_RWSHFT_TYPE_WRITE) != 0) {
+ limitrdnum = low_writer;
+ } else {
+ allreaders = 1;
+ }
+
+ numneeded = 0;
+
+ if ((rwtype & PTH_RWSHFT_TYPE_WRITE) != 0) {
+ limitrdnum = low_writer;
+ numneeded = ksyn_queue_count_tolowest(kq, limitrdnum);
+ if (((flags & KW_UNLOCK_PREPOST_READLOCK) != 0) && (is_seqlower(premgen, limitrdnum) != 0)) {
+ curthreturns = 1;
+ numneeded += 1;
+ }
+ } else {
+ // no writers at all
+ // no other waiters only readers
+ kwq->kw_overlapwatch = 1;
+ numneeded += kwq->kw_ksynqueues[KSYN_QUEUE_READ].ksynq_count;
+ if ((flags & KW_UNLOCK_PREPOST_READLOCK) != 0) {
+ curthreturns = 1;
+ numneeded += 1;
+ }
+ }
+
+ updatebits += (numneeded << PTHRW_COUNT_SHIFT);
+
+ kwq->kw_nextseqword = (rw_wc & PTHRW_COUNT_MASK) + updatebits;
+
+ if (curthreturns != 0) {
+ block = 0;
+ uth = current_uthread();
+ kwe = pthread_kern->uthread_get_uukwe(uth);
+ kwe->kwe_psynchretval = updatebits;
+ }
+
+
+ failed = ksyn_wakeupreaders(kwq, limitrdnum, allreaders, updatebits, &woken);
+ if (failed != 0) {
+ kwq->kw_pre_intrcount = failed; /* actually a count */
+ kwq->kw_pre_intrseq = limitrdnum;
+ kwq->kw_pre_intrretbits = updatebits;
+ kwq->kw_pre_intrtype = PTH_RW_TYPE_READ;
+ }
+
+ error = 0;
+
+ if ((kwq->kw_ksynqueues[KSYN_QUEUE_WRITER].ksynq_count != 0) && ((updatebits & PTH_RWL_WBIT) == 0))
+ panic("kwq_handle_unlock: writer pending but no writebit set %x\n", updatebits);
+ }
+ break;
+
+ case PTH_RW_TYPE_WRITE: {
+
+ /* only one thread is goin to be granted */
+ updatebits |= (PTHRW_INC);
+ updatebits |= PTH_RWL_KBIT| PTH_RWL_EBIT;
+
+ if (((flags & KW_UNLOCK_PREPOST_WRLOCK) != 0) && (low_writer == premgen)) {
+ block = 0;
+ if (kwq->kw_ksynqueues[KSYN_QUEUE_WRITER].ksynq_count != 0) {
+ updatebits |= PTH_RWL_WBIT;
+ }
+ th = preth;
+ uth = pthread_kern->get_bsdthread_info(th);
+ kwe = pthread_kern->uthread_get_uukwe(uth);
+ kwe->kwe_psynchretval = updatebits;
+ } else {
+ /* we are not granting writelock to the preposting thread */
+ /* if there are writers present or the preposting write thread then W bit is to be set */
+ if (kwq->kw_ksynqueues[KSYN_QUEUE_WRITER].ksynq_count > 1 ||
+ (flags & KW_UNLOCK_PREPOST_WRLOCK) != 0) {
+ updatebits |= PTH_RWL_WBIT;
+ }
+ /* setup next in the queue */
+ kret = ksyn_signal(kwq, KSYN_QUEUE_WRITER, NULL, updatebits);
+ if (kret == KERN_NOT_WAITING) {
+ kwq->kw_pre_intrcount = 1; /* actually a count */
+ kwq->kw_pre_intrseq = low_writer;
+ kwq->kw_pre_intrretbits = updatebits;
+ kwq->kw_pre_intrtype = PTH_RW_TYPE_WRITE;
+ }
+ error = 0;
+ }
+ kwq->kw_nextseqword = (rw_wc & PTHRW_COUNT_MASK) + updatebits;
+ if ((updatebits & (PTH_RWL_KBIT | PTH_RWL_EBIT)) != (PTH_RWL_KBIT | PTH_RWL_EBIT))
+ panic("kwq_handle_unlock: writer lock granted but no ke set %x\n", updatebits);
+ }
+ break;
+
+ default:
+ panic("rwunlock: invalid type for lock grants");
+
+ };
+
+ if (updatep != NULL)
+ *updatep = updatebits;
+ if (blockp != NULL)
+ *blockp = block;
+ return(error);
+}
+
+/************* Indiv queue support routines ************************/
+void
+ksyn_queue_init(ksyn_queue_t kq)
+{
+ TAILQ_INIT(&kq->ksynq_kwelist);
+ kq->ksynq_count = 0;
+ kq->ksynq_firstnum = 0;
+ kq->ksynq_lastnum = 0;
+}
+
+int
+ksyn_queue_insert(ksyn_wait_queue_t kwq, int kqi, ksyn_waitq_element_t kwe, uint32_t mgen, int fit)
+{
+ ksyn_queue_t kq = &kwq->kw_ksynqueues[kqi];
+ uint32_t lockseq = mgen & PTHRW_COUNT_MASK;
+ int res = 0;
+
+ if (kwe->kwe_kwqqueue != NULL) {
+ panic("adding enqueued item to another queue");
+ }
+
+ if (kq->ksynq_count == 0) {
+ TAILQ_INSERT_HEAD(&kq->ksynq_kwelist, kwe, kwe_list);
+ kq->ksynq_firstnum = lockseq;
+ kq->ksynq_lastnum = lockseq;
+ } else if (fit == FIRSTFIT) {
+ /* TBD: if retry bit is set for mutex, add it to the head */
+ /* firstfit, arriving order */
+ TAILQ_INSERT_TAIL(&kq->ksynq_kwelist, kwe, kwe_list);
+ if (is_seqlower(lockseq, kq->ksynq_firstnum)) {
+ kq->ksynq_firstnum = lockseq;
+ }
+ if (is_seqhigher(lockseq, kq->ksynq_lastnum)) {
+ kq->ksynq_lastnum = lockseq;
+ }
+ } else if (lockseq == kq->ksynq_firstnum || lockseq == kq->ksynq_lastnum) {
+ /* During prepost when a thread is getting cancelled, we could have two with same seq */
+ res = EBUSY;
+ if (kwe->kwe_state == KWE_THREAD_PREPOST) {
+ ksyn_waitq_element_t tmp = ksyn_queue_find_seq(kwq, kq, lockseq);
+ if (tmp != NULL && tmp->kwe_uth != NULL && pthread_kern->uthread_is_cancelled(tmp->kwe_uth)) {
+ TAILQ_INSERT_TAIL(&kq->ksynq_kwelist, kwe, kwe_list);
+ res = 0;
+ }
+ }
+ } else if (is_seqlower(kq->ksynq_lastnum, lockseq)) { // XXX is_seqhigher
+ TAILQ_INSERT_TAIL(&kq->ksynq_kwelist, kwe, kwe_list);
+ kq->ksynq_lastnum = lockseq;
+ } else if (is_seqlower(lockseq, kq->ksynq_firstnum)) {
+ TAILQ_INSERT_HEAD(&kq->ksynq_kwelist, kwe, kwe_list);
+ kq->ksynq_firstnum = lockseq;
+ } else {
+ ksyn_waitq_element_t q_kwe, r_kwe;
+
+ res = ESRCH;
+ TAILQ_FOREACH_SAFE(q_kwe, &kq->ksynq_kwelist, kwe_list, r_kwe) {
+ if (is_seqhigher(q_kwe->kwe_lockseq, lockseq)) {
+ TAILQ_INSERT_BEFORE(q_kwe, kwe, kwe_list);
+ res = 0;
+ break;
+ }
+ }
+ }
+
+ if (res == 0) {
+ kwe->kwe_kwqqueue = kwq;
+ kq->ksynq_count++;
+ kwq->kw_inqueue++;
+ update_low_high(kwq, lockseq);
+ }
+ return res;
+}
+
+void
+ksyn_queue_remove_item(ksyn_wait_queue_t kwq, ksyn_queue_t kq, ksyn_waitq_element_t kwe)
+{
+ if (kq->ksynq_count == 0) {
+ panic("removing item from empty queue");
+ }
+
+ if (kwe->kwe_kwqqueue != kwq) {
+ panic("removing item from wrong queue");
+ }
+
+ TAILQ_REMOVE(&kq->ksynq_kwelist, kwe, kwe_list);
+ kwe->kwe_list.tqe_next = NULL;
+ kwe->kwe_list.tqe_prev = NULL;
+ kwe->kwe_kwqqueue = NULL;
+
+ if (--kq->ksynq_count > 0) {
+ ksyn_waitq_element_t tmp;
+ tmp = TAILQ_FIRST(&kq->ksynq_kwelist);
+ kq->ksynq_firstnum = tmp->kwe_lockseq & PTHRW_COUNT_MASK;
+ tmp = TAILQ_LAST(&kq->ksynq_kwelist, ksynq_kwelist_head);
+ kq->ksynq_lastnum = tmp->kwe_lockseq & PTHRW_COUNT_MASK;
+ } else {
+ kq->ksynq_firstnum = 0;
+ kq->ksynq_lastnum = 0;
+ }
+
+ if (--kwq->kw_inqueue > 0) {
+ uint32_t curseq = kwe->kwe_lockseq & PTHRW_COUNT_MASK;
+ if (kwq->kw_lowseq == curseq) {
+ kwq->kw_lowseq = find_nextlowseq(kwq);
+ }
+ if (kwq->kw_highseq == curseq) {
+ kwq->kw_highseq = find_nexthighseq(kwq);
+ }
+ } else {
+ kwq->kw_lowseq = 0;
+ kwq->kw_highseq = 0;
+ }
+}
+
+ksyn_waitq_element_t
+ksyn_queue_find_seq(__unused ksyn_wait_queue_t kwq, ksyn_queue_t kq, uint32_t seq)
+{
+ ksyn_waitq_element_t kwe;
+
+ // XXX: should stop searching when higher sequence number is seen
+ TAILQ_FOREACH(kwe, &kq->ksynq_kwelist, kwe_list) {
+ if ((kwe->kwe_lockseq & PTHRW_COUNT_MASK) == seq) {
+ return kwe;
+ }
+ }
+ return NULL;
+}
+
+/* find the thread at the target sequence (or a broadcast/prepost at or above) */
+ksyn_waitq_element_t
+ksyn_queue_find_cvpreposeq(ksyn_queue_t kq, uint32_t cgen)
+{
+ ksyn_waitq_element_t result = NULL;
+ ksyn_waitq_element_t kwe;
+ uint32_t lgen = (cgen & PTHRW_COUNT_MASK);
+
+ TAILQ_FOREACH(kwe, &kq->ksynq_kwelist, kwe_list) {
+ if (is_seqhigher_eq(kwe->kwe_lockseq, cgen)) {
+ result = kwe;
+
+ // KWE_THREAD_INWAIT must be strictly equal
+ if (kwe->kwe_state == KWE_THREAD_INWAIT && (kwe->kwe_lockseq & PTHRW_COUNT_MASK) != lgen) {
+ result = NULL;
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+/* look for a thread at lockseq, a */
+ksyn_waitq_element_t
+ksyn_queue_find_signalseq(__unused ksyn_wait_queue_t kwq, ksyn_queue_t kq, uint32_t uptoseq, uint32_t signalseq)
+{
+ ksyn_waitq_element_t result = NULL;
+ ksyn_waitq_element_t q_kwe, r_kwe;
+
+ // XXX
+ /* case where wrap in the tail of the queue exists */
+ TAILQ_FOREACH_SAFE(q_kwe, &kq->ksynq_kwelist, kwe_list, r_kwe) {
+ if (q_kwe->kwe_state == KWE_THREAD_PREPOST) {
+ if (is_seqhigher(q_kwe->kwe_lockseq, uptoseq)) {
+ return result;
+ }
+ }
+ if (q_kwe->kwe_state == KWE_THREAD_PREPOST || q_kwe->kwe_state == KWE_THREAD_BROADCAST) {
+ /* match any prepost at our same uptoseq or any broadcast above */
+ if (is_seqlower(q_kwe->kwe_lockseq, uptoseq)) {
+ continue;
+ }
+ return q_kwe;
+ } else if (q_kwe->kwe_state == KWE_THREAD_INWAIT) {
+ /*
+ * Match any (non-cancelled) thread at or below our upto sequence -
+ * but prefer an exact match to our signal sequence (if present) to
+ * keep exact matches happening.
+ */
+ if (is_seqhigher(q_kwe->kwe_lockseq, uptoseq)) {
+ return result;
+ }
+ if (q_kwe->kwe_kwqqueue == kwq) {
+ if (!pthread_kern->uthread_is_cancelled(q_kwe->kwe_uth)) {
+ /* if equal or higher than our signal sequence, return this one */
+ if (is_seqhigher_eq(q_kwe->kwe_lockseq, signalseq)) {
+ return q_kwe;
+ }
+
+ /* otherwise, just remember this eligible thread and move on */
+ if (result == NULL) {
+ result = q_kwe;
+ }
+ }
+ }
+ } else {
+ panic("ksyn_queue_find_signalseq(): unknown wait queue element type (%d)\n", q_kwe->kwe_state);
+ }
+ }
+ return result;
+}
+
+void
+ksyn_queue_free_items(ksyn_wait_queue_t kwq, int kqi, uint32_t upto, int all)
+{
+ ksyn_waitq_element_t kwe;
+ uint32_t tseq = upto & PTHRW_COUNT_MASK;
+ ksyn_queue_t kq = &kwq->kw_ksynqueues[kqi];
+
+ while ((kwe = TAILQ_FIRST(&kq->ksynq_kwelist)) != NULL) {
+ if (all == 0 && is_seqhigher(kwe->kwe_lockseq, tseq)) {
+ break;
+ }
+ if (kwe->kwe_state == KWE_THREAD_INWAIT) {
+ /*
+ * This scenario is typically noticed when the cvar is
+ * reinited and the new waiters are waiting. We can
+ * return them as spurious wait so the cvar state gets
+ * reset correctly.
+ */
+
+ /* skip canceled ones */
+ /* wake the rest */
+ /* set M bit to indicate to waking CV to retun Inc val */
+ (void)ksyn_signal(kwq, kqi, kwe, PTHRW_INC | PTH_RWS_CV_MBIT | PTH_RWL_MTX_WAIT);
+ } else {
+ ksyn_queue_remove_item(kwq, kq, kwe);
+ pthread_kern->zfree(kwe_zone, kwe);
+ kwq->kw_fakecount--;
+ }
+ }
+}
+
+/*************************************************************************/
+
+void
+update_low_high(ksyn_wait_queue_t kwq, uint32_t lockseq)
+{
+ if (kwq->kw_inqueue == 1) {
+ kwq->kw_lowseq = lockseq;
+ kwq->kw_highseq = lockseq;
+ } else {
+ if (is_seqlower(lockseq, kwq->kw_lowseq)) {
+ kwq->kw_lowseq = lockseq;
+ }
+ if (is_seqhigher(lockseq, kwq->kw_highseq)) {
+ kwq->kw_highseq = lockseq;
+ }
+ }
+}
+
+uint32_t
+find_nextlowseq(ksyn_wait_queue_t kwq)
+{
+ uint32_t lowest = 0;
+ int first = 1;
+ int i;
+
+ for (i = 0; i < KSYN_QUEUE_MAX; i++) {
+ if (kwq->kw_ksynqueues[i].ksynq_count > 0) {
+ uint32_t current = kwq->kw_ksynqueues[i].ksynq_firstnum;
+ if (first || is_seqlower(current, lowest)) {
+ lowest = current;
+ first = 0;
+ }
+ }
+ }
+
+ return lowest;
+}
+
+uint32_t
+find_nexthighseq(ksyn_wait_queue_t kwq)
+{
+ uint32_t highest = 0;
+ int first = 1;
+ int i;
+
+ for (i = 0; i < KSYN_QUEUE_MAX; i++) {
+ if (kwq->kw_ksynqueues[i].ksynq_count > 0) {
+ uint32_t current = kwq->kw_ksynqueues[i].ksynq_lastnum;
+ if (first || is_seqhigher(current, highest)) {
+ highest = current;
+ first = 0;
+ }
+ }
+ }
+
+ return highest;
+}
+
+int
+find_seq_till(ksyn_wait_queue_t kwq, uint32_t upto, uint32_t nwaiters, uint32_t *countp)
+{
+ int i;
+ uint32_t count = 0;
+
+ for (i = 0; i< KSYN_QUEUE_MAX; i++) {
+ count += ksyn_queue_count_tolowest(&kwq->kw_ksynqueues[i], upto);
+ if (count >= nwaiters) {
+ break;
+ }
+ }
+
+ if (countp != NULL) {
+ *countp = count;
+ }
+
+ if (count == 0) {
+ return 0;
+ } else if (count >= nwaiters) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+uint32_t
+ksyn_queue_count_tolowest(ksyn_queue_t kq, uint32_t upto)
+{
+ uint32_t i = 0;
+ ksyn_waitq_element_t kwe, newkwe;
+
+ if (kq->ksynq_count == 0 || is_seqhigher(kq->ksynq_firstnum, upto)) {
+ return 0;
+ }
+ if (upto == kq->ksynq_firstnum) {
+ return 1;
+ }
+ TAILQ_FOREACH_SAFE(kwe, &kq->ksynq_kwelist, kwe_list, newkwe) {
+ uint32_t curval = (kwe->kwe_lockseq & PTHRW_COUNT_MASK);
+ if (is_seqhigher(curval, upto)) {
+ break;
+ }
+ ++i;
+ if (upto == curval) {
+ break;
+ }
+ }
+ return i;
+}
+
+/* handles the cond broadcast of cvar and returns number of woken threads and bits for syscall return */
+void
+ksyn_handle_cvbroad(ksyn_wait_queue_t ckwq, uint32_t upto, uint32_t *updatep)
+{
+ ksyn_waitq_element_t kwe, newkwe;
+ uint32_t updatebits = 0;
+ ksyn_queue_t kq = &ckwq->kw_ksynqueues[KSYN_QUEUE_WRITER];
+
+ struct ksyn_queue kfreeq;
+ ksyn_queue_init(&kfreeq);
+
+retry:
+ TAILQ_FOREACH_SAFE(kwe, &kq->ksynq_kwelist, kwe_list, newkwe) {
+ if (is_seqhigher(kwe->kwe_lockseq, upto)) {
+ // outside our range
+ break;
+ }
+
+ if (kwe->kwe_state == KWE_THREAD_INWAIT) {
+ // Wake only non-canceled threads waiting on this CV.
+ if (!pthread_kern->uthread_is_cancelled(kwe->kwe_uth)) {
+ (void)ksyn_signal(ckwq, KSYN_QUEUE_WRITER, kwe, PTH_RWL_MTX_WAIT);
+ updatebits += PTHRW_INC;
+ }
+ } else if (kwe->kwe_state == KWE_THREAD_BROADCAST ||
+ kwe->kwe_state == KWE_THREAD_PREPOST) {
+ ksyn_queue_remove_item(ckwq, kq, kwe);
+ TAILQ_INSERT_TAIL(&kfreeq.ksynq_kwelist, kwe, kwe_list);
+ ckwq->kw_fakecount--;
+ } else {
+ panic("unknown kwe state\n");
+ }
+ }
+
+ /* Need to enter a broadcast in the queue (if not already at L == S) */
+
+ if (diff_genseq(ckwq->kw_lword, ckwq->kw_sword)) {
+ newkwe = TAILQ_FIRST(&kfreeq.ksynq_kwelist);
+ if (newkwe == NULL) {
+ ksyn_wqunlock(ckwq);
+ newkwe = (ksyn_waitq_element_t)pthread_kern->zalloc(kwe_zone);
+ TAILQ_INSERT_TAIL(&kfreeq.ksynq_kwelist, newkwe, kwe_list);
+ ksyn_wqlock(ckwq);
+ goto retry;
+ } else {
+ TAILQ_REMOVE(&kfreeq.ksynq_kwelist, newkwe, kwe_list);
+ ksyn_prepost(ckwq, newkwe, KWE_THREAD_BROADCAST, upto);
+ }
+ }
+
+ // free up any remaining things stumbled across above
+ while ((kwe = TAILQ_FIRST(&kfreeq.ksynq_kwelist)) != NULL) {
+ TAILQ_REMOVE(&kfreeq.ksynq_kwelist, kwe, kwe_list);
+ pthread_kern->zfree(kwe_zone, kwe);
+ }
+
+ if (updatep != NULL) {
+ *updatep = updatebits;
+ }
+}
+
+void
+ksyn_cvupdate_fixup(ksyn_wait_queue_t ckwq, uint32_t *updatebits)
+{
+ if ((ckwq->kw_lword & PTHRW_COUNT_MASK) == (ckwq->kw_sword & PTHRW_COUNT_MASK)) {
+ if (ckwq->kw_inqueue != 0) {
+ /* FREE THE QUEUE */
+ ksyn_queue_free_items(ckwq, KSYN_QUEUE_WRITER, ckwq->kw_lword, 0);
+#if __TESTPANICS__
+ if (ckwq->kw_inqueue != 0)
+ panic("ksyn_cvupdate_fixup: L == S, but entries in queue beyond S");
+#endif /* __TESTPANICS__ */
+ }
+ ckwq->kw_lword = ckwq->kw_uword = ckwq->kw_sword = 0;
+ ckwq->kw_kflags |= KSYN_KWF_ZEROEDOUT;
+ *updatebits |= PTH_RWS_CV_CBIT;
+ } else if (ckwq->kw_inqueue != 0 && ckwq->kw_fakecount == ckwq->kw_inqueue) {
+ // only fake entries are present in the queue
+ *updatebits |= PTH_RWS_CV_PBIT;
+ }
+}
+
+void
+psynch_zoneinit(void)
+{
+ kwq_zone = (zone_t)pthread_kern->zinit(sizeof(struct ksyn_wait_queue), 8192 * sizeof(struct ksyn_wait_queue), 4096, "ksyn_wait_queue");
+ kwe_zone = (zone_t)pthread_kern->zinit(sizeof(struct ksyn_waitq_element), 8192 * sizeof(struct ksyn_waitq_element), 4096, "ksyn_waitq_element");
+}
--- /dev/null
+/*
+ * Copyright (c) 2000-2003 Apple Computer, 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 _KERN_TRACE_H_
+#define _KERN_TRACE_H_
+
+/* pthread kext, or userspace, kdebug trace points. Defined here and output to
+ * /usr/share/misc/pthread.codes during build.
+ */
+
+// pthread tracing subclasses
+# define _TRACE_SUB_DEFAULT 0
+# define _TRACE_SUB_WORKQUEUE 1
+# define _TRACE_SUB_MUTEX 2
+
+#ifndef _PTHREAD_BUILDING_CODES_
+
+#include <sys/kdebug.h>
+
+#ifndef DBG_PTHREAD
+#define DBG_PTHREAD DBG_WORKQUEUE
+#endif
+
+#if KERNEL
+extern uint32_t pthread_debug_tracing;
+
+# define PTHREAD_TRACE(x,a,b,c,d,e) \
+ { if (pthread_debug_tracing) { KERNEL_DEBUG_CONSTANT(x, a, b, c, d, e); } }
+
+# define PTHREAD_TRACE1(x,a,b,c,d,e) \
+ { if (pthread_debug_tracing) { KERNEL_DEBUG_CONSTANT1(x, a, b, c, d, e); } }
+#endif
+
+# define TRACE_CODE(name, subclass, code) \
+ static const int TRACE_##name = KDBG_CODE(DBG_PTHREAD, subclass, code)
+
+#else
+/* When not included as a header, this file is pre-processed into perl source to generate
+ * the pthread.codes file during build.
+ */
+# define DBG_PTHREAD 9
+# define STR(x) #x
+
+# define TRACE_CODE(name, subclass, code) \
+ printf("0x%x\t%s\n", ((DBG_PTHREAD << 24) | ((subclass & 0xff) << 16) | ((code & 0x3fff) << 2)), STR(name))
+#endif
+
+/* These defines translate into TRACE_<name> when used in source code, and are
+ * pre-processed out to a codes file by the build system.
+ */
+
+// "default" trace points
+TRACE_CODE(pthread_thread_create, _TRACE_SUB_DEFAULT, 0x10);
+TRACE_CODE(pthread_thread_terminate, _TRACE_SUB_DEFAULT, 0x20);
+TRACE_CODE(pthread_set_qos_self, _TRACE_SUB_DEFAULT, 0x30);
+
+// workqueue trace points
+TRACE_CODE(wq_pthread_exit, _TRACE_SUB_WORKQUEUE, 0x01);
+TRACE_CODE(wq_workqueue_exit, _TRACE_SUB_WORKQUEUE, 0x02);
+TRACE_CODE(wq_run_nextitem, _TRACE_SUB_WORKQUEUE, 0x03);
+TRACE_CODE(wq_runitem, _TRACE_SUB_WORKQUEUE, 0x04);
+TRACE_CODE(wq_req_threads, _TRACE_SUB_WORKQUEUE, 0x05);
+TRACE_CODE(wq_req_octhreads, _TRACE_SUB_WORKQUEUE, 0x06);
+TRACE_CODE(wq_thread_suspend, _TRACE_SUB_WORKQUEUE, 0x07);
+TRACE_CODE(wq_thread_park, _TRACE_SUB_WORKQUEUE, 0x08);
+TRACE_CODE(wq_thread_block, _TRACE_SUB_WORKQUEUE, 0x9);
+TRACE_CODE(wq_new_max_scheduled, _TRACE_SUB_WORKQUEUE, 0xa);
+TRACE_CODE(wq_add_timer, _TRACE_SUB_WORKQUEUE, 0xb);
+TRACE_CODE(wq_start_add_timer, _TRACE_SUB_WORKQUEUE, 0x0c);
+TRACE_CODE(wq_stalled, _TRACE_SUB_WORKQUEUE, 0x0d);
+TRACE_CODE(wq_reset_priority, _TRACE_SUB_WORKQUEUE, 0x0e);
+TRACE_CODE(wq_thread_yielded, _TRACE_SUB_WORKQUEUE, 0x0f);
+TRACE_CODE(wq_delay_octhreads, _TRACE_SUB_WORKQUEUE, 0x10);
+TRACE_CODE(wq_overcommitted, _TRACE_SUB_WORKQUEUE, 0x11);
+TRACE_CODE(wq_override_start, _TRACE_SUB_WORKQUEUE, 0x12);
+TRACE_CODE(wq_override_end, _TRACE_SUB_WORKQUEUE, 0x13);
+TRACE_CODE(wq_override_dispatch, _TRACE_SUB_WORKQUEUE, 0x14);
+TRACE_CODE(wq_override_reset, _TRACE_SUB_WORKQUEUE, 0x15);
+
+// synch trace points
+TRACE_CODE(psynch_mutex_ulock, _TRACE_SUB_MUTEX, 0x0);
+TRACE_CODE(psynch_mutex_utrylock_failed, _TRACE_SUB_MUTEX, 0x1);
+TRACE_CODE(psynch_mutex_uunlock, _TRACE_SUB_MUTEX, 0x2);
+TRACE_CODE(psynch_ksyn_incorrect_owner, _TRACE_SUB_MUTEX, 0x3);
+
+#endif // _KERN_TRACE_H_
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>OSBundleRequired</key>
+ <string>Root</string>
+ <key>AppleKernelExternalComponent</key>
+ <true/>
+ <key>OSBundleAllowUserLoad</key>
+ <true/>
+ <key>OSBundleCompatibleVersion</key>
+ <string>1.0</string>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>English</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string></string>
+ <key>CFBundleIdentifier</key>
+ <string>${MODULE_NAME}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>KEXT</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>NSHumanReadableCopyright</key>
+ <string>Copyright © 2012 Apple Inc. All rights reserved.</string>
+ <key>OSBundleLibraries</key>
+ <dict>
+ <key>com.apple.kpi.bsd</key>
+ <string>12.0</string>
+ <key>com.apple.kpi.libkern</key>
+ <string>11.2</string>
+ <key>com.apple.kpi.mach</key>
+ <string>11.2</string>
+ <key>com.apple.kpi.private</key>
+ <string>11.2</string>
+ <key>com.apple.kpi.unsupported</key>
+ <string>11.2</string>
+ </dict>
+</dict>
+</plist>
--- /dev/null
+/*
+ * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#ifndef __SYNCH_INTERNAL_H__
+#define __SYNCH_INTERNAL_H__
+
+
+#define _PTHREAD_MTX_OPT_PSHARED 0x010
+#define _PTHREAD_MTX_OPT_NOTIFY 0x1000 /* notify to drop mutex handling in cvwait */
+#define _PTHREAD_MTX_OPT_MUTEX 0x2000 /* this is a mutex type */
+
+
+#define PTHRW_COUNT_SHIFT 8
+#define PTHRW_INC (1 << PTHRW_COUNT_SHIFT)
+#define PTHRW_BIT_MASK ((1 << PTHRW_COUNT_SHIFT) - 1)
+#define PTHRW_COUNT_MASK ((uint32_t)~PTHRW_BIT_MASK)
+#define PTHRW_MAX_READERS PTHRW_COUNT_MASK
+
+// L word
+#define PTH_RWL_KBIT 0x01 // cannot acquire in user mode
+#define PTH_RWL_EBIT 0x02 // exclusive lock in progress
+#define PTH_RWL_WBIT 0x04 // write waiters pending in kernel
+#define PTH_RWL_PBIT 0x04 // prepost (cv) pending in kernel
+
+#define PTH_RWL_MTX_WAIT 0x20 // in cvar in mutex wait
+#define PTH_RWL_RBIT 0x40 // reader pending in kernel (not used)
+#define PTH_RWL_MBIT 0x40 // overlapping grants from kernel
+#define PTH_RWL_IBIT 0x80 // lock reset, held until first successful unlock
+
+#define PTHRW_RWL_INIT PTH_RWL_IBIT // reset on the lock bits (U)
+#define PTHRW_RWLOCK_INIT (PTH_RWL_IBIT | PTH_RWL_RBIT) // reset on the lock bits (U)
+#define PTH_RWLOCK_RESET_RBIT ((uint32_t)~PTH_RWL_RBIT)
+
+// S word
+#define PTH_RWS_SBIT 0x01 // kernel transition seq not set yet
+#define PTH_RWS_IBIT 0x02 // Sequence is not set on return from kernel
+
+#define PTH_RWS_CV_CBIT PTH_RWS_SBIT // kernel has cleared all info w.r.s.t CV
+#define PTH_RWS_CV_PBIT PTH_RWS_IBIT // kernel has prepost/fake structs only,no waiters
+#define PTH_RWS_CV_BITSALL (PTH_RWS_CV_CBIT | PTH_RWS_CV_PBIT)
+#define PTH_RWS_CV_MBIT PTH_RWL_MBIT // to indicate prepost return from kernel
+#define PTH_RWS_CV_RESET_PBIT ((uint32_t)~PTH_RWS_CV_PBIT)
+
+#define PTH_RWS_WSVBIT 0x04 // save W bit
+
+#define PTHRW_RWS_SAVEMASK (PTH_RWS_WSVBIT) // save bits mask
+
+#define PTHRW_RWS_INIT PTH_RWS_SBIT // reset on the lock bits (U)
+#define PTHRW_SW_Reset_BIT_MASK (PTHRW_BIT_MASK & ~PTH_RWS_SBIT) // All bits except the S bit
+
+// rw_flags
+#define PTHRW_KERN_PROCESS_SHARED 0x10
+#define PTHRW_KERN_PROCESS_PRIVATE 0x20
+
+#define PTHREAD_MTX_TID_SWITCHING (uint64_t)-1
+
+// L word tests
+#define can_rwl_readinuser(x) (((x) & (PTH_RWL_WBIT | PTH_RWL_KBIT)) == 0)
+#define is_rwl_ebit_set(x) (((x) & PTH_RWL_EBIT) != 0)
+#define is_rwl_wbit_set(x) (((x) & PTH_RWL_WBIT) != 0)
+#define is_rwl_ebit_clear(x) (((x) & PTH_RWL_EBIT) == 0)
+#define is_rwl_readoverlap(x) (((x) & PTH_RWL_MBIT) != 0)
+
+// S word tests
+#define is_rws_setseq(x) (((x) & PTH_RWS_SBIT))
+#define is_rws_setunlockinit(x) (((x) & PTH_RWS_IBIT))
+
+static inline int
+is_seqlower(uint32_t x, uint32_t y)
+{
+ x &= PTHRW_COUNT_MASK;
+ y &= PTHRW_COUNT_MASK;
+ if (x < y) {
+ return ((y - x) < (PTHRW_MAX_READERS / 2));
+ } else {
+ return ((x - y) > (PTHRW_MAX_READERS / 2));
+ }
+}
+
+static inline int
+is_seqlower_eq(uint32_t x, uint32_t y)
+{
+ if ((x & PTHRW_COUNT_MASK) == (y & PTHRW_COUNT_MASK)) {
+ return 1;
+ } else {
+ return is_seqlower(x, y);
+ }
+}
+
+static inline int
+is_seqhigher(uint32_t x, uint32_t y)
+{
+ x &= PTHRW_COUNT_MASK;
+ y &= PTHRW_COUNT_MASK;
+ if (x > y) {
+ return ((x - y) < (PTHRW_MAX_READERS / 2));
+ } else {
+ return ((y - x) > (PTHRW_MAX_READERS / 2));
+ }
+}
+
+static inline int
+is_seqhigher_eq(uint32_t x, uint32_t y)
+{
+ if ((x & PTHRW_COUNT_MASK) == (y & PTHRW_COUNT_MASK)) {
+ return 1;
+ } else {
+ return is_seqhigher(x,y);
+ }
+}
+
+static inline int
+diff_genseq(uint32_t x, uint32_t y)
+{
+ x &= PTHRW_COUNT_MASK;
+ y &= PTHRW_COUNT_MASK;
+ if (x == y) {
+ return 0;
+ } else if (x > y) {
+ return x - y;
+ } else {
+ return ((PTHRW_MAX_READERS - y) + x + PTHRW_INC);
+ }
+}
+
+static inline int
+find_diff(uint32_t upto, uint32_t lowest)
+{
+ uint32_t diff;
+
+ if (upto == lowest)
+ return(0);
+#if 0
+ diff = diff_genseq(upto, lowest);
+#else
+ if (is_seqlower(upto, lowest) != 0)
+ diff = diff_genseq(lowest, upto);
+ else
+ diff = diff_genseq(upto, lowest);
+#endif
+ diff = (diff >> PTHRW_COUNT_SHIFT);
+ return(diff);
+}
+
+#endif /* __SYNCH_INTERNAL_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2014 Apple Computer, 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 _WORKQUEUE_INTERNAL_H_
+#define _WORKQUEUE_INTERNAL_H_
+
+/* These definitions are shared between the kext and userspace inside the pthread project. Consolidating
+ * duplicate definitions that used to exist in both projects, when separate.
+ */
+
+/* workq_kernreturn commands */
+#define WQOPS_THREAD_RETURN 4
+#define WQOPS_QUEUE_NEWSPISUPP 0x10 /* this is to check for newer SPI support */
+#define WQOPS_QUEUE_REQTHREADS 0x20 /* request number of threads of a prio */
+#define WQOPS_QUEUE_REQTHREADS2 0x30 /* request a number of threads in a given priority bucket */
+
+/* flag values for reuse field in the libc side _pthread_wqthread */
+#define WQ_FLAG_THREAD_PRIOMASK 0x0000ffff
+#define WQ_FLAG_THREAD_PRIOSHIFT (8ull)
+#define WQ_FLAG_THREAD_OVERCOMMIT 0x00010000 /* thread is with overcommit prio */
+#define WQ_FLAG_THREAD_REUSE 0x00020000 /* thread is being reused */
+#define WQ_FLAG_THREAD_NEWSPI 0x00040000 /* the call is with new SPIs */
+
+/* These definitions are only available to the kext, to avoid bleeding constants and types across the boundary to
+ * the userspace library.
+ */
+#ifdef KERNEL
+
+/* These defines come from kern/thread.h but are XNU_KERNEL_PRIVATE so do not get
+ * exported to kernel extensions.
+ */
+#define SCHED_CALL_BLOCK 0x1
+#define SCHED_CALL_UNBLOCK 0x2
+
+// kwe_state
+enum {
+ KWE_THREAD_INWAIT = 1,
+ KWE_THREAD_PREPOST,
+ KWE_THREAD_BROADCAST,
+};
+
+/* old workq priority scheme */
+
+#define WORKQUEUE_HIGH_PRIOQUEUE 0 /* high priority queue */
+#define WORKQUEUE_DEFAULT_PRIOQUEUE 1 /* default priority queue */
+#define WORKQUEUE_LOW_PRIOQUEUE 2 /* low priority queue */
+#define WORKQUEUE_BG_PRIOQUEUE 3 /* background priority queue */
+
+#define WORKQUEUE_NUM_BUCKETS 6
+
+/* wq_max_constrained_threads = max(64, N_CPU * WORKQUEUE_CONSTRAINED_FACTOR)
+ * This used to be WORKQUEUE_NUM_BUCKETS + 1 when NUM_BUCKETS was 4, yielding
+ * N_CPU * 5. When NUM_BUCKETS changed, we decided that the limit should
+ * not change. So the factor is now always 5.
+ */
+#define WORKQUEUE_CONSTRAINED_FACTOR 5
+
+#define WORKQUEUE_OVERCOMMIT 0x10000
+
+struct threadlist {
+ TAILQ_ENTRY(threadlist) th_entry;
+ thread_t th_thread;
+ int th_flags;
+ uint8_t th_priority;
+ uint8_t th_policy;
+ struct workqueue *th_workq;
+ mach_vm_size_t th_stacksize;
+ mach_vm_size_t th_allocsize;
+ mach_vm_offset_t th_stackaddr;
+ mach_port_name_t th_thport;
+ uint32_t th_override_count;
+ uint32_t th_dispatch_override_count;
+};
+#define TH_LIST_INITED 0x01
+#define TH_LIST_RUNNING 0x02
+#define TH_LIST_BLOCKED 0x04
+#define TH_LIST_SUSPENDED 0x08
+#define TH_LIST_BUSY 0x10
+#define TH_LIST_NEED_WAKEUP 0x20
+#define TH_LIST_CONSTRAINED 0x40
+
+
+struct workqueue {
+ proc_t wq_proc;
+ vm_map_t wq_map;
+ task_t wq_task;
+ thread_call_t wq_atimer_call;
+ int wq_flags;
+ int wq_lflags;
+ uint64_t wq_thread_yielded_timestamp;
+ uint32_t wq_thread_yielded_count;
+ uint32_t wq_timer_interval;
+ uint32_t wq_max_concurrency;
+ uint32_t wq_threads_scheduled;
+ uint32_t wq_constrained_threads_scheduled;
+ uint32_t wq_nthreads;
+ uint32_t wq_thidlecount;
+ uint32_t wq_reqcount;
+ TAILQ_HEAD(, threadlist) wq_thrunlist;
+ TAILQ_HEAD(, threadlist) wq_thidlelist;
+ uint16_t wq_requests[WORKQUEUE_NUM_BUCKETS];
+ uint16_t wq_ocrequests[WORKQUEUE_NUM_BUCKETS];
+ uint16_t wq_reqconc[WORKQUEUE_NUM_BUCKETS]; /* requested concurrency for each priority level */
+ uint16_t wq_thscheduled_count[WORKQUEUE_NUM_BUCKETS];
+ uint32_t wq_thactive_count[WORKQUEUE_NUM_BUCKETS] __attribute__((aligned(4))); /* must be uint32_t since we OSAddAtomic on these */
+ uint64_t wq_lastblocked_ts[WORKQUEUE_NUM_BUCKETS] __attribute__((aligned(8)));
+};
+#define WQ_LIST_INITED 0x01
+#define WQ_ATIMER_RUNNING 0x02
+#define WQ_EXITING 0x04
+
+#define WQL_ATIMER_BUSY 0x01
+#define WQL_ATIMER_WAITING 0x02
+#define WQL_EXCEEDED_CONSTRAINED_THREAD_LIMIT 0x04
+#define WQL_EXCEEDED_TOTAL_THREAD_LIMIT 0x08
+
+
+#define WQ_VECT_SET_BIT(vector, bit) \
+ vector[(bit) / 32] |= (1 << ((bit) % 32))
+
+#define WQ_VECT_CLEAR_BIT(vector, bit) \
+ vector[(bit) / 32] &= ~(1 << ((bit) % 32))
+
+#define WQ_VECT_TEST_BIT(vector, bit) \
+ vector[(bit) / 32] & (1 << ((bit) % 32))
+
+#define WORKQUEUE_MAXTHREADS 512
+#define WQ_YIELDED_THRESHOLD 2000
+#define WQ_YIELDED_WINDOW_USECS 30000
+#define WQ_STALLED_WINDOW_USECS 200
+#define WQ_REDUCE_POOL_WINDOW_USECS 5000000
+#define WQ_MAX_TIMER_INTERVAL_USECS 50000
+
+#endif // KERNEL
+
+#endif // _WORKQUEUE_INTERNAL_H_
--- /dev/null
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 46;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ C90E7AAC15DC3D3300A06D48 /* All */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = C90E7AAD15DC3D3300A06D48 /* Build configuration list for PBXAggregateTarget "All" */;
+ buildPhases = (
+ );
+ dependencies = (
+ C90E7AB015DC3D3D00A06D48 /* PBXTargetDependency */,
+ C90E7AB215DC3D3D00A06D48 /* PBXTargetDependency */,
+ );
+ name = All;
+ productName = All;
+ };
+ C91D01B5162892FF0002E29A /* Kext */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = C91D01B6162892FF0002E29A /* Build configuration list for PBXAggregateTarget "Kext" */;
+ buildPhases = (
+ );
+ dependencies = (
+ C91D01B9162893070002E29A /* PBXTargetDependency */,
+ );
+ name = Kext;
+ productName = Kext;
+ };
+ C98832C115DEB44000B3308E /* Embedded */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = C98832C315DEB44000B3308E /* Build configuration list for PBXAggregateTarget "Embedded" */;
+ buildPhases = (
+ );
+ dependencies = (
+ C98832C615DEB44B00B3308E /* PBXTargetDependency */,
+ C98832C815DEB44B00B3308E /* PBXTargetDependency */,
+ 74E594AB1613AD7F006C417B /* PBXTargetDependency */,
+ C91D01BC162CA80F0002E29A /* PBXTargetDependency */,
+ );
+ name = Embedded;
+ productName = Embedded;
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 74E594931613AAF4006C417B /* pthread.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FA15B7513200270056 /* pthread.c */; };
+ 74E594941613AAF4006C417B /* pthread_cancelable.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F115B7513200270056 /* pthread_cancelable.c */; };
+ 74E594951613AAF4006C417B /* pthread_cond.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F215B7513200270056 /* pthread_cond.c */; };
+ 74E594961613AAF4006C417B /* pthread_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F515B7513200270056 /* pthread_mutex.c */; };
+ 74E594971613AAF4006C417B /* pthread_rwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F615B7513200270056 /* pthread_rwlock.c */; };
+ 74E594981613AAF4006C417B /* pthread_support.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DC15C9D16B0098ECD8 /* pthread_support.c */; };
+ 74E594991613AAF4006C417B /* pthread_tsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F815B7513200270056 /* pthread_tsd.c */; };
+ 74E5949A1613AAF4006C417B /* thread_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FC15B7513200270056 /* thread_setup.c */; };
+ 74E5949C1613AAF4006C417B /* pthread_atfork.c in Sources */ = {isa = PBXBuildFile; fileRef = C90E7AB415DC40D900A06D48 /* pthread_atfork.c */; };
+ 74E5949E1613AAF4006C417B /* pthread_asm.s in Sources */ = {isa = PBXBuildFile; fileRef = C99AD87D15DF04D10009A6F8 /* pthread_asm.s */; };
+ 74E594A61613AB10006C417B /* pthread_cancelable_cancel.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A1BF5215C9A9F5006BB313 /* pthread_cancelable_cancel.c */; };
+ C90E7AA415DC3C9D00A06D48 /* pthread.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FA15B7513200270056 /* pthread.c */; };
+ C90E7AA515DC3C9D00A06D48 /* pthread_cancelable.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F115B7513200270056 /* pthread_cancelable.c */; };
+ C90E7AA615DC3C9D00A06D48 /* pthread_cond.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F215B7513200270056 /* pthread_cond.c */; };
+ C90E7AA715DC3C9D00A06D48 /* pthread_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F515B7513200270056 /* pthread_mutex.c */; };
+ C90E7AA815DC3C9D00A06D48 /* pthread_rwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F615B7513200270056 /* pthread_rwlock.c */; };
+ C90E7AA915DC3C9D00A06D48 /* pthread_support.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DC15C9D16B0098ECD8 /* pthread_support.c */; };
+ C90E7AAA15DC3C9D00A06D48 /* pthread_tsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F815B7513200270056 /* pthread_tsd.c */; };
+ C90E7AAB15DC3C9D00A06D48 /* thread_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FC15B7513200270056 /* thread_setup.c */; };
+ C90E7AB815DC40D900A06D48 /* pthread_atfork.c in Sources */ = {isa = PBXBuildFile; fileRef = C90E7AB415DC40D900A06D48 /* pthread_atfork.c */; };
+ C90E7AB915DC40D900A06D48 /* pthread_atfork.c in Sources */ = {isa = PBXBuildFile; fileRef = C90E7AB415DC40D900A06D48 /* pthread_atfork.c */; };
+ C9153096167ACC2B006BB094 /* private.h in Headers */ = {isa = PBXBuildFile; fileRef = C9153095167ACC22006BB094 /* private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C9169DDE1603DE84005A2F8C /* kern_support.c in Sources */ = {isa = PBXBuildFile; fileRef = C9169DDC1603DE84005A2F8C /* kern_support.c */; };
+ C9169DE01603DF9B005A2F8C /* kern_init.c in Sources */ = {isa = PBXBuildFile; fileRef = C9169DDF1603DF9B005A2F8C /* kern_init.c */; };
+ C9244C1B185FD33000075748 /* qos.h in Headers */ = {isa = PBXBuildFile; fileRef = C9244C1A185FCFED00075748 /* qos.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C9244C1D1860D8EF00075748 /* qos.c in Sources */ = {isa = PBXBuildFile; fileRef = C9244C1C1860D8EF00075748 /* qos.c */; };
+ C9244C1E1860D96D00075748 /* qos.c in Sources */ = {isa = PBXBuildFile; fileRef = C9244C1C1860D8EF00075748 /* qos.c */; };
+ C9244C1F1860D96E00075748 /* qos.c in Sources */ = {isa = PBXBuildFile; fileRef = C9244C1C1860D8EF00075748 /* qos.c */; };
+ C948FCF715D1D1E100180BF5 /* thread_setup.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FC15B7513200270056 /* thread_setup.c */; };
+ C975D5D715C9CECA0098ECD8 /* pthread_cond_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5D615C9CECA0098ECD8 /* pthread_cond_legacy.c */; };
+ C975D5D915C9CEEA0098ECD8 /* pthread_mutex_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5D815C9CEEA0098ECD8 /* pthread_mutex_legacy.c */; };
+ C975D5DB15C9CEFA0098ECD8 /* pthread_rwlock_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DA15C9CEFA0098ECD8 /* pthread_rwlock_legacy.c */; };
+ C975D5DD15C9D16B0098ECD8 /* pthread_support.c in Sources */ = {isa = PBXBuildFile; fileRef = C975D5DC15C9D16B0098ECD8 /* pthread_support.c */; };
+ C98C95D918FF1F4E005654FB /* spawn.h in Headers */ = {isa = PBXBuildFile; fileRef = C98C95D818FF1F4E005654FB /* spawn.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C99AD87B15DEC4BC0009A6F8 /* posix_sched.h in Headers */ = {isa = PBXBuildFile; fileRef = C9A325F015B7513200270056 /* posix_sched.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C99AD87C15DEC5290009A6F8 /* spinlock_private.h in Headers */ = {isa = PBXBuildFile; fileRef = C9A325F715B7513200270056 /* spinlock_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C99AD87F15DF04D10009A6F8 /* pthread_asm.s in Sources */ = {isa = PBXBuildFile; fileRef = C99AD87D15DF04D10009A6F8 /* pthread_asm.s */; };
+ C99AD88015E2D8B50009A6F8 /* pthread_asm.s in Sources */ = {isa = PBXBuildFile; fileRef = C99AD87D15DF04D10009A6F8 /* pthread_asm.s */; };
+ C9A1BF4715C9A578006BB313 /* pthread.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325FA15B7513200270056 /* pthread.c */; };
+ C9A1BF4815C9A578006BB313 /* pthread_cancelable.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F115B7513200270056 /* pthread_cancelable.c */; };
+ C9A1BF4915C9A578006BB313 /* pthread_cond.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F215B7513200270056 /* pthread_cond.c */; };
+ C9A1BF4A15C9A578006BB313 /* pthread_mutex.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F515B7513200270056 /* pthread_mutex.c */; };
+ C9A1BF4B15C9A578006BB313 /* pthread_rwlock.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F615B7513200270056 /* pthread_rwlock.c */; };
+ C9A1BF4C15C9A578006BB313 /* pthread_tsd.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A325F815B7513200270056 /* pthread_tsd.c */; };
+ C9A1BF4D15C9A58E006BB313 /* pthread.h in Headers */ = {isa = PBXBuildFile; fileRef = C9A325FE15B7513700270056 /* pthread.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C9A1BF4E15C9A594006BB313 /* pthread_impl.h in Headers */ = {isa = PBXBuildFile; fileRef = C9A325FF15B7513700270056 /* pthread_impl.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C9A1BF4F15C9A598006BB313 /* pthread_spis.h in Headers */ = {isa = PBXBuildFile; fileRef = C9A3260015B7513700270056 /* pthread_spis.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C9A1BF5015C9A59B006BB313 /* sched.h in Headers */ = {isa = PBXBuildFile; fileRef = C9A3260115B7513700270056 /* sched.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ C9A1BF5315C9A9F5006BB313 /* pthread_cancelable_cancel.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A1BF5215C9A9F5006BB313 /* pthread_cancelable_cancel.c */; };
+ C9A1BF5515C9CB9D006BB313 /* pthread_cancelable_legacy.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A1BF5415C9CB9D006BB313 /* pthread_cancelable_legacy.c */; };
+ C9A960B0183EB42700AE10C8 /* kern_policy.c in Sources */ = {isa = PBXBuildFile; fileRef = C9A960AF183EB42700AE10C8 /* kern_policy.c */; };
+ C9BB478B15E6ABD900F135B7 /* workqueue_private.h in Headers */ = {isa = PBXBuildFile; fileRef = C9A325F915B7513200270056 /* workqueue_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C9BB478D15E6ADF700F135B7 /* tsd_private.h in Headers */ = {isa = PBXBuildFile; fileRef = C9A325F415B7513200270056 /* tsd_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C9CCFB9D18B6D0910060CAAE /* qos_private.h in Headers */ = {isa = PBXBuildFile; fileRef = C99B17DA189C2E1B00991D38 /* qos_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ C9D75E4216127B3900C2FB26 /* kern_synch.c in Sources */ = {isa = PBXBuildFile; fileRef = C9169DDB1603DE84005A2F8C /* kern_synch.c */; };
+ E4063CF31906B75A000202F9 /* qos.h in Headers */ = {isa = PBXBuildFile; fileRef = E4063CF21906B4FB000202F9 /* qos.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ E4657D4117284F7B007D1847 /* introspection_private.h in Headers */ = {isa = PBXBuildFile; fileRef = E4657D4017284F7B007D1847 /* introspection_private.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ FC4DBBB316DEA8DA00503E47 /* plockstat.d in Sources */ = {isa = PBXBuildFile; fileRef = C9A325EF15B7513200270056 /* plockstat.d */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 74E594AA1613AD7F006C417B /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C9A325D915B7347000270056 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 74E594911613AAF4006C417B;
+ remoteInfo = "libpthread.a eOS";
+ };
+ C90E7AAF15DC3D3D00A06D48 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C9A325D915B7347000270056 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C9A325E115B7347000270056;
+ remoteInfo = Libpthread;
+ };
+ C90E7AB115DC3D3D00A06D48 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C9A325D915B7347000270056 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C90E7A9E15DC3C3800A06D48;
+ remoteInfo = libpthread.a;
+ };
+ C91D01B8162893070002E29A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C9A325D915B7347000270056 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C9CA27D81602813000259F78;
+ remoteInfo = pthread;
+ };
+ C91D01BB162CA80F0002E29A /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C9A325D915B7347000270056 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C9CA27D81602813000259F78;
+ remoteInfo = pthread;
+ };
+ C98832C515DEB44B00B3308E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C9A325D915B7347000270056 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C9A325E115B7347000270056;
+ remoteInfo = libsystem_pthread.dylib;
+ };
+ C98832C715DEB44B00B3308E /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = C9A325D915B7347000270056 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = C90E7A9E15DC3C3800A06D48;
+ remoteInfo = libpthread.a;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 74E594A41613AAF4006C417B /* libpthread_eOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpthread_eOS.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ A98FE72D19479F7C007718DA /* qos_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = qos_private.h; sourceTree = "<group>"; };
+ C90E7A9F15DC3C3800A06D48 /* libpthread.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libpthread.a; sourceTree = BUILT_PRODUCTS_DIR; };
+ C90E7AB415DC40D900A06D48 /* pthread_atfork.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_atfork.c; sourceTree = "<group>"; };
+ C9153094167ACAB8006BB094 /* install-symlinks.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "install-symlinks.sh"; sourceTree = "<group>"; };
+ C9153095167ACC22006BB094 /* private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = private.h; sourceTree = "<group>"; };
+ C9169DDB1603DE84005A2F8C /* kern_synch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kern_synch.c; sourceTree = "<group>"; };
+ C9169DDC1603DE84005A2F8C /* kern_support.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kern_support.c; sourceTree = "<group>"; };
+ C9169DDF1603DF9B005A2F8C /* kern_init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kern_init.c; sourceTree = "<group>"; };
+ C91D01BA162893CD0002E29A /* kext.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = kext.xcconfig; sourceTree = "<group>"; };
+ C9244C1A185FCFED00075748 /* qos.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = qos.h; sourceTree = "<group>"; };
+ C9244C1C1860D8EF00075748 /* qos.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = qos.c; sourceTree = "<group>"; };
+ C948FCC115D187FA00180BF5 /* pthread_atfork.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_atfork.3; sourceTree = "<group>"; };
+ C948FCC215D187FA00180BF5 /* pthread_attr_init_destroy.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_init_destroy.3; sourceTree = "<group>"; };
+ C948FCC315D187FA00180BF5 /* pthread_attr_set_getdetachstate.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getdetachstate.3; sourceTree = "<group>"; };
+ C948FCC415D187FA00180BF5 /* pthread_attr_set_getinheritsched.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getinheritsched.3; sourceTree = "<group>"; };
+ C948FCC515D187FA00180BF5 /* pthread_attr_set_getschedparam.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getschedparam.3; sourceTree = "<group>"; };
+ C948FCC615D187FA00180BF5 /* pthread_attr_set_getschedpolicy.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getschedpolicy.3; sourceTree = "<group>"; };
+ C948FCC715D187FA00180BF5 /* pthread_attr_set_getscope.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getscope.3; sourceTree = "<group>"; };
+ C948FCC815D187FA00180BF5 /* pthread_attr_set_getstackaddr.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getstackaddr.3; sourceTree = "<group>"; };
+ C948FCC915D187FA00180BF5 /* pthread_attr_set_getstacksize.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getstacksize.3; sourceTree = "<group>"; };
+ C948FCCA15D187FA00180BF5 /* pthread_attr.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr.3; sourceTree = "<group>"; };
+ C948FCCB15D187FA00180BF5 /* pthread_cancel.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cancel.3; sourceTree = "<group>"; };
+ C948FCCC15D187FA00180BF5 /* pthread_cleanup_pop.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cleanup_pop.3; sourceTree = "<group>"; };
+ C948FCCD15D187FA00180BF5 /* pthread_cleanup_push.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cleanup_push.3; sourceTree = "<group>"; };
+ C948FCCE15D187FA00180BF5 /* pthread_cond_broadcast.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cond_broadcast.3; sourceTree = "<group>"; };
+ C948FCCF15D187FA00180BF5 /* pthread_cond_destroy.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cond_destroy.3; sourceTree = "<group>"; };
+ C948FCD015D187FA00180BF5 /* pthread_cond_init.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cond_init.3; sourceTree = "<group>"; };
+ C948FCD115D187FA00180BF5 /* pthread_cond_signal.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cond_signal.3; sourceTree = "<group>"; };
+ C948FCD215D187FA00180BF5 /* pthread_cond_timedwait.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cond_timedwait.3; sourceTree = "<group>"; };
+ C948FCD315D187FA00180BF5 /* pthread_cond_wait.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cond_wait.3; sourceTree = "<group>"; };
+ C948FCD415D187FA00180BF5 /* pthread_condattr.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_condattr.3; sourceTree = "<group>"; };
+ C948FCD515D187FA00180BF5 /* pthread_create.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_create.3; sourceTree = "<group>"; };
+ C948FCD615D187FA00180BF5 /* pthread_detach.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_detach.3; sourceTree = "<group>"; };
+ C948FCD715D187FA00180BF5 /* pthread_equal.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_equal.3; sourceTree = "<group>"; };
+ C948FCD815D187FA00180BF5 /* pthread_exit.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_exit.3; sourceTree = "<group>"; };
+ C948FCD915D187FA00180BF5 /* pthread_getschedparam.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_getschedparam.3; sourceTree = "<group>"; };
+ C948FCDA15D187FA00180BF5 /* pthread_getspecific.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_getspecific.3; sourceTree = "<group>"; };
+ C948FCDB15D187FA00180BF5 /* pthread_join.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_join.3; sourceTree = "<group>"; };
+ C948FCDC15D187FA00180BF5 /* pthread_key_create.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_key_create.3; sourceTree = "<group>"; };
+ C948FCDD15D187FA00180BF5 /* pthread_key_delete.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_key_delete.3; sourceTree = "<group>"; };
+ C948FCDE15D187FA00180BF5 /* pthread_mutex_destroy.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_mutex_destroy.3; sourceTree = "<group>"; };
+ C948FCDF15D187FA00180BF5 /* pthread_mutex_init.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_mutex_init.3; sourceTree = "<group>"; };
+ C948FCE015D187FA00180BF5 /* pthread_mutex_lock.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_mutex_lock.3; sourceTree = "<group>"; };
+ C948FCE115D187FA00180BF5 /* pthread_mutex_trylock.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_mutex_trylock.3; sourceTree = "<group>"; };
+ C948FCE215D187FA00180BF5 /* pthread_mutex_unlock.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_mutex_unlock.3; sourceTree = "<group>"; };
+ C948FCE315D187FA00180BF5 /* pthread_mutexattr.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_mutexattr.3; sourceTree = "<group>"; };
+ C948FCE415D187FA00180BF5 /* pthread_once.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_once.3; sourceTree = "<group>"; };
+ C948FCE515D187FA00180BF5 /* pthread_rwlock_destroy.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlock_destroy.3; sourceTree = "<group>"; };
+ C948FCE615D187FA00180BF5 /* pthread_rwlock_init.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlock_init.3; sourceTree = "<group>"; };
+ C948FCE715D187FA00180BF5 /* pthread_rwlock_rdlock.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlock_rdlock.3; sourceTree = "<group>"; };
+ C948FCE815D187FA00180BF5 /* pthread_rwlock_unlock.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlock_unlock.3; sourceTree = "<group>"; };
+ C948FCE915D187FA00180BF5 /* pthread_rwlock_wrlock.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlock_wrlock.3; sourceTree = "<group>"; };
+ C948FCEA15D187FA00180BF5 /* pthread_rwlockattr_destroy.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlockattr_destroy.3; sourceTree = "<group>"; };
+ C948FCEB15D187FA00180BF5 /* pthread_rwlockattr_getpshared.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlockattr_getpshared.3; sourceTree = "<group>"; };
+ C948FCEC15D187FA00180BF5 /* pthread_rwlockattr_init.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlockattr_init.3; sourceTree = "<group>"; };
+ C948FCED15D187FA00180BF5 /* pthread_rwlockattr_setpshared.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlockattr_setpshared.3; sourceTree = "<group>"; };
+ C948FCEE15D187FA00180BF5 /* pthread_self.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_self.3; sourceTree = "<group>"; };
+ C948FCEF15D187FA00180BF5 /* pthread_setcancelstate.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_setcancelstate.3; sourceTree = "<group>"; };
+ C948FCF015D187FA00180BF5 /* pthread_setspecific.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_setspecific.3; sourceTree = "<group>"; };
+ C948FCF115D187FA00180BF5 /* pthread.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread.3; sourceTree = "<group>"; };
+ C975D5D615C9CECA0098ECD8 /* pthread_cond_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_cond_legacy.c; sourceTree = "<group>"; };
+ C975D5D815C9CEEA0098ECD8 /* pthread_mutex_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_mutex_legacy.c; sourceTree = "<group>"; };
+ C975D5DA15C9CEFA0098ECD8 /* pthread_rwlock_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_rwlock_legacy.c; sourceTree = "<group>"; };
+ C975D5DC15C9D16B0098ECD8 /* pthread_support.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_support.c; sourceTree = "<group>"; };
+ C979E9FB18A1BC2A000951E5 /* kern_trace.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = kern_trace.h; sourceTree = "<group>"; };
+ C979E9FC18A2BF2C000951E5 /* install-codes.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "install-codes.sh"; sourceTree = "<group>"; };
+ C98005141899BD2000368E4D /* workqueue_internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = workqueue_internal.h; sourceTree = "<group>"; };
+ C98C95D818FF1F4E005654FB /* spawn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spawn.h; sourceTree = "<group>"; };
+ C99AD87D15DF04D10009A6F8 /* pthread_asm.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = pthread_asm.s; sourceTree = "<group>"; };
+ C99B17DA189C2E1B00991D38 /* qos_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = qos_private.h; sourceTree = "<group>"; };
+ C99EA612161F8288003EBC56 /* eos.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = eos.xcconfig; sourceTree = "<group>"; };
+ C9A1BF5215C9A9F5006BB313 /* pthread_cancelable_cancel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_cancelable_cancel.c; sourceTree = "<group>"; };
+ C9A1BF5415C9CB9D006BB313 /* pthread_cancelable_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_cancelable_legacy.c; sourceTree = "<group>"; };
+ C9A325E215B7347000270056 /* libsystem_pthread.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libsystem_pthread.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ C9A325EE15B7513200270056 /* mk_pthread_impl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = mk_pthread_impl.c; sourceTree = "<group>"; };
+ C9A325EF15B7513200270056 /* plockstat.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = plockstat.d; sourceTree = "<group>"; };
+ C9A325F015B7513200270056 /* posix_sched.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = posix_sched.h; sourceTree = "<group>"; };
+ C9A325F115B7513200270056 /* pthread_cancelable.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread_cancelable.c; sourceTree = "<group>"; };
+ C9A325F215B7513200270056 /* pthread_cond.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread_cond.c; sourceTree = "<group>"; };
+ C9A325F315B7513200270056 /* internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = "<group>"; };
+ C9A325F415B7513200270056 /* tsd_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tsd_private.h; sourceTree = "<group>"; };
+ C9A325F515B7513200270056 /* pthread_mutex.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread_mutex.c; sourceTree = "<group>"; };
+ C9A325F615B7513200270056 /* pthread_rwlock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread_rwlock.c; sourceTree = "<group>"; };
+ C9A325F715B7513200270056 /* spinlock_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = spinlock_private.h; sourceTree = "<group>"; };
+ C9A325F815B7513200270056 /* pthread_tsd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread_tsd.c; sourceTree = "<group>"; };
+ C9A325F915B7513200270056 /* workqueue_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = workqueue_private.h; sourceTree = "<group>"; };
+ C9A325FA15B7513200270056 /* pthread.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread.c; sourceTree = "<group>"; };
+ C9A325FC15B7513200270056 /* thread_setup.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = thread_setup.c; sourceTree = "<group>"; };
+ C9A325FE15B7513700270056 /* pthread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pthread.h; sourceTree = "<group>"; };
+ C9A325FF15B7513700270056 /* pthread_impl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pthread_impl.h; sourceTree = "<group>"; };
+ C9A3260015B7513700270056 /* pthread_spis.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pthread_spis.h; sourceTree = "<group>"; };
+ C9A3260115B7513700270056 /* sched.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sched.h; sourceTree = "<group>"; };
+ C9A3260C15B759B600270056 /* pthread.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = pthread.xcconfig; sourceTree = "<group>"; };
+ C9A960AF183EB42700AE10C8 /* kern_policy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kern_policy.c; sourceTree = "<group>"; };
+ C9A960B318452B2F00AE10C8 /* pthread.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = pthread.py; sourceTree = "<group>"; };
+ C9A960B618452CDD00AE10C8 /* install-lldbmacros.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "install-lldbmacros.sh"; sourceTree = "<group>"; };
+ C9C2212D15FA978D00447568 /* pthread.aliases */ = {isa = PBXFileReference; lastKnownFileType = text; path = pthread.aliases; sourceTree = "<group>"; };
+ C9C533841607C928009988FA /* kern_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kern_internal.h; sourceTree = "<group>"; };
+ C9CA27D91602813000259F78 /* pthread.kext */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = pthread.kext; sourceTree = BUILT_PRODUCTS_DIR; };
+ C9CA27DC1602813000259F78 /* Kernel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Kernel.framework; path = System/Library/Frameworks/Kernel.framework; sourceTree = SDKROOT; };
+ C9D9E8FE1626248800448CED /* pthread-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "pthread-Info.plist"; sourceTree = "<group>"; };
+ C9DCA2A115DC4F2000D057E2 /* install-manpages.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "install-manpages.sh"; sourceTree = "<group>"; };
+ E4063CF21906B4FB000202F9 /* qos.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = qos.h; sourceTree = "<group>"; };
+ E4657D4017284F7B007D1847 /* introspection_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = introspection_private.h; sourceTree = "<group>"; };
+ E4D962F919086AD600E8A9F2 /* qos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = qos.h; sourceTree = "<group>"; };
+ E4D962FC19086C5700E8A9F2 /* install-sys-headers.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "install-sys-headers.sh"; sourceTree = "<group>"; };
+ FC30E28D16A747AD00A25B5F /* synch_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = synch_internal.h; sourceTree = "<group>"; };
+ FC5A372417CEB3D6008C323E /* _pthread_attr_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_attr_t.h; sourceTree = "<group>"; };
+ FC5A372517CEB3D6008C323E /* _pthread_cond_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_cond_t.h; sourceTree = "<group>"; };
+ FC5A372617CEB3D6008C323E /* _pthread_condattr_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_condattr_t.h; sourceTree = "<group>"; };
+ FC5A372717CEB3D6008C323E /* _pthread_key_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_key_t.h; sourceTree = "<group>"; };
+ FC5A372817CEB3D6008C323E /* _pthread_mutex_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_mutex_t.h; sourceTree = "<group>"; };
+ FC5A372917CEB3D6008C323E /* _pthread_mutexattr_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_mutexattr_t.h; sourceTree = "<group>"; };
+ FC5A372A17CEB3D6008C323E /* _pthread_once_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_once_t.h; sourceTree = "<group>"; };
+ FC5A372B17CEB3D6008C323E /* _pthread_rwlock_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_rwlock_t.h; sourceTree = "<group>"; };
+ FC5A372C17CEB3D6008C323E /* _pthread_rwlockattr_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_rwlockattr_t.h; sourceTree = "<group>"; };
+ FC5A372D17CEB3D6008C323E /* _pthread_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_t.h; sourceTree = "<group>"; };
+ FC5A372E17CEB3D6008C323E /* _pthread_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_types.h; sourceTree = "<group>"; };
+ FC618A76160E8155006810FE /* pthread_kill.2 */ = {isa = PBXFileReference; lastKnownFileType = text; path = pthread_kill.2; sourceTree = "<group>"; };
+ FC618A77160E8155006810FE /* pthread_sigmask.2 */ = {isa = PBXFileReference; lastKnownFileType = text; path = pthread_sigmask.2; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 74E594A01613AAF4006C417B /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C90E7A9C15DC3C3800A06D48 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C9A325DF15B7347000270056 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C9CA27D41602813000259F78 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ C9169DD91603DE68005A2F8C /* kern */ = {
+ isa = PBXGroup;
+ children = (
+ C9D9E8FE1626248800448CED /* pthread-Info.plist */,
+ C9C533841607C928009988FA /* kern_internal.h */,
+ C9169DDF1603DF9B005A2F8C /* kern_init.c */,
+ C9A960AF183EB42700AE10C8 /* kern_policy.c */,
+ C9169DDB1603DE84005A2F8C /* kern_synch.c */,
+ C9169DDC1603DE84005A2F8C /* kern_support.c */,
+ C979E9FB18A1BC2A000951E5 /* kern_trace.h */,
+ FC30E28D16A747AD00A25B5F /* synch_internal.h */,
+ C98005141899BD2000368E4D /* workqueue_internal.h */,
+ );
+ path = kern;
+ sourceTree = "<group>";
+ };
+ C948FCC015D187AD00180BF5 /* man */ = {
+ isa = PBXGroup;
+ children = (
+ C948FCC115D187FA00180BF5 /* pthread_atfork.3 */,
+ C948FCC215D187FA00180BF5 /* pthread_attr_init_destroy.3 */,
+ C948FCC315D187FA00180BF5 /* pthread_attr_set_getdetachstate.3 */,
+ C948FCC415D187FA00180BF5 /* pthread_attr_set_getinheritsched.3 */,
+ C948FCC515D187FA00180BF5 /* pthread_attr_set_getschedparam.3 */,
+ C948FCC615D187FA00180BF5 /* pthread_attr_set_getschedpolicy.3 */,
+ C948FCC715D187FA00180BF5 /* pthread_attr_set_getscope.3 */,
+ C948FCC815D187FA00180BF5 /* pthread_attr_set_getstackaddr.3 */,
+ C948FCC915D187FA00180BF5 /* pthread_attr_set_getstacksize.3 */,
+ C948FCCA15D187FA00180BF5 /* pthread_attr.3 */,
+ C948FCCB15D187FA00180BF5 /* pthread_cancel.3 */,
+ C948FCCC15D187FA00180BF5 /* pthread_cleanup_pop.3 */,
+ C948FCCD15D187FA00180BF5 /* pthread_cleanup_push.3 */,
+ C948FCCE15D187FA00180BF5 /* pthread_cond_broadcast.3 */,
+ C948FCCF15D187FA00180BF5 /* pthread_cond_destroy.3 */,
+ C948FCD015D187FA00180BF5 /* pthread_cond_init.3 */,
+ C948FCD115D187FA00180BF5 /* pthread_cond_signal.3 */,
+ C948FCD215D187FA00180BF5 /* pthread_cond_timedwait.3 */,
+ C948FCD315D187FA00180BF5 /* pthread_cond_wait.3 */,
+ C948FCD415D187FA00180BF5 /* pthread_condattr.3 */,
+ C948FCD515D187FA00180BF5 /* pthread_create.3 */,
+ C948FCD615D187FA00180BF5 /* pthread_detach.3 */,
+ C948FCD715D187FA00180BF5 /* pthread_equal.3 */,
+ C948FCD815D187FA00180BF5 /* pthread_exit.3 */,
+ C948FCD915D187FA00180BF5 /* pthread_getschedparam.3 */,
+ C948FCDA15D187FA00180BF5 /* pthread_getspecific.3 */,
+ C948FCDB15D187FA00180BF5 /* pthread_join.3 */,
+ C948FCDC15D187FA00180BF5 /* pthread_key_create.3 */,
+ C948FCDD15D187FA00180BF5 /* pthread_key_delete.3 */,
+ FC618A76160E8155006810FE /* pthread_kill.2 */,
+ C948FCDE15D187FA00180BF5 /* pthread_mutex_destroy.3 */,
+ C948FCDF15D187FA00180BF5 /* pthread_mutex_init.3 */,
+ C948FCE015D187FA00180BF5 /* pthread_mutex_lock.3 */,
+ C948FCE115D187FA00180BF5 /* pthread_mutex_trylock.3 */,
+ C948FCE215D187FA00180BF5 /* pthread_mutex_unlock.3 */,
+ C948FCE315D187FA00180BF5 /* pthread_mutexattr.3 */,
+ C948FCE415D187FA00180BF5 /* pthread_once.3 */,
+ C948FCE515D187FA00180BF5 /* pthread_rwlock_destroy.3 */,
+ C948FCE615D187FA00180BF5 /* pthread_rwlock_init.3 */,
+ C948FCE715D187FA00180BF5 /* pthread_rwlock_rdlock.3 */,
+ C948FCE815D187FA00180BF5 /* pthread_rwlock_unlock.3 */,
+ C948FCE915D187FA00180BF5 /* pthread_rwlock_wrlock.3 */,
+ C948FCEA15D187FA00180BF5 /* pthread_rwlockattr_destroy.3 */,
+ C948FCEB15D187FA00180BF5 /* pthread_rwlockattr_getpshared.3 */,
+ C948FCEC15D187FA00180BF5 /* pthread_rwlockattr_init.3 */,
+ C948FCED15D187FA00180BF5 /* pthread_rwlockattr_setpshared.3 */,
+ C948FCEE15D187FA00180BF5 /* pthread_self.3 */,
+ C948FCEF15D187FA00180BF5 /* pthread_setcancelstate.3 */,
+ C948FCF015D187FA00180BF5 /* pthread_setspecific.3 */,
+ FC618A77160E8155006810FE /* pthread_sigmask.2 */,
+ C948FCF115D187FA00180BF5 /* pthread.3 */,
+ );
+ path = man;
+ sourceTree = "<group>";
+ };
+ C9A1BF5115C9A8B7006BB313 /* variants */ = {
+ isa = PBXGroup;
+ children = (
+ C9A1BF5215C9A9F5006BB313 /* pthread_cancelable_cancel.c */,
+ C9A1BF5415C9CB9D006BB313 /* pthread_cancelable_legacy.c */,
+ C975D5D615C9CECA0098ECD8 /* pthread_cond_legacy.c */,
+ C975D5D815C9CEEA0098ECD8 /* pthread_mutex_legacy.c */,
+ C975D5DA15C9CEFA0098ECD8 /* pthread_rwlock_legacy.c */,
+ );
+ path = variants;
+ sourceTree = "<group>";
+ };
+ C9A325D715B7347000270056 = {
+ isa = PBXGroup;
+ children = (
+ C9169DD91603DE68005A2F8C /* kern */,
+ C9A960B218452B0700AE10C8 /* lldbmacros */,
+ C9A325FD15B7513700270056 /* pthread */,
+ FC5A372217CEB3D6008C323E /* sys */,
+ C9D70EBE167AC7D100D52713 /* private */,
+ C948FCC015D187AD00180BF5 /* man */,
+ C9A325ED15B74FB600270056 /* src */,
+ C9A3260B15B759A100270056 /* xcodescripts */,
+ C9CA27DA1602813000259F78 /* Frameworks */,
+ C9A325E315B7347000270056 /* Products */,
+ );
+ sourceTree = "<group>";
+ usesTabs = 1;
+ };
+ C9A325E315B7347000270056 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ C9A325E215B7347000270056 /* libsystem_pthread.dylib */,
+ C90E7A9F15DC3C3800A06D48 /* libpthread.a */,
+ 74E594A41613AAF4006C417B /* libpthread_eOS.a */,
+ C9CA27D91602813000259F78 /* pthread.kext */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ C9A325ED15B74FB600270056 /* src */ = {
+ isa = PBXGroup;
+ children = (
+ C9A325F315B7513200270056 /* internal.h */,
+ C9A325EE15B7513200270056 /* mk_pthread_impl.c */,
+ C9A325EF15B7513200270056 /* plockstat.d */,
+ C9A325FA15B7513200270056 /* pthread.c */,
+ C99AD87D15DF04D10009A6F8 /* pthread_asm.s */,
+ C90E7AB415DC40D900A06D48 /* pthread_atfork.c */,
+ C9A325F115B7513200270056 /* pthread_cancelable.c */,
+ C9A325F215B7513200270056 /* pthread_cond.c */,
+ C9A325F515B7513200270056 /* pthread_mutex.c */,
+ C9A325F615B7513200270056 /* pthread_rwlock.c */,
+ C975D5DC15C9D16B0098ECD8 /* pthread_support.c */,
+ C9A325F815B7513200270056 /* pthread_tsd.c */,
+ C9244C1C1860D8EF00075748 /* qos.c */,
+ C9A325FC15B7513200270056 /* thread_setup.c */,
+ C9A1BF5115C9A8B7006BB313 /* variants */,
+ );
+ path = src;
+ sourceTree = "<group>";
+ };
+ C9A325FD15B7513700270056 /* pthread */ = {
+ isa = PBXGroup;
+ children = (
+ C9A325FE15B7513700270056 /* pthread.h */,
+ C9A325FF15B7513700270056 /* pthread_impl.h */,
+ C9A3260015B7513700270056 /* pthread_spis.h */,
+ C9A3260115B7513700270056 /* sched.h */,
+ C98C95D818FF1F4E005654FB /* spawn.h */,
+ C9244C1A185FCFED00075748 /* qos.h */,
+ );
+ path = pthread;
+ sourceTree = "<group>";
+ };
+ C9A3260B15B759A100270056 /* xcodescripts */ = {
+ isa = PBXGroup;
+ children = (
+ C91D01BA162893CD0002E29A /* kext.xcconfig */,
+ C9A3260C15B759B600270056 /* pthread.xcconfig */,
+ C99EA612161F8288003EBC56 /* eos.xcconfig */,
+ C9DCA2A115DC4F2000D057E2 /* install-manpages.sh */,
+ C9153094167ACAB8006BB094 /* install-symlinks.sh */,
+ E4D962FC19086C5700E8A9F2 /* install-sys-headers.sh */,
+ C9A960B618452CDD00AE10C8 /* install-lldbmacros.sh */,
+ C979E9FC18A2BF2C000951E5 /* install-codes.sh */,
+ C9C2212D15FA978D00447568 /* pthread.aliases */,
+ );
+ path = xcodescripts;
+ sourceTree = "<group>";
+ };
+ C9A960B218452B0700AE10C8 /* lldbmacros */ = {
+ isa = PBXGroup;
+ children = (
+ C9A960B318452B2F00AE10C8 /* pthread.py */,
+ );
+ path = lldbmacros;
+ sourceTree = "<group>";
+ };
+ C9CA27DA1602813000259F78 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ C9CA27DB1602813000259F78 /* Other Frameworks */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ C9CA27DB1602813000259F78 /* Other Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ C9CA27DC1602813000259F78 /* Kernel.framework */,
+ );
+ name = "Other Frameworks";
+ sourceTree = "<group>";
+ };
+ C9D70EBE167AC7D100D52713 /* private */ = {
+ isa = PBXGroup;
+ children = (
+ C9153095167ACC22006BB094 /* private.h */,
+ C9A325F015B7513200270056 /* posix_sched.h */,
+ C9A325F715B7513200270056 /* spinlock_private.h */,
+ C9A325F415B7513200270056 /* tsd_private.h */,
+ C9A325F915B7513200270056 /* workqueue_private.h */,
+ E4657D4017284F7B007D1847 /* introspection_private.h */,
+ C99B17DA189C2E1B00991D38 /* qos_private.h */,
+ E4063CF21906B4FB000202F9 /* qos.h */,
+ );
+ path = private;
+ sourceTree = "<group>";
+ };
+ FC5A372217CEB3D6008C323E /* sys */ = {
+ isa = PBXGroup;
+ children = (
+ E4D962F919086AD600E8A9F2 /* qos.h */,
+ FC5A372317CEB3D6008C323E /* _pthread */,
+ A98FE72D19479F7C007718DA /* qos_private.h */,
+ );
+ path = sys;
+ sourceTree = "<group>";
+ };
+ FC5A372317CEB3D6008C323E /* _pthread */ = {
+ isa = PBXGroup;
+ children = (
+ FC5A372417CEB3D6008C323E /* _pthread_attr_t.h */,
+ FC5A372517CEB3D6008C323E /* _pthread_cond_t.h */,
+ FC5A372617CEB3D6008C323E /* _pthread_condattr_t.h */,
+ FC5A372717CEB3D6008C323E /* _pthread_key_t.h */,
+ FC5A372817CEB3D6008C323E /* _pthread_mutex_t.h */,
+ FC5A372917CEB3D6008C323E /* _pthread_mutexattr_t.h */,
+ FC5A372A17CEB3D6008C323E /* _pthread_once_t.h */,
+ FC5A372B17CEB3D6008C323E /* _pthread_rwlock_t.h */,
+ FC5A372C17CEB3D6008C323E /* _pthread_rwlockattr_t.h */,
+ FC5A372D17CEB3D6008C323E /* _pthread_t.h */,
+ FC5A372E17CEB3D6008C323E /* _pthread_types.h */,
+ );
+ path = _pthread;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 74E594A11613AAF4006C417B /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C90E7A9D15DC3C3800A06D48 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C9A325E015B7347000270056 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C9244C1B185FD33000075748 /* qos.h in Headers */,
+ C9A1BF4D15C9A58E006BB313 /* pthread.h in Headers */,
+ C9A1BF4E15C9A594006BB313 /* pthread_impl.h in Headers */,
+ E4063CF31906B75A000202F9 /* qos.h in Headers */,
+ C9A1BF4F15C9A598006BB313 /* pthread_spis.h in Headers */,
+ C9A1BF5015C9A59B006BB313 /* sched.h in Headers */,
+ E4657D4117284F7B007D1847 /* introspection_private.h in Headers */,
+ C9BB478D15E6ADF700F135B7 /* tsd_private.h in Headers */,
+ C99AD87B15DEC4BC0009A6F8 /* posix_sched.h in Headers */,
+ C9CCFB9D18B6D0910060CAAE /* qos_private.h in Headers */,
+ C98C95D918FF1F4E005654FB /* spawn.h in Headers */,
+ C99AD87C15DEC5290009A6F8 /* spinlock_private.h in Headers */,
+ C9BB478B15E6ABD900F135B7 /* workqueue_private.h in Headers */,
+ C9153096167ACC2B006BB094 /* private.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C9CA27D51602813000259F78 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 74E594911613AAF4006C417B /* libpthread.a eOS */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 74E594A21613AAF4006C417B /* Build configuration list for PBXNativeTarget "libpthread.a eOS" */;
+ buildPhases = (
+ 74E594921613AAF4006C417B /* Sources */,
+ 74E594A01613AAF4006C417B /* Frameworks */,
+ 74E594A11613AAF4006C417B /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = "libpthread.a eOS";
+ productName = libpthread.a;
+ productReference = 74E594A41613AAF4006C417B /* libpthread_eOS.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ C90E7A9E15DC3C3800A06D48 /* libpthread.a */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C90E7AA115DC3C3800A06D48 /* Build configuration list for PBXNativeTarget "libpthread.a" */;
+ buildPhases = (
+ C90E7A9B15DC3C3800A06D48 /* Sources */,
+ C90E7A9C15DC3C3800A06D48 /* Frameworks */,
+ C90E7A9D15DC3C3800A06D48 /* Headers */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libpthread.a;
+ productName = libpthread.a;
+ productReference = C90E7A9F15DC3C3800A06D48 /* libpthread.a */;
+ productType = "com.apple.product-type.library.static";
+ };
+ C9A325E115B7347000270056 /* libsystem_pthread.dylib */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C9A325E615B7347000270056 /* Build configuration list for PBXNativeTarget "libsystem_pthread.dylib" */;
+ buildPhases = (
+ C99AD87815DEBE450009A6F8 /* Generate dtrace header */,
+ C9A325DE15B7347000270056 /* Sources */,
+ C9A325DF15B7347000270056 /* Frameworks */,
+ C9A325E015B7347000270056 /* Headers */,
+ C9D70EBD167AC76700D52713 /* Symlink Old Header Location */,
+ C9DCA2A215DC4F3500D057E2 /* Install Manpages */,
+ FC5A372F17CEB60D008C323E /* Install sys headers */,
+ C979E9FD18A2BF3D000951E5 /* Install Codes file */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = libsystem_pthread.dylib;
+ productName = Libpthread;
+ productReference = C9A325E215B7347000270056 /* libsystem_pthread.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+ C9CA27D81602813000259F78 /* pthread */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C9CA27E71602813000259F78 /* Build configuration list for PBXNativeTarget "pthread" */;
+ buildPhases = (
+ C9CA27D31602813000259F78 /* Sources */,
+ C9CA27D41602813000259F78 /* Frameworks */,
+ C9CA27D51602813000259F78 /* Headers */,
+ C9CA27D61602813000259F78 /* Resources */,
+ C9CA27D71602813000259F78 /* Rez */,
+ C9A960B518452C1800AE10C8 /* Install lldbmacros */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = pthread;
+ productName = pthread;
+ productReference = C9CA27D91602813000259F78 /* pthread.kext */;
+ productType = "com.apple.product-type.kernel-extension";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ C9A325D915B7347000270056 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ LastUpgradeCheck = 0500;
+ ORGANIZATIONNAME = "";
+ };
+ buildConfigurationList = C9A325DC15B7347000270056 /* Build configuration list for PBXProject "libpthread" */;
+ compatibilityVersion = "Xcode 3.2";
+ developmentRegion = English;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ );
+ mainGroup = C9A325D715B7347000270056;
+ productRefGroup = C9A325E315B7347000270056 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ C90E7AAC15DC3D3300A06D48 /* All */,
+ C91D01B5162892FF0002E29A /* Kext */,
+ C98832C115DEB44000B3308E /* Embedded */,
+ C9A325E115B7347000270056 /* libsystem_pthread.dylib */,
+ C90E7A9E15DC3C3800A06D48 /* libpthread.a */,
+ 74E594911613AAF4006C417B /* libpthread.a eOS */,
+ C9CA27D81602813000259F78 /* pthread */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ C9CA27D61602813000259F78 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXRezBuildPhase section */
+ C9CA27D71602813000259F78 /* Rez */ = {
+ isa = PBXRezBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXRezBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ C979E9FD18A2BF3D000951E5 /* Install Codes file */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/kern/kern_trace.h",
+ );
+ name = "Install Codes file";
+ outputPaths = (
+ "$(DSTROOT)$(INSTALL_PATH_PREFIX)/usr/share/misc/pthread.codes",
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = "/bin/bash -e";
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-codes.sh";
+ };
+ C99AD87815DEBE450009A6F8 /* Generate dtrace header */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/src/plockstat.d",
+ );
+ name = "Generate dtrace header";
+ outputPaths = (
+ "$(DERIVED_FILE_DIR)/dtrace/plockstat.h",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "dtrace -h -C -s ${SCRIPT_INPUT_FILE_0} -o ${SCRIPT_OUTPUT_FILE_0}";
+ };
+ C9A960B518452C1800AE10C8 /* Install lldbmacros */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 12;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Install lldbmacros";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-lldbmacros.sh";
+ };
+ C9D70EBD167AC76700D52713 /* Symlink Old Header Location */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "",
+ );
+ name = "Symlink Old Header Location";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = "/bin/bash -e -x";
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-symlinks.sh";
+ showEnvVarsInLog = 0;
+ };
+ C9DCA2A215DC4F3500D057E2 /* Install Manpages */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ "",
+ );
+ name = "Install Manpages";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = "/bin/bash -e";
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-manpages.sh";
+ showEnvVarsInLog = 0;
+ };
+ FC5A372F17CEB60D008C323E /* Install sys headers */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 8;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Install sys headers";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ shellPath = /bin/sh;
+ shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-sys-headers.sh";
+ showEnvVarsInLog = 0;
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 74E594921613AAF4006C417B /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 74E594931613AAF4006C417B /* pthread.c in Sources */,
+ 74E594941613AAF4006C417B /* pthread_cancelable.c in Sources */,
+ 74E594A61613AB10006C417B /* pthread_cancelable_cancel.c in Sources */,
+ 74E594951613AAF4006C417B /* pthread_cond.c in Sources */,
+ 74E594961613AAF4006C417B /* pthread_mutex.c in Sources */,
+ 74E594971613AAF4006C417B /* pthread_rwlock.c in Sources */,
+ 74E594981613AAF4006C417B /* pthread_support.c in Sources */,
+ 74E594991613AAF4006C417B /* pthread_tsd.c in Sources */,
+ 74E5949A1613AAF4006C417B /* thread_setup.c in Sources */,
+ C9244C1F1860D96E00075748 /* qos.c in Sources */,
+ 74E5949C1613AAF4006C417B /* pthread_atfork.c in Sources */,
+ 74E5949E1613AAF4006C417B /* pthread_asm.s in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C90E7A9B15DC3C3800A06D48 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C9244C1E1860D96D00075748 /* qos.c in Sources */,
+ C90E7AA415DC3C9D00A06D48 /* pthread.c in Sources */,
+ C90E7AA515DC3C9D00A06D48 /* pthread_cancelable.c in Sources */,
+ C90E7AA615DC3C9D00A06D48 /* pthread_cond.c in Sources */,
+ C90E7AA715DC3C9D00A06D48 /* pthread_mutex.c in Sources */,
+ C90E7AA815DC3C9D00A06D48 /* pthread_rwlock.c in Sources */,
+ C90E7AA915DC3C9D00A06D48 /* pthread_support.c in Sources */,
+ C90E7AAA15DC3C9D00A06D48 /* pthread_tsd.c in Sources */,
+ C90E7AAB15DC3C9D00A06D48 /* thread_setup.c in Sources */,
+ C90E7AB915DC40D900A06D48 /* pthread_atfork.c in Sources */,
+ C99AD87F15DF04D10009A6F8 /* pthread_asm.s in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C9A325DE15B7347000270056 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C9A1BF4715C9A578006BB313 /* pthread.c in Sources */,
+ C9A1BF4815C9A578006BB313 /* pthread_cancelable.c in Sources */,
+ FC4DBBB316DEA8DA00503E47 /* plockstat.d in Sources */,
+ C9A1BF4915C9A578006BB313 /* pthread_cond.c in Sources */,
+ C9A1BF4A15C9A578006BB313 /* pthread_mutex.c in Sources */,
+ C9244C1D1860D8EF00075748 /* qos.c in Sources */,
+ C9A1BF4B15C9A578006BB313 /* pthread_rwlock.c in Sources */,
+ C9A1BF4C15C9A578006BB313 /* pthread_tsd.c in Sources */,
+ C9A1BF5315C9A9F5006BB313 /* pthread_cancelable_cancel.c in Sources */,
+ C9A1BF5515C9CB9D006BB313 /* pthread_cancelable_legacy.c in Sources */,
+ C975D5D715C9CECA0098ECD8 /* pthread_cond_legacy.c in Sources */,
+ C975D5D915C9CEEA0098ECD8 /* pthread_mutex_legacy.c in Sources */,
+ C975D5DB15C9CEFA0098ECD8 /* pthread_rwlock_legacy.c in Sources */,
+ C975D5DD15C9D16B0098ECD8 /* pthread_support.c in Sources */,
+ C948FCF715D1D1E100180BF5 /* thread_setup.c in Sources */,
+ C90E7AB815DC40D900A06D48 /* pthread_atfork.c in Sources */,
+ C99AD88015E2D8B50009A6F8 /* pthread_asm.s in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ C9CA27D31602813000259F78 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ C9169DDE1603DE84005A2F8C /* kern_support.c in Sources */,
+ C9A960B0183EB42700AE10C8 /* kern_policy.c in Sources */,
+ C9169DE01603DF9B005A2F8C /* kern_init.c in Sources */,
+ C9D75E4216127B3900C2FB26 /* kern_synch.c in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 74E594AB1613AD7F006C417B /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 74E594911613AAF4006C417B /* libpthread.a eOS */;
+ targetProxy = 74E594AA1613AD7F006C417B /* PBXContainerItemProxy */;
+ };
+ C90E7AB015DC3D3D00A06D48 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C9A325E115B7347000270056 /* libsystem_pthread.dylib */;
+ targetProxy = C90E7AAF15DC3D3D00A06D48 /* PBXContainerItemProxy */;
+ };
+ C90E7AB215DC3D3D00A06D48 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C90E7A9E15DC3C3800A06D48 /* libpthread.a */;
+ targetProxy = C90E7AB115DC3D3D00A06D48 /* PBXContainerItemProxy */;
+ };
+ C91D01B9162893070002E29A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C9CA27D81602813000259F78 /* pthread */;
+ targetProxy = C91D01B8162893070002E29A /* PBXContainerItemProxy */;
+ };
+ C91D01BC162CA80F0002E29A /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C9CA27D81602813000259F78 /* pthread */;
+ targetProxy = C91D01BB162CA80F0002E29A /* PBXContainerItemProxy */;
+ };
+ C98832C615DEB44B00B3308E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C9A325E115B7347000270056 /* libsystem_pthread.dylib */;
+ targetProxy = C98832C515DEB44B00B3308E /* PBXContainerItemProxy */;
+ };
+ C98832C815DEB44B00B3308E /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = C90E7A9E15DC3C3800A06D48 /* libpthread.a */;
+ targetProxy = C98832C715DEB44B00B3308E /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 74E594A31613AAF4006C417B /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = C99EA612161F8288003EBC56 /* eos.xcconfig */;
+ buildSettings = {
+ COMBINE_HIDPI_IMAGES = YES;
+ SDKROOT = macosx.internal;
+ };
+ name = Release;
+ };
+ C90E7AA015DC3C3800A06D48 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = C9A3260C15B759B600270056 /* pthread.xcconfig */;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ COMBINE_HIDPI_IMAGES = YES;
+ EXECUTABLE_PREFIX = lib;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(BASE_PREPROCESSOR_MACROS)",
+ "VARIANT_DYLD=1",
+ );
+ INSTALL_PATH = /usr/local/lib/dyld;
+ "INSTALL_PATH[sdk=iphonesimulator*]" = "$(SDKROOT)/usr/local/lib/dyld";
+ OTHER_LDFLAGS = "";
+ PRODUCT_NAME = pthread;
+ SDKROOT = macosx.internal;
+ };
+ name = Release;
+ };
+ C90E7AAE15DC3D3300A06D48 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COMBINE_HIDPI_IMAGES = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ C91D01B7162892FF0002E29A /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COMBINE_HIDPI_IMAGES = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ C98832C215DEB44000B3308E /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COMBINE_HIDPI_IMAGES = YES;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ };
+ name = Release;
+ };
+ C9A325E515B7347000270056 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ };
+ name = Release;
+ };
+ C9A325E815B7347000270056 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = C9A3260C15B759B600270056 /* pthread.xcconfig */;
+ buildSettings = {
+ COMBINE_HIDPI_IMAGES = YES;
+ EXECUTABLE_PREFIX = lib;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "$(BASE_PREPROCESSOR_MACROS)",
+ "PLOCKSTAT=1",
+ );
+ PRODUCT_NAME = system_pthread;
+ SDKROOT = macosx.internal;
+ };
+ name = Release;
+ };
+ C9CA27E61602813000259F78 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = C91D01BA162893CD0002E29A /* kext.xcconfig */;
+ buildSettings = {
+ COMBINE_HIDPI_IMAGES = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SDKROOT = macosx.internal;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 74E594A21613AAF4006C417B /* Build configuration list for PBXNativeTarget "libpthread.a eOS" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 74E594A31613AAF4006C417B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C90E7AA115DC3C3800A06D48 /* Build configuration list for PBXNativeTarget "libpthread.a" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C90E7AA015DC3C3800A06D48 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C90E7AAD15DC3D3300A06D48 /* Build configuration list for PBXAggregateTarget "All" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C90E7AAE15DC3D3300A06D48 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C91D01B6162892FF0002E29A /* Build configuration list for PBXAggregateTarget "Kext" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C91D01B7162892FF0002E29A /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C98832C315DEB44000B3308E /* Build configuration list for PBXAggregateTarget "Embedded" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C98832C215DEB44000B3308E /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C9A325DC15B7347000270056 /* Build configuration list for PBXProject "libpthread" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C9A325E515B7347000270056 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C9A325E615B7347000270056 /* Build configuration list for PBXNativeTarget "libsystem_pthread.dylib" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C9A325E815B7347000270056 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C9CA27E71602813000259F78 /* Build configuration list for PBXNativeTarget "pthread" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C9CA27E61602813000259F78 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = C9A325D915B7347000270056 /* Project object */;
+}
--- /dev/null
+from xnu import *
+import struct
+
+@header("{0: <24s} {1: <16s} {2: <16s} {3: <16s} {4: <16s}".format('sig', 'tid', 'options', 'lseq', 'useq'))
+def GetUserMutexSummary(task, uaddr):
+ if int(task.t_flags) & 0x1:
+ mtxlayout = "QIIhhIQIII"
+ padoffset = 1
+ else:
+ mtxlayout = "QIIhhQIII"
+ padoffset = 0
+
+ data = GetUserDataAsString(task, uaddr, struct.calcsize(mtxlayout))
+ info = struct.unpack(mtxlayout, data)
+
+ format = "{0: <24s} {1: <16s} {2: <16s} {3: <16s} {4: <16s}"
+ sigstr = str("{0: <#020x}".format(info[0]))
+
+ # the options field dictates whether we were created misaligned
+ if info[2] & 0x800:
+ lseq = info[7+padoffset]
+ useq = info[8+padoffset]
+ else:
+ lseq = info[6+padoffset]
+ useq = info[7+padoffset]
+
+ return format.format(sigstr, hex(info[5+padoffset]), hex(info[2]), hex(lseq), hex(useq))
+
+@lldb_command('showusermutex')
+def PthreadShowUserMutex(cmd_args=None):
+ """
+ display information about a userspace mutex at a given address
+ Syntax: (lldb) showusermutex <task_t> <uaddr>
+ """
+ if not cmd_args:
+ raise ArgumentError("No arguments passed")
+ task = kern.GetValueFromAddress(cmd_args[0], "task_t")
+ uaddr = kern.GetValueFromAddress(cmd_args[1], "user_addr_t")
+
+ print GetUserMutexSummary.header
+ print GetUserMutexSummary(task, uaddr)
+
+@lldb_type_summary(['ksyn_waitq_element *', 'ksyn_waitq_element_t'])
+@header("{0: <24s} {1: <24s} {2: <24s} {3: <10s}".format('kwe', 'kwq', 'uaddr', 'type'))
+def GetKweSummary(kwe):
+ format = "{0: <24s} {1: <24s} {2: <24s} {3: <10s}"
+ kwe = Cast(addressof(kwe), "ksyn_waitq_element_t")
+ kwestr = str("{0: <#020x}".format(kwe))
+
+ kwq = Cast(kwe.kwe_kwqqueue, "ksyn_wait_queue_t")
+ kwqstr = str("{0: <#020x}".format(kwq))
+ uaddrstr = str("{0: <#020x}".format(kwq.kw_addr))
+
+ kwqtype = ""
+ if kwq.kw_type & 0xff == 0x01:
+ kwqtype = "mtx"
+ if kwq.kw_type & 0xff == 0x02:
+ kwqtype = "cvar"
+ if kwq.kw_type & 0xff == 0x04:
+ kwqtype = "rwlock"
+ if kwq.kw_type & 0xff == 0x05:
+ kwqtype = "sema"
+
+ return format.format(kwestr, kwqstr, uaddrstr, kwqtype)
+
+@header("{0: <24s} {1: <24s} {2: <24s}".format('thread', 'thread_id', 'uthread'))
+def GetPthreadSummary(thread):
+ format = "{0: <24s} {1: <24s} {2: <24s}"
+
+ threadstr = str("{0: <#020x}".format(thread))
+ if int(thread.static_param):
+ threadstr += "[WQ]"
+
+ uthread = Cast(thread.uthread, "uthread_t")
+ uthreadstr = str("{0: <#020x}".format(uthread))
+
+
+ return format.format(threadstr, hex(thread.thread_id), uthreadstr)
+
+@header("{0: <24s} {1: <24s} {2: <10s} {3: <10s} {4: <10s} {5: <10s} {6: <10s}".format('proc', 'wq', 'sched', 'req', 'idle', 'flags', 'wqflags'))
+def GetPthreadWorkqueueSummary(wq):
+ format = "{0: <24s} {1: <24s} {2: <10d} {3: <10d} {4: <10d} {5: <10s} {6: <10s}"
+ procstr = str("{0: <#020x}".format(wq.wq_proc))
+ wqstr = str("{0: <#020x}".format(wq))
+
+ flags = []
+ if wq.wq_flags & 0x1:
+ flags.append("I")
+ if wq.wq_flags & 0x2:
+ flags.append("R")
+ if wq.wq_flags & 0x4:
+ flags.append("E")
+
+ wqflags = []
+ if wq.wq_lflags & 0x1:
+ wqflags.append("B")
+ if wq.wq_lflags & 0x2:
+ wqflags.append("W")
+ if wq.wq_lflags & 0x4:
+ wqflags.append("C")
+ if wq.wq_lflags & 0x8:
+ wqflags.append("L")
+
+ return format.format(procstr, wqstr, wq.wq_threads_scheduled, wq.wq_reqcount, wq.wq_thidlecount, "".join(flags), "".join(wqflags))
+
+@header("{0: <24s} {1: <5s} {2: <5s} {3: <5s} {4: <5s} {5: <5s} {6: <5s}".format('category', 'uint', 'uinit', 'lgcy', 'util', 'bckgd', 'maint'))
+def GetPthreadWorkqueueDetail(wq):
+ format = " {0: <22s} {1: <5d} {2: <5d} {3: <5d} {4: <5d} {5: <5d} {6: <5d}"
+ # requests
+ reqstr = format.format('requests', wq.wq_requests[0], wq.wq_requests[1], wq.wq_requests[2], wq.wq_requests[3], wq.wq_requests[4], wq.wq_requests[5])
+ ocstr = format.format('ocreqs', wq.wq_ocrequests[0], wq.wq_ocrequests[1], wq.wq_ocrequests[2], wq.wq_ocrequests[3], wq.wq_ocrequests[4], wq.wq_ocrequests[5])
+ schedstr = format.format('scheduled', wq.wq_thscheduled_count[0], wq.wq_thscheduled_count[1], wq.wq_thscheduled_count[2], wq.wq_thscheduled_count[3], wq.wq_thscheduled_count[4], wq.wq_thscheduled_count[5])
+ activestr = format.format('active', wq.wq_thactive_count[0], wq.wq_thactive_count[1], wq.wq_thactive_count[2], wq.wq_thactive_count[3], wq.wq_thactive_count[4], wq.wq_thactive_count[5])
+ return "\n".join([reqstr, ocstr, schedstr, activestr])
+
+@lldb_command('showpthreadstate')
+def PthreadCurrentMutex(cmd_args=None):
+ """
+ display information about a thread's pthread state
+ Syntax: (lldb) showpthreadstate <thread_t>
+ """
+ if not cmd_args:
+ raise ArgumentError("No arguments passed")
+
+ thread = kern.GetValueFromAddress(cmd_args[0], "thread_t")
+ print GetPthreadSummary.header
+ print GetPthreadSummary(thread)
+
+ uthread = Cast(thread.uthread, "uthread_t")
+ kwe = addressof(uthread.uu_kevent.uu_kwe)
+ print GetKweSummary.header
+ print GetKweSummary(kwe)
+
+@lldb_command('showpthreadworkqueue')
+def ShowPthreadWorkqueue(cmd_args=None):
+ """
+ display information about a processes' pthread workqueue
+ Syntax: (lldb) showpthreadworkqueue <proc_t>
+ """
+
+ if not cmd_args:
+ raise ArgumentError("No arguments passed")
+
+ proc = kern.GetValueFromAddress(cmd_args[0], "proc_t")
+ wq = Cast(proc.p_wqptr, "struct workqueue *");
+
+ print GetPthreadWorkqueueSummary.header
+ print GetPthreadWorkqueueSummary(wq)
+
+ print GetPthreadWorkqueueDetail.header
+ print GetPthreadWorkqueueDetail(wq)
+
+def __lldb_init_module(debugger, internal_dict):
+ pass
\ No newline at end of file
--- /dev/null
+.\" Portions Copyright (c) 2001 Apple Computer, Inc. All Rights Reserved.
+.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by John Birrell.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/share/man/man3/pthread.3,v 1.12.2.4 2001/08/17 13:08:36 ru Exp $
+.\"
+.Dd November 5, 2001
+.Dt PTHREAD 3
+.Os Darwin
+.Sh NAME
+.Nm pthread
+.Nd POSIX thread functions
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Sh DESCRIPTION
+POSIX threads are a set of functions that support applications with
+requirements for multiple flows of control, called
+.Fa threads ,
+within a process.
+Multithreading is used to improve the performance of a
+program.
+.Pp
+The POSIX thread functions are summarized in this section in the following
+groups:
+.Bl -bullet -offset indent
+.It
+Thread Routines
+.It
+Attribute Object Routines
+.It
+Mutex Routines
+.It
+Condition Variable Routines
+.It
+Read/Write Lock Routines
+.It
+Per-Thread Context Routines
+.It
+Cleanup Routines
+.El
+.Sh THREAD ROUTINES
+.Bl -tag -width Er
+.It Xo
+.Ft int
+.Fn pthread_create "pthread_t *thread" "const pthread_attr_t *attr" "void *(*start_routine)(void *)" "void *arg"
+.Xc
+Creates a new thread of execution.
+.It Xo
+.Ft int
+.Fn pthread_detach "pthread_t thread"
+.Xc
+Marks a thread for deletion.
+.It Xo
+.Ft int
+.Fn pthread_equal "pthread_t t1" "pthread_t t2"
+.Xc
+Compares two thread IDs.
+.It Xo
+.Ft void
+.Fn pthread_exit "void *value_ptr"
+.Xc
+Terminates the calling thread.
+.It Xo
+.Ft int
+.Fn pthread_join "pthread_t thread" "void **value_ptr"
+.Xc
+Causes the calling thread to wait for the termination of the specified thread.
+.It Xo
+.Ft int
+.Fn pthread_cancel "pthread_t thread"
+.Xc
+Cancels execution of a thread.
+.It Xo
+.Ft int
+.Fn pthread_once "pthread_once_t *once_control" "void (*init_routine)(void)"
+.Xc
+Calls an initialization routine once.
+.It Xo
+.Ft pthread_t
+.Fn pthread_self void
+.Xc
+Returns the thread ID of the calling thread.
+.It Xo
+.Ft int
+.Fn pthread_atfork "void (*prepare)(void)" "void (*parent)(void)" "void (*child)(void)"
+.Xc
+Registers handlers to be called before and after
+.Fn fork
+.El
+.Sh ATTRIBUTE OBJECT ROUTINES
+.Bl -tag -width Er
+.It Xo
+.Ft int
+.Fn pthread_attr_destroy "pthread_attr_t *attr"
+.Xc
+Destroy a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_getinheritsched "const pthread_attr_t *attr" "int *inheritsched"
+.Xc
+Get the inherit scheduling attribute from a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_getschedparam "const pthread_attr_t *attr" "struct sched_param *param"
+.Xc
+Get the scheduling parameter attribute from a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_getschedpolicy "const pthread_attr_t *attr" "int *policy"
+.Xc
+Get the scheduling policy attribute from a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_getscope "const pthread_attr_t *attr" "int *contentionscope"
+.Xc
+Get the contention scope attribute from a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_getstacksize "const pthread_attr_t *attr" "size_t *stacksize"
+.Xc
+Get the stack size attribute from a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_getstackaddr "const pthread_attr_t *attr" "void **stackaddr"
+.Xc
+Get the stack address attribute from a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_getdetachstate "const pthread_attr_t *attr" "int *detachstate"
+.Xc
+Get the detach state attribute from a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_init "pthread_attr_t *attr"
+.Xc
+Initialize a thread attributes object with default values.
+.It Xo
+.Ft int
+.Fn pthread_attr_setinheritsched "pthread_attr_t *attr" "int inheritsched"
+.Xc
+Set the inherit scheduling attribute in a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_setschedparam "pthread_attr_t *attr" "const struct sched_param *param"
+.Xc
+Set the scheduling parameter attribute in a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_setschedpolicy "pthread_attr_t *attr" "int policy"
+.Xc
+Set the scheduling policy attribute in a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_setscope "pthread_attr_t *attr" "int contentionscope"
+.Xc
+Set the contention scope attribute in a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_setstacksize "pthread_attr_t *attr" "size_t stacksize"
+.Xc
+Set the stack size attribute in a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_setstackaddr "pthread_attr_t *attr" "void *stackaddr"
+.Xc
+Set the stack address attribute in a thread attributes object.
+.It Xo
+.Ft int
+.Fn pthread_attr_setdetachstate "pthread_attr_t *attr" "int detachstate"
+.Xc
+Set the detach state in a thread attributes object.
+.El
+.Sh MUTEX ROUTINES
+.Bl -tag -width Er
+.It Xo
+.Ft int
+.Fn pthread_mutexattr_destroy "pthread_mutexattr_t *attr"
+.Xc
+Destroy a mutex attributes object.
+.It Xo
+.Ft int
+.Fn pthread_mutexattr_init "pthread_mutexattr_t *attr"
+.Xc
+Initialize a mutex attributes object with default values.
+.It Xo
+.Ft int
+.Fn pthread_mutex_destroy "pthread_mutex_t *mutex"
+.Xc
+Destroy a mutex.
+.It Xo
+.Ft int
+.Fn pthread_mutex_init "pthread_mutex_t *mutex" "const pthread_mutexattr_t *attr"
+.Xc
+Initialize a mutex with specified attributes.
+.It Xo
+.Ft int
+.Fn pthread_mutex_lock "pthread_mutex_t *mutex"
+.Xc
+Lock a mutex and block until it becomes available.
+.It Xo
+.Ft int
+.Fn pthread_mutex_trylock "pthread_mutex_t *mutex"
+.Xc
+Try to lock a mutex, but don't block if the mutex is locked by another thread,
+including the current thread.
+.It Xo
+.Ft int
+.Fn pthread_mutex_unlock "pthread_mutex_t *mutex"
+.Xc
+Unlock a mutex.
+.El
+.Sh CONDITION VARIABLE ROUTINES
+.Bl -tag -width Er
+.It Xo
+.Ft int
+.Fn pthread_condattr_init "pthread_condattr_t *attr"
+.Xc
+Initialize a condition variable attributes object with default values.
+.It Xo
+.Ft int
+.Fn pthread_condattr_destroy "pthread_condattr_t *attr"
+.Xc
+Destroy a condition variable attributes object.
+.It Xo
+.Ft int
+.Fn pthread_cond_broadcast "pthread_cond_t *cond"
+.Xc
+Unblock all threads currently blocked on the specified condition variable.
+.It Xo
+.Ft int
+.Fn pthread_cond_destroy "pthread_cond_t *cond"
+.Xc
+Destroy a condition variable.
+.It Xo
+.Ft int
+.Fn pthread_cond_init "pthread_cond_t *cond" "const pthread_condattr_t *attr"
+.Xc
+Initialize a condition variable with specified attributes.
+.It Xo
+.Ft int
+.Fn pthread_cond_signal "pthread_cond_t *cond"
+.Xc
+Unblock at least one of the threads blocked on the specified condition variable.
+.It Xo
+.Ft int
+.Fn pthread_cond_timedwait "pthread_cond_t *cond" "pthread_mutex_t *mutex" "const struct timespec *abstime"
+.Xc
+Atomically unlock the specified mutex and block on a condition
+or until the specified time passes.
+.It Xo
+.Ft int
+.Fn pthread_cond_wait "pthread_cond_t *" "pthread_mutex_t *mutex"
+.Xc
+Atomically unlock the specified mutex and block on a condition.
+.El
+.Sh READ/WRITE LOCK ROUTINES
+.Bl -tag -width Er
+.It Xo
+.Ft int
+.Fn pthread_rwlock_destroy "pthread_rwlock_t *lock"
+.Xc
+Destroy a read/write lock object.
+.It Xo
+.Ft int
+.Fn pthread_rwlock_init "pthread_rwlock_t *lock" "const pthread_rwlockattr_t *attr"
+.Xc
+Initialize a read/write lock object.
+.It Xo
+.Ft int
+.Fn pthread_rwlock_rdlock "pthread_rwlock_t *lock"
+.Xc
+Lock a read/write lock for reading, blocking until the lock can be
+acquired.
+.It Xo
+.Ft int
+.Fn pthread_rwlock_tryrdlock "pthread_rwlock_t *lock"
+.Xc
+Attempt to lock a read/write lock for reading, without blocking if the
+lock is unavailable.
+.It Xo
+.Ft int
+.Fn pthread_rwlock_trywrlock "pthread_rwlock_t *lock"
+.Xc
+Attempt to lock a read/write lock for writing, without blocking if the
+lock is unavailable.
+.It Xo
+.Ft int
+.Fn pthread_rwlock_unlock "pthread_rwlock_t *lock"
+.Xc
+Unlock a read/write lock.
+.It Xo
+.Ft int
+.Fn pthread_rwlock_wrlock "pthread_rwlock_t *lock"
+.Xc
+Lock a read/write lock for writing, blocking until the lock can be
+acquired.
+.It Xo
+.Ft int
+.Fn pthread_rwlockattr_destroy "pthread_rwlockattr_t *attr"
+.Xc
+Destroy a read/write lock attribute object.
+.It Xo
+.Ft int
+.Fn pthread_rwlockattr_getpshared "const pthread_rwlockattr_t *attr" "int *pshared"
+.Xc
+Retrieve the process shared setting for the read/write lock attribute
+object.
+.It Xo
+.Ft int
+.Fn pthread_rwlockattr_init "pthread_rwlockattr_t *attr"
+.Xc
+Initialize a read/write lock attribute object.
+.It Xo
+.Ft int
+.Fn pthread_rwlockattr_setpshared "pthread_rwlockattr_t *attr" "int pshared"
+.Xc
+Set the process shared setting for the read/write lock attribute object.
+.El
+.Sh PER-THREAD CONTEXT ROUTINES
+.Bl -tag -width Er
+.It Xo
+.Ft int
+.Fn pthread_key_create "pthread_key_t *key" "void (*routine)(void *)"
+.Xc
+Create a thread-specific data key.
+.It Xo
+.Ft int
+.Fn pthread_key_delete "pthread_key_t key"
+.Xc
+Delete a thread-specific data key.
+.It Xo
+.Ft "void *"
+.Fn pthread_getspecific "pthread_key_t key"
+.Xc
+Get the thread-specific value for the specified key.
+.It Xo
+.Ft int
+.Fn pthread_setspecific "pthread_key_t key" "const void *value_ptr"
+.Xc
+Set the thread-specific value for the specified key.
+.El
+.Sh CLEANUP ROUTINES
+.Bl -tag -width Er
+.It Xo
+.Ft void
+.Fn pthread_cleanup_pop "int execute"
+.Xc
+Remove the routine at the top of the calling thread's cancellation cleanup
+stack and optionally invoke it.
+.It Xo
+.Ft void
+.Fn pthread_cleanup_push "void (*routine)(void *)" "void *routine_arg"
+.Xc
+Push the specified cancellation cleanup handler onto the calling thread's
+cancellation stack.
+.El
+.Sh INSTALLATION
+The default system libraries include
+.Nm pthread
+functions.
+No additional libraries or CFLAGS are necessary to use these interfaces.
+.Sh SEE ALSO
+.Xr pthread_atfork 3 ,
+.Xr pthread_attr 3 ,
+.Xr pthread_attr_init_destroy 3 ,
+.Xr pthread_attr_getdetachstate 3 ,
+.Xr pthread_attr_getinheritsched 3 ,
+.Xr pthread_attr_getschedparam 3 ,
+.Xr pthread_attr_getschedpolicy 3 ,
+.Xr pthread_attr_getscope 3 ,
+.Xr pthread_attr_getstackaddr 3 ,
+.Xr pthread_attr_getstacksize 3 ,
+.Xr pthread_attr_init 3 ,
+.Xr pthread_attr_init_destroy 3 ,
+.Xr pthread_attr_setdetachstate 3 ,
+.Xr pthread_attr_setinheritsched 3 ,
+.Xr pthread_attr_setschedparam 3 ,
+.Xr pthread_attr_setschedpolicy 3 ,
+.Xr pthread_attr_setscope 3 ,
+.Xr pthread_attr_setstackaddr 3 ,
+.Xr pthread_attr_setstacksize 3 ,
+.Xr pthread_cancel 3 ,
+.Xr pthread_cleanup_pop 3 ,
+.Xr pthread_cleanup_push 3 ,
+.Xr pthread_cond_broadcast 3 ,
+.Xr pthread_cond_destroy 3 ,
+.Xr pthread_cond_init 3 ,
+.Xr pthread_cond_signal 3 ,
+.Xr pthread_cond_timedwait 3 ,
+.Xr pthread_cond_wait 3 ,
+.Xr pthread_condattr 3 ,
+.Xr pthread_condattr_destroy 3 ,
+.Xr pthread_condattr_init 3 ,
+.Xr pthread_create 3 ,
+.Xr pthread_detach 3 ,
+.Xr pthread_equal 3 ,
+.Xr pthread_exit 3 ,
+.Xr pthread_getschedparam 3 ,
+.Xr pthread_getspecific 3 ,
+.Xr pthread_join 3 ,
+.Xr pthread_key_create 3 ,
+.Xr pthread_key_delete 3 ,
+.Xr pthread_mutex_destroy 3 ,
+.Xr pthread_mutex_init 3 ,
+.Xr pthread_mutex_lock 3 ,
+.Xr pthread_mutex_trylock 3 ,
+.Xr pthread_mutex_unlock 3 ,
+.Xr pthread_mutexattr 3 ,
+.Xr pthread_mutexattr_destroy 3 ,
+.Xr pthread_mutexattr_getprioceiling 3 ,
+.Xr pthread_mutexattr_getprotocol 3 ,
+.Xr pthread_mutexattr_gettype 3 ,
+.Xr pthread_mutexattr_init 3 ,
+.Xr pthread_mutexattr_setprioceiling 3 ,
+.Xr pthread_mutexattr_setprotocol 3 ,
+.Xr pthread_mutexattr_settype 3 ,
+.Xr pthread_once 3 ,
+.Xr pthread_rwlock_destroy 3 ,
+.Xr pthread_rwlock_init 3 ,
+.Xr pthread_rwlock_rdlock 3 ,
+.Xr pthread_rwlock_tryrdlock 3 ,
+.Xr pthread_rwlock_trywrlock 3 ,
+.Xr pthread_rwlock_unlock 3 ,
+.Xr pthread_rwlock_wrlock 3 ,
+.Xr pthread_rwlockattr_destroy 3 ,
+.Xr pthread_rwlockattr_getpshared 3 ,
+.Xr pthread_rwlockattr_init 3 ,
+.Xr pthread_rwlockattr_setpshared 3 ,
+.Xr pthread_self 3 ,
+.Xr pthread_setcancelstate 3
+.Xr pthread_setcanceltype 3
+.Xr pthread_setschedparam 3
+.Xr pthread_setspecific 3
+.Xr pthread_testcancel 3
+.Sh STANDARDS
+The functions with the
+.Fa pthread_
+prefix and not
+.Fa _np
+suffix or
+.Fa pthread_rwlock
+prefix conform to
+.St -p1003.1-96 .
+.Pp
+The functions with the
+.Fa pthread_
+prefix and
+.Fa _np
+suffix are non-portable extensions to POSIX threads.
+.Pp
+The functions with the
+.Fa pthread_rwlock
+prefix are extensions created by The Open Group as part of the
+.St -susv2 .
--- /dev/null
+.\" Copyright (c) 2004 Apple Computer, Inc.
+.\"
+.Dd August 12, 2004
+.Dt PTHREAD_ATFORK 3
+.Os
+.Sh NAME
+.Nm pthread_atfork
+.Nd register handlers to be called before and after
+.Fn fork
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fn pthread_atfork "void (*prepare)(void)" "void (*parent)(void)" "void (*child)(void)"
+.Sh DESCRIPTION
+The
+.Fn pthread_atfork
+function is used to register functions to be called before and after
+.Fn fork .
+The
+.Fa prepare
+handler is called before
+.Fn fork ,
+while the
+.Fa parent
+and
+.Fa child
+handlers are called after
+.Fn fork
+in the parent and child process respectively.
+The
+.Fa prepare
+handlers are called in reverse order of their registration, while
+.Fa parent
+and
+.Fa child
+handlers are called in the order in which they were registered.
+Any of the handlers may be NULL.
+.Pp
+.Em Important :
+only async-signal-safe functions are allowed on the child side of
+.Fn fork .
+See
+.Xr sigaction 2
+for details.
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_atfork
+function will return zero; otherwise an error number will be returned to
+indicate the error.
+.Sh ERRORS
+.Fn pthread_atfork
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+The system lacked the necessary resources to add another handler to the list.
+.El
+.Sh SEE ALSO
+.Xr fork 2
+.Sh STANDARDS
+.Fn pthread_atfork
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (C) 2000 Jason Evans <jasone@FreeBSD.org>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_attr.3,v 1.4.2.5 2001/08/17 15:42:51 ru Exp $
+.Dd April 28, 2000
+.Dt PTHREAD_ATTR 3
+.Os
+.Sh NAME
+.Nm pthread_attr_destroy ,
+.Nm pthread_attr_getdetachstate ,
+.Nm pthread_attr_getinheritsched ,
+.Nm pthread_attr_getschedparam ,
+.Nm pthread_attr_getschedpolicy ,
+.Nm pthread_attr_getscope ,
+.Nm pthread_attr_getstackaddr ,
+.Nm pthread_attr_getstacksize ,
+.Nm pthread_attr_init ,
+.Nm pthread_attr_setdetachstate ,
+.Nm pthread_attr_setinheritsched ,
+.Nm pthread_attr_setschedparam ,
+.Nm pthread_attr_setschedpolicy ,
+.Nm pthread_attr_setscope ,
+.Nm pthread_attr_setstackaddr ,
+.Nm pthread_attr_setstacksize
+.Nd thread attribute operations
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_attr_destroy
+.Fa "pthread_attr_t *attr"
+.Fc
+.Ft int
+.Fo pthread_attr_getdetachstate
+.Fa "const pthread_attr_t *attr"
+.Fa "int *detachstate"
+.Fc
+.Ft int
+.Fo pthread_attr_getinheritsched
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "int *restrict inheritsched"
+.Fc
+.Ft int
+.Fo pthread_attr_getschedparam
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "struct sched_param *restrict param"
+.Fc
+.Ft int
+.Fo pthread_attr_getschedpolicy
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "int *restrict policy"
+.Fc
+.Ft int
+.Fo pthread_attr_getscope
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "int *restrict contentionscope"
+.Fc
+.Ft int
+.Fo pthread_attr_getstackaddr
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "void **restrict stackaddr"
+.Fc
+.Ft int
+.Fo pthread_attr_getstacksize
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "size_t *restrict stacksize"
+.Fc
+.Ft int
+.Fo pthread_attr_init
+.Fa "pthread_attr_t *attr"
+.Fc
+.Ft int
+.Fo pthread_attr_setdetachstate
+.Fa "pthread_attr_t *attr"
+.Fa "int detachstate"
+.Fc
+.Ft int
+.Fo pthread_attr_setinheritsched
+.Fa "pthread_attr_t *attr"
+.Fa "int inheritsched"
+.Fc
+.Ft int
+.Fo pthread_attr_setschedparam
+.Fa "pthread_attr_t *restrict attr"
+.Fa "const struct sched_param *restrict param"
+.Fc
+.Ft int
+.Fo pthread_attr_setschedpolicy
+.Fa "pthread_attr_t *attr"
+.Fa "int policy"
+.Fc
+.Ft int
+.Fo pthread_attr_setscope
+.Fa "pthread_attr_t *attr"
+.Fa "int contentionscope"
+.Fc
+.Ft int
+.Fo pthread_attr_setstackaddr
+.Fa "pthread_attr_t *attr"
+.Fa "void *stackaddr"
+.Fc
+.Ft int
+.Fo pthread_attr_setstacksize
+.Fa "pthread_attr_t *attr"
+.Fa "size_t stacksize"
+.Fc
+.Sh DESCRIPTION
+Thread attributes are used to specify parameters to
+.Fn pthread_create .
+One attribute object can be used in multiple calls to
+.Fn pthread_create ,
+with or without modifications between calls.
+.Pp
+The
+.Fn pthread_attr_init
+function initializes
+.Fa attr
+with all the default thread attributes.
+.Pp
+The
+.Fn pthread_attr_destroy
+function destroys
+.Fa attr .
+.Pp
+The
+.Fn pthread_attr_set*
+functions set the attribute that corresponds to each function name.
+.Pp
+The
+.Fn pthread_attr_get*
+functions copy the value of the attribute that corresponds to each function name
+to the location pointed to by the second function parameter.
+.Sh RETURN VALUES
+If successful, these functions return 0.
+Otherwise, an error number is returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_attr_init
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er ENOMEM
+Out of memory.
+.El
+.Pp
+.Fn pthread_attr_destroy
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.El
+.Pp
+.Fn pthread_attr_setstacksize
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.\" ========
+.It Bq Er EINVAL
+.Fa stacksize
+is less than
+.Dv PTHREAD_STACK_MIN .
+.\" ========
+.It Bq Er EINVAL
+.Fa stacksize
+is not a multiple of the system page size.
+.El
+.Pp
+.Fn pthread_attr_setdetachstate
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr
+or
+.Fa detachstate .
+.El
+.Pp
+.Fn pthread_attr_setinheritsched
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.El
+.Pp
+.Fn pthread_attr_setschedparam
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.\" ========
+.It Bq Er ENOTSUP
+Invalid value for
+.Fa param .
+.El
+.Pp
+.Fn pthread_attr_setschedpolicy
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.It Bq Er ENOTSUP
+Invalid or unsupported value for
+.Fa policy .
+.El
+.Pp
+.Fn pthread_attr_setscope
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.\" ========
+.It Bq Er ENOTSUP
+Invalid or unsupported value for
+.Fa contentionscope .
+.El
+.Sh SEE ALSO
+.Xr pthread_create 3
+.Sh STANDARDS
+.Fn pthread_attr_init ,
+.Fn pthread_attr_destroy ,
+.Fn pthread_attr_setstacksize ,
+.Fn pthread_attr_getstacksize ,
+.Fn pthread_attr_setstackaddr ,
+.Fn pthread_attr_getstackaddr ,
+.Fn pthread_attr_setdetachstate ,
+and
+.Fn pthread_attr_getdetachstate
+conform to
+.St -p1003.1-96
+.Pp
+.Fn pthread_attr_setinheritsched ,
+.Fn pthread_attr_getinheritsched ,
+.Fn pthread_attr_setschedparam ,
+.Fn pthread_attr_getschedparam ,
+.Fn pthread_attr_setschedpolicy ,
+.Fn pthread_attr_getschedpolicy ,
+.Fn pthread_attr_setscope ,
+and
+.Fn pthread_attr_getscope
+conform to
+.St -susv2
--- /dev/null
+.\" Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+.Dd December 31, 2007
+.Dt PTHREAD_ATTR 3
+.Os
+.Sh NAME
+.Nm pthread_attr_destroy ,
+.Nm pthread_attr_init
+.Nd thread attribute operations
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_attr_destroy
+.Fa "pthread_attr_t *attr"
+.Fc
+.Ft int
+.Fo pthread_attr_init
+.Fa "pthread_attr_t *attr"
+.Fc
+.Sh DESCRIPTION
+Thread attributes are used to specify parameters to
+.Fn pthread_create .
+One attribute object can be used in multiple calls to
+.Fn pthread_create ,
+with or without modifications between calls.
+.Pp
+The
+.Fn pthread_attr_init
+function initializes
+.Fa attr
+with all the default thread attributes.
+.Pp
+The
+.Fn pthread_attr_destroy
+function destroys
+.Fa attr .
+.Sh RETURN VALUES
+If successful, these functions return 0.
+Otherwise, an error number is returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_attr_init
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er ENOMEM
+Out of memory.
+.El
+.Pp
+.Fn pthread_attr_destroy
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.El
+.Pp
+.Sh SEE ALSO
+.Xr pthread_create 3
+.Sh STANDARDS
+.Fn pthread_attr_init ,
+.Fn pthread_attr_destroy
+conform to
+.St -p1003.1-96
+.Pp
--- /dev/null
+.\" Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+.Dd December 31, 2007
+.Dt PTHREAD_ATTR 3
+.Os
+.Sh NAME
+.Nm pthread_attr_getdetachstate ,
+.Nm pthread_attr_setdetachstate
+.Nd thread attribute operations
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_attr_getdetachstate
+.Fa "const pthread_attr_t *attr"
+.Fa "int *detachstate"
+.Fc
+.Ft int
+.Fo pthread_attr_setdetachstate
+.Fa "pthread_attr_t *attr"
+.Fa "int detachstate"
+.Fc
+.Sh DESCRIPTION
+Thread attributes are used to specify parameters to
+.Fn pthread_create .
+One attribute object can be used in multiple calls to
+.Fn pthread_create ,
+with or without modifications between calls.
+.Pp
+One of these thread attributes governs the creation state of the new thread. The new thread
+can be either created "detached" or "joinable". The constants corresponding to these states are PTHREAD_CREATE_DETACHED and PTHREAD_CREATE_JOINABLE respectively.
+Creating a "joinable" thread allows the user
+to call
+.Fn pthread_join
+and
+.Fn pthread_detach ,
+with the new thread's ID. A "detached" thread's ID cannot be used with
+.Fn pthread_join
+and
+.Fn pthread_detach .
+The default value for the "detachstate" attribute is PTHREAD_CREATE_JOINABLE.
+.Pp
+The
+.Fn pthread_attr_setdetachstate
+function sets the thread's "detachstate" attribute.
+.Pp
+The "detachstate" attribute is set within the
+.Fa attr
+argument, which can subsequently be used as an argument to
+.Fn pthread_create .
+.Sh RETURN VALUES
+If successful, these functions return 0.
+Otherwise, an error number is returned to indicate the error.
+.Fn pthread_attr_getdetachstate ,
+on success, will copy the value of the thread's "detachstate" attribute
+to the location pointed to by the second function parameter.
+.Sh ERRORS
+.Fn pthread_attr_getdetachstate
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr
+.El
+.Pp
+.Fn pthread_attr_setdetachstate
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr
+or
+.Fa detachstate .
+.El
+.Pp
+.Sh SEE ALSO
+.Xr pthread_create 3 ,
+.Xr pthread_join 3 ,
+.Xr pthread_attr_init 3 ,
+.Xr pthread_detach 3
+.Sh STANDARDS
+.Fn pthread_attr_setdetachstate ,
+.Fn pthread_attr_getdetachstate
+conform to
+.St -p1003.1-96
+.Pp
--- /dev/null
+.\" Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+.Dd December 31, 2007
+.Dt PTHREAD_ATTR 3
+.Os
+.Sh NAME
+.Nm pthread_attr_getinheritsched ,
+.Nm pthread_attr_setinheritsched
+.Nd thread attribute operations
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_attr_getinheritsched
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "int *restrict inheritsched"
+.Fc
+.Ft int
+.Fo pthread_attr_setinheritsched
+.Fa "pthread_attr_t *attr"
+.Fa "int inheritsched"
+.Fc
+.Sh DESCRIPTION
+Thread attributes are used to specify parameters to
+.Fn pthread_create .
+One attribute object can be used in multiple calls to
+.Fn pthread_create ,
+with or without modifications between calls.
+.Pp
+One of the thread attributes of interest is the "inheritsched" attribute. This attribute
+controls the scheduling policy and related attributes of the newly created thread. The values of the
+"inheritsched" attribute can be either PTHREAD_INHERIT_SCHED or PTHREAD_EXPLICIT_SCHED.
+.Pp
+PTHREAD_INHERIT_SCHED
+.Pp
+ Indicates that the newly created thread should inherit all it's scheduling related attributes from it's creating
+thread. It ignores the values of the relevant attributes within the
+.Fa attr
+argument.
+.Pp
+PTHREAD_EXPLICIT_SCHED
+.Pp
+ Indicates that the newly created thread should set it's scheduling related attributes based on
+.Fa attr
+argument.
+.Pp
+The
+.Fn pthread_attr_setinheritsched
+functions set the "inheritsched" attribute within the
+.Fa attr
+argument to the desired value.
+.Pp
+The
+.Fn pthread_attr_getinheritsched
+functions copy the value of the "inheritsched" attribute to the location pointed to by the second function parameter.
+.Sh RETURN VALUES
+If successful, these functions return 0.
+Otherwise, an error number is returned to indicate the error.
+.Sh ERRORS
+.Pp
+.Fn pthread_attr_getinheritsched
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.El
+.Pp
+.Fn pthread_attr_setinheritsched
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.El
+.Sh SEE ALSO
+.Xr pthread_create 3 ,
+.Xr pthread_attr_init 3 ,
+.Xr pthread_attr_setschedparam 3
+.Sh STANDARDS
+.Pp
+.Fn pthread_attr_setinheritsched ,
+.Fn pthread_attr_getinheritsched
+conform to
+.St -susv2
--- /dev/null
+.\" Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+.Dd December 31, 2007
+.Dt PTHREAD_ATTR 3
+.Os
+.Sh NAME
+.Nm pthread_attr_getschedparam ,
+.Nm pthread_attr_setschedparam
+.Nd thread attribute operations
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_attr_getschedparam
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "struct sched_param *restrict param"
+.Fc
+.Ft int
+.Fo pthread_attr_setschedparam
+.Fa "pthread_attr_t *restrict attr"
+.Fa "const struct sched_param *restrict param"
+.Fc
+.Sh DESCRIPTION
+Thread attributes are used to specify parameters to
+.Fn pthread_create .
+One attribute object can be used in multiple calls to
+.Fn pthread_create ,
+with or without modifications between calls.
+.Pp
+.Fn pthread_attr_getschedparam
+and
+.Fn pthread_attr_setschedparam
+get and set the scheduling parameters within the
+.Fa attr
+argument. See
+.Fd /usr/include/sched.h
+for the definition of
+.Fa struct sched_param .
+The
+.Fa sched_priority
+field of
+.Fa struct sched_param
+can be set to SCHED_OTHER, SCHED_FIFO and SCHED_RR.
+.Sh RETURN VALUES
+If successful, these functions return 0.
+Otherwise, an error number is returned to indicate the error.
+.Fn pthread_attr_getschedparam ,
+on success, will copy the value of the thread's scheduling parameter attribute
+to the location pointed to by the second function parameter.
+.Sh ERRORS
+.Pp
+.Fn pthread_attr_getschedparam
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.\" ========
+.El
+.Pp
+.Fn pthread_attr_setschedparam
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.\" ========
+.It Bq Er ENOTSUP
+Invalid value for
+.Fa param .
+.El
+.Sh SEE ALSO
+.Xr pthread_create 3 ,
+.Xr pthread_attr_init 3 ,
+.Xr pthread_attr_setinheritsched 3
+.Sh STANDARDS
+.Pp
+.Fn pthread_attr_setschedparam ,
+.Fn pthread_attr_getschedparam
+conform to
+.St -susv2
--- /dev/null
+.\" Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+.Dd December 31, 2007
+.Dt PTHREAD_ATTR 3
+.Os
+.Sh NAME
+.Nm pthread_attr_getschedpolicy ,
+.Nm pthread_attr_setschedpolicy
+.Nd thread attribute operations
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_attr_getschedpolicy
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "int *restrict policy"
+.Fc
+.Ft int
+.Fo pthread_attr_setschedpolicy
+.Fa "pthread_attr_t *attr"
+.Fa "int policy"
+.Fc
+.Sh DESCRIPTION
+Thread attributes are used to specify parameters to
+.Fn pthread_create .
+One attribute object can be used in multiple calls to
+.Fn pthread_create ,
+with or without modifications between calls.
+.Pp
+The functions
+.Fn pthread_attr_setschedpolicy
+and
+.Fn pthread_attr_getschedpolicy ,
+set and get the attribute in the
+.Fa attr
+argument related to the scheduling policy.
+The value for the aforementioned attribute can be SCHED_FIFO, SCHED_RR and SCHED_OTHER.
+.Sh RETURN VALUES
+If successful, these functions return 0.
+Otherwise, an error number is returned to indicate the error.
+.Fn pthread_attr_getschedpolicy ,
+on success, will copy the value of the thread's scheduling policy attribute
+to the location pointed to by the second function parameter.
+.Sh ERRORS
+.Pp
+.Fn pthread_attr_getschedpolicy
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.El
+.Pp
+.Fn pthread_attr_setschedpolicy
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.It Bq Er ENOTSUP
+Invalid or unsupported value for
+.Fa policy .
+.El
+.Sh SEE ALSO
+.Xr pthread_create 3 ,
+.Xr pthread_attr_init 3 ,
+.Xr pthread_attr_setschedparam 3 ,
+.Xr pthread_attr_setinheritsched 3
+.Sh STANDARDS
+.Fn pthread_attr_setschedpolicy ,
+.Fn pthread_attr_getschedpolicy
+conform to
+.St -susv2
--- /dev/null
+.\" Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+.Dd December 31, 2007
+.Dt PTHREAD_ATTR 3
+.Os
+.Sh NAME
+.Nm pthread_attr_getscope ,
+.Nm pthread_attr_setscope
+.Nd thread attribute operations
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_attr_getscope
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "int *restrict contentionscope"
+.Fc
+.Ft int
+.Fo pthread_attr_setscope
+.Fa "pthread_attr_t *attr"
+.Fa "int contentionscope"
+.Fc
+.Sh DESCRIPTION
+Thread attributes are used to specify parameters to
+.Fn pthread_create .
+One attribute object can be used in multiple calls to
+.Fn pthread_create ,
+with or without modifications between calls.
+.Pp
+The
+.Fn pthread_attr_setscope
+and
+.Fn pthread_attr_getscope
+functions, respectively, set and get the attribute within
+.Fa attr
+argument that controls the contention scope of the thread.
+The acceptable values are PTHREAD_SCOPE_SYSTEM, indicating a scheduling contention scope that
+is system-wide, and PTHREAD_SCOPE_PROCESS, which indicates a process scheduling contention scope.
+Currently on Mac OS X we only support PTHREAD_SCOPE_SYSTEM.
+.Sh RETURN VALUES
+If successful, these functions return 0.
+Otherwise, an error number is returned to indicate the error.
+.Sh ERRORS
+.Pp
+.Fn pthread_attr_getscope
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.\" ========
+.El
+.Pp
+.Fn pthread_attr_setscope
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.\" ========
+.It Bq Er ENOTSUP
+Invalid or unsupported value for
+.Fa contentionscope .
+.El
+.Sh SEE ALSO
+.Xr pthread_create 3 ,
+.Xr pthread_attr_init 3 ,
+.Xr pthread_attr_setinheritsched 3 ,
+.Xr pthread_attr_setschedpolicy 3 ,
+.Xr pthread_attr_setschedparam 3
+.Sh STANDARDS
+.Fn pthread_attr_setscope ,
+.Fn pthread_attr_getscope
+conform to
+.St -susv2
--- /dev/null
+.\" Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+.Dd December 31, 2007
+.Dt PTHREAD_ATTR 3
+.Os
+.Sh NAME
+.Nm pthread_attr_getstackaddr ,
+.Nm pthread_attr_setstackaddr
+.Nd thread attribute operations
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_attr_getstackaddr
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "void **restrict stackaddr"
+.Fc
+.Ft int
+.Fo pthread_attr_setstackaddr
+.Fa "pthread_attr_t *attr"
+.Fa "void *stackaddr"
+.Fc
+.Sh DESCRIPTION
+Thread attributes are used to specify parameters to
+.Fn pthread_create .
+One attribute object can be used in multiple calls to
+.Fn pthread_create ,
+with or without modifications between calls.
+.Pp
+The functions
+.Fn pthread_attr_setstackaddr
+and
+.Fn pthread_attr_getstackaddr
+respectively, set and get the address at which the stack of the newly created thread should be located.
+The stackaddr attribute is set within the
+.Fa attr
+argument, which can subsequently be used as an argument to
+.Fn pthread_create .
+.Sh RETURN VALUES
+If successful, these functions return 0.
+Otherwise, an error number is returned to indicate the error.
+.Fn pthread_attr_getstackaddr
+returns the stackaddr attribute value in
+.Fa stackaddr
+if successful.
+.Sh ERRORS
+.Fn pthread_attr_setstackaddr
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.\" ========
+.El
+.Pp
+.Fn pthread_attr_getstackaddr
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.\" ========
+.El
+.Pp
+.Sh SEE ALSO
+.Xr pthread_create 3 ,
+.Xr pthread_attr_init 3 ,
+.Xr pthread_attr_setdetachstate 3 ,
+.Xr pthread_attr_setstacksize 3
+.Sh STANDARDS
+.Fn pthread_attr_setstackaddr ,
+.Fn pthread_attr_getstackaddr ,
+conform to
+.St -p1003.1-96
--- /dev/null
+.\" Copyright (c) 2004-2007 Apple Inc. All rights reserved.
+.Dd December 31, 2007
+.Dt PTHREAD_ATTR 3
+.Os
+.Sh NAME
+.Nm pthread_attr_getstacksize ,
+.Nm pthread_attr_setstacksize
+.Nd thread attribute operations
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_attr_getstacksize
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "size_t *restrict stacksize"
+.Fc
+.Ft int
+.Fo pthread_attr_setstacksize
+.Fa "pthread_attr_t *attr"
+.Fa "size_t stacksize"
+.Fc
+.Sh DESCRIPTION
+Thread attributes are used to specify parameters to
+.Fn pthread_create .
+One attribute object can be used in multiple calls to
+.Fn pthread_create ,
+with or without modifications between calls.
+.Pp
+The functions
+.Fn pthread_attr_setstacksize
+and
+.Fn pthread_attr_getstacksize ,
+respectively, set and get the size of the stack that is to be created for the new thread. The stack size attribute is set within the
+.Fa attr
+argument, which can subsequently be used as an argument to
+.Fn pthread_create .
+.Sh RETURN VALUES
+If successful, these functions return 0.
+Otherwise, an error number is returned to indicate the error.
+.Fn pthread_attr_getstacksize
+returns the stacksize attribute value in
+.Fa stacksize
+if successful.
+.Sh ERRORS
+.Fn pthread_attr_getstacksize
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.El
+.Pp
+.Fn pthread_attr_setstacksize
+will fail if:
+.Bl -tag -width Er
+.\" ========
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.\" ========
+.It Bq Er EINVAL
+.Fa stacksize
+is less than
+.Dv PTHREAD_STACK_MIN .
+.\" ========
+.It Bq Er EINVAL
+.Fa stacksize
+is not a multiple of the system page size.
+.El
+.Sh SEE ALSO
+.Xr pthread_create 3 ,
+.Xr pthread_attr_init 3 ,
+.Xr pthread_attr_setstackaddr 3
+.Sh STANDARDS
+.Fn pthread_attr_setstacksize ,
+.Fn pthread_attr_getstacksize
+conform to
+.St -p1003.1-96
--- /dev/null
+.\" $FreeBSD: src/lib/libc_r/man/pthread_cancel.3,v 1.3.2.3 2001/03/06 16:46:08 ru Exp $
+.Dd January 17, 1999
+.Dt PTHREAD_CANCEL 3
+.Os
+.Sh NAME
+.Nm pthread_cancel
+.Nd cancel execution of a thread
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fn pthread_cancel "pthread_t thread"
+.Sh DESCRIPTION
+The
+.Fn pthread_cancel
+function requests that
+.Fa thread
+be canceled.
+The target thread's cancelability state and type determines
+when the cancellation takes effect.
+When the cancellation is acted on,
+the cancellation cleanup handlers for
+.Fa thread
+are called.
+When the last cancellation cleanup handler returns,
+the thread-specific data destructor functions will be called for
+.Fa thread .
+When the last destructor function returns,
+.Fa thread
+will be terminated.
+.Pp
+The cancellation processing in the target thread runs asynchronously with
+respect to the calling thread returning from
+.Fn pthread_cancel .
+.Pp
+A status of
+.Dv PTHREAD_CANCELED
+is made available to any threads joining with the target.
+The symbolic
+constant
+.Dv PTHREAD_CANCELED
+expands to a constant expression of type
+.Ft "(void *)" ,
+whose value matches no pointer to an object in memory nor the value
+.Dv NULL .
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_cancel
+functions will return zero.
+Otherwise an error number will be returned to
+indicate the error.
+.Sh ERRORS
+.Fn pthread_cancel
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+No thread could be found corresponding to that specified by the given
+thread ID.
+.El
+.Sh SEE ALSO
+.Xr pthread_cleanup_pop 3 ,
+.Xr pthread_cleanup_push 3 ,
+.Xr pthread_exit 3 ,
+.Xr pthread_join 3 ,
+.Xr pthread_setcancelstate 3 ,
+.Xr pthread_setcanceltype 3 ,
+.Xr pthread_testcancel 3
+.Sh STANDARDS
+.Fn pthread_cancel
+conforms to
+.St -p1003.1-96 .
+.Sh AUTHORS
+This man page was written by
+.An David Leonard Aq d@openbsd.org
+for the
+.Ox
+implementation of
+.Fn pthread_cancel .
--- /dev/null
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_cleanup_pop.3,v 1.5.2.3 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd July 30, 1998
+.Dt PTHREAD_CLEANUP_POP 3
+.Os
+.Sh NAME
+.Nm pthread_cleanup_pop
+.Nd call the first cleanup routine
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft void
+.Fn pthread_cleanup_pop "int execute"
+.Sh DESCRIPTION
+The
+.Fn pthread_cleanup_pop
+function pops the top cleanup routine off
+of the current thread's cleanup routine stack and, if
+.Fa execute
+is non-zero, it will execute the function.
+If there is no cleanup routine,
+.Fn pthread_cleanup_pop
+does nothing.
+.Pp
+.Fn pthread_cleanup_pop
+must be paired with a corresponding
+.Xr pthread_cleanup_push 3
+in the same lexical scope.
+.Sh RETURN VALUES
+.Fn pthread_cleanup_pop
+does not return any value.
+.Sh ERRORS
+None
+.Sh SEE ALSO
+.Xr pthread_cleanup_push 3 ,
+.Xr pthread_exit 3
+.Sh STANDARDS
+.Fn pthread_cleanup_pop
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_cleanup_push.3,v 1.5.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd July 30, 1998
+.Dt PTHREAD_CLEANUP_PUSH 3
+.Os
+.Sh NAME
+.Nm pthread_cleanup_push
+.Nd add a cleanup function for thread exit
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft void
+.Fo pthread_cleanup_push
+.Fa "void \*[lp]*routine\*[rp]\*[lp]void *\*[rp]"
+.Fa "void *arg"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_cleanup_push
+function adds
+.Fa routine
+to the top of the stack of cleanup handlers that
+get called when the current thread exits.
+.Pp
+When
+.Fa routine
+is called, it is passed
+.Fa arg
+as its only argument.
+.Fn pthread_cleanup_push
+must be paired with a corresponding
+.Xr pthread_cleanup_pop 3
+in the same lexical scope.
+.Sh RETURN VALUES
+.Fn pthread_cleanup_push
+does not return any value.
+.Sh ERRORS
+None
+.Sh SEE ALSO
+.Xr pthread_cleanup_pop 3 ,
+.Xr pthread_exit 3
+.Sh STANDARDS
+.Fn pthread_cleanup_push
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_cond_broadcast.3,v 1.5.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd July 28, 1998
+.Dt PTHREAD_COND_BROADCAST 3
+.Os
+.Sh NAME
+.Nm pthread_cond_broadcast
+.Nd unblock all threads waiting for a condition variable
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fn pthread_cond_broadcast "pthread_cond_t *cond"
+.Sh DESCRIPTION
+The
+.Fn pthread_cond_broadcast
+function unblocks all threads that are waiting for the condition variable
+.Fa cond .
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_cond_broadcast
+function will return zero.
+Otherwise, an error number will be returned
+to indicate the error.
+.Sh ERRORS
+.Fn pthread_cond_broadcast
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value specified by
+.Fa cond
+is invalid.
+.El
+.Sh SEE ALSO
+.Xr pthread_cond_destroy 3 ,
+.Xr pthread_cond_init 3 ,
+.Xr pthread_cond_signal 3 ,
+.Xr pthread_cond_timedwait 3 ,
+.Xr pthread_cond_wait 3
+.Sh STANDARDS
+.Fn pthread_cond_broadcast
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_cond_destroy.3,v 1.6.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd July 28, 1998
+.Dt PTHREAD_COND_DESTROY 3
+.Os
+.Sh NAME
+.Nm pthread_cond_destroy
+.Nd destroy a condition variable
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fn pthread_cond_destroy "pthread_cond_t *cond"
+.Sh DESCRIPTION
+The
+.Fn pthread_cond_destroy
+function frees the resources allocated by the condition variable
+.Fa cond .
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_cond_destroy
+function will return zero.
+Otherwise, an error number will be returned
+to indicate the error.
+.Sh ERRORS
+.Fn pthread_cond_destroy
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The variable
+.Fa cond
+is locked by another thread.
+.It Bq Er EINVAL
+The value specified by
+.Fa cond
+is invalid.
+.El
+.Sh SEE ALSO
+.Xr pthread_cond_broadcast 3 ,
+.Xr pthread_cond_init 3 ,
+.Xr pthread_cond_signal 3 ,
+.Xr pthread_cond_timedwait 3 ,
+.Xr pthread_cond_wait 3
+.Sh STANDARDS
+.Fn pthread_cond_destroy
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_cond_init.3,v 1.6.2.5 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd July 28, 1998
+.Dt PTHREAD_COND_INIT 3
+.Os
+.Sh NAME
+.Nm pthread_cond_init
+.Nd create a condition variable
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_cond_init
+.Fa "pthread_cond_t *restrict cond"
+.Fa "const pthread_condattr_t *restrict attr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_cond_init
+function creates a new condition variable, with attributes specified with
+.Fa attr .
+If
+.Fa attr
+is NULL, the default attributes are used.
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_cond_init
+function will return zero and put the new condition variable id into
+.Fa cond .
+Otherwise, an error number will be returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_cond_init
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The system temporarily lacks the resources to create another condition
+variable.
+.It Bq Er EINVAL
+The value specified by
+.Fa attr
+is invalid.
+.It Bq Er ENOMEM
+The process cannot allocate enough memory to create another condition
+variable.
+.El
+.Sh SEE ALSO
+.Xr pthread_cond_broadcast 3 ,
+.Xr pthread_cond_destroy 3 ,
+.Xr pthread_cond_signal 3 ,
+.Xr pthread_cond_timedwait 3 ,
+.Xr pthread_cond_wait 3
+.Sh STANDARDS
+.Fn pthread_cond_init
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_cond_signal.3,v 1.5.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd July 28, 1998
+.Dt PTHREAD_COND_SIGNAL 3
+.Os
+.Sh NAME
+.Nm pthread_cond_signal
+.Nd unblock a thread waiting for a condition variable
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fn pthread_cond_signal "pthread_cond_t *cond"
+.Sh DESCRIPTION
+The
+.Fn pthread_cond_signal
+function unblocks one thread waiting for the condition variable
+.Fa cond .
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_cond_signal
+function will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_cond_signal
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value specified by
+.Fa cond
+is invalid.
+.El
+.Sh SEE ALSO
+.Xr pthread_cond_broadcast 3 ,
+.Xr pthread_cond_destroy 3 ,
+.Xr pthread_cond_init 3 ,
+.Xr pthread_cond_timedwait 3 ,
+.Xr pthread_cond_wait 3
+.Sh STANDARDS
+.Fn pthread_cond_signal
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_cond_timedwait.3,v 1.8.2.6 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd July 28, 1998
+.Dt PTHREAD_COND_TIMEDWAIT 3
+.Os
+.Sh NAME
+.Nm pthread_cond_timedwait
+.Nd "wait on a condition variable for a specific amount of time"
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_cond_timedwait
+.Fa "pthread_cond_t *restrict cond"
+.Fa "pthread_mutex_t *restrict mutex"
+.Fa "const struct timespec *restrict abstime"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_cond_timedwait
+function atomically blocks the current thread waiting on the condition
+variable specified by
+.Fa cond
+and unblocks the mutex specified by
+.Fa mutex .
+The waiting thread unblocks only after another thread calls
+.Xr pthread_cond_signal 3 ,
+or
+.Xr pthread_cond_broadcast 3
+with the same condition variable, or if the system time reaches the
+time specified in
+.Fa abstime ,
+and the current thread reacquires the lock on
+.Fa mutex .
+.Pp
+Values for struct timespec can be obtained by adding the required
+time interval to the the current time obtained using
+.Xr gettimeofday 2 .
+.Pp
+.Fa Note
+that struct timeval and struct timespec use different units to specify
+the time. Hence, the user should always take care to perform the time unit
+conversions accordingly.
+.Sh EXAMPLE
+.Pp
+ struct timeval tv;
+ struct timespec ts;
+ gettimeofday(&tv, NULL);
+ ts.tv_sec = tv.tv_sec + 0;
+ ts.tv_nsec = 0;
+.Pp
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_cond_timedwait
+function will return zero.
+Otherwise, an error number will be returned to
+indicate the error.
+.Sh ERRORS
+.Fn pthread_cond_timedwait
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value specified by
+.Fa cond ,
+.Fa mutex
+or
+.Fa abstime
+is invalid.
+.It Bq Er ETIMEDOUT
+The system time has reached or exceeded the time specified in
+.Fa abstime .
+.El
+.Sh SEE ALSO
+.Xr pthread_cond_broadcast 3 ,
+.Xr pthread_cond_destroy 3 ,
+.Xr pthread_cond_init 3 ,
+.Xr pthread_cond_signal 3 ,
+.Xr pthread_cond_wait 3 ,
+.Xr gettimeofday 2
+.Sh STANDARDS
+.Fn pthread_cond_timedwait
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Portions Copyright (c) 2001 Apple Computer, Inc. All Rights Reserved.
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_cond_wait.3,v 1.8.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd November 5, 2001
+.Dt PTHREAD_COND_WAIT 3
+.Os Darwin
+.Sh NAME
+.Nm pthread_cond_wait
+.Nd wait on a condition variable
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_cond_wait
+.Fa "pthread_cond_t *restrict cond"
+.Fa "pthread_mutex_t *restrict mutex"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_cond_wait
+function atomically unlocks the
+.Fa mutex
+and blocks the current thread on the condition specified by the
+.Fa cond
+argument.
+The current thread unblocks only after another thread calls
+.Xr pthread_cond_signal 3
+or
+.Xr pthread_cond_broadcast 3
+with the same condition variable.
+The
+.Fa mutex
+must be locked before calling this function, otherwise the behavior is
+undefined. Before
+.Fn pthread_cond_wait
+returns to the calling function, it re-acquires the
+.Fa mutex .
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_cond_wait
+function will return zero; otherwise, an error number will be returned to
+indicate the error.
+.Sh ERRORS
+.Fn pthread_cond_wait
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value specified by
+.Fa cond
+or the value specified by
+.Fa mutex
+is invalid.
+.El
+.Sh SEE ALSO
+.Xr pthread_cond_broadcast 3 ,
+.Xr pthread_cond_destroy 3 ,
+.Xr pthread_cond_init 3 ,
+.Xr pthread_cond_signal 3 ,
+.Xr pthread_cond_timedwait 3
+.Sh STANDARDS
+.Fn pthread_cond_wait
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (C) 2000 Jason Evans <jasone@FreeBSD.org>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_condattr.3,v 1.9 2001/10/01 16:09:09 ru Exp $
+.Dd April 28, 2000
+.Dt PTHREAD_CONDATTR 3
+.Os
+.Sh NAME
+.Nm pthread_condattr_destroy ,
+.Nm pthread_condattr_init
+.Nd condition attribute operations
+.Sh SYNOPSIS
+.In pthread.h
+.Ft int
+.Fo pthread_condattr_destroy
+.Fa "pthread_condattr_t *attr"
+.Fc
+.Ft int
+.Fo pthread_condattr_init
+.Fa "pthread_condattr_t *attr"
+.Fc
+.Sh DESCRIPTION
+Condition attribute objects are used to specify parameters to
+.Fn pthread_cond_init .
+.Fx Ns 's
+implementation of conditions does not support any non-default
+attributes, so these functions are not very useful, though they are required to
+to be present by
+.Tn POSIX .
+.Pp
+The
+.Fn pthread_condattr_init
+function initializes a condition attribute object with the default attributes.
+.Pp
+The
+.Fn pthread_condattr_destroy
+function destroys a condition attribute object.
+.Sh RETURN VALUES
+If successful, these functions return 0.
+Otherwise, an error number is returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_condattr_destroy
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.El
+.Pp
+.Fn pthread_condattr_init
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Out of memory.
+.El
+.Sh SEE ALSO
+.Xr pthread_cond_init 3
+.Sh STANDARDS
+.Fn pthread_condattr_init
+and
+.Fn pthread_condattr_destroy
+conform to
+.St -p1003.1-96
--- /dev/null
+.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by John Birrell.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_create.3,v 1.9.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd April 4, 1996
+.Dt PTHREAD_CREATE 3
+.Os
+.Sh NAME
+.Nm pthread_create
+.Nd create a new thread
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_create
+.Fa "pthread_t *restrict thread"
+.Fa "const pthread_attr_t *restrict attr"
+.Fa "void *(*start_routine)(void *)"
+.Fa "void *restrict arg"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_create
+function is used to create a new thread, with attributes specified by
+.Fa attr ,
+within a process.
+If
+.Fa attr
+is NULL, the default attributes are used.
+If the attributes specified by
+.Fa attr
+are modified later, the thread's attributes are not affected.
+Upon successful completion,
+.Fn pthread_create
+will store the ID of the created thread in the location specified by
+.Fa thread .
+.Pp
+Upon its creation, the thread executes
+.Fa start_routine ,
+with
+.Fa arg
+as its sole argument.
+If
+.Fa start_routine
+returns, the effect is as if there was an implicit call to
+.Fn pthread_exit ,
+using the return value of
+.Fa start_routine
+as the exit status.
+Note that the thread in which
+.Fn main
+was originally invoked differs from this.
+When it returns from
+.Fn main ,
+the effect is as if there was an implicit call to
+.Fn exit ,
+using the return value of
+.Fn main
+as the exit status.
+.Pp
+Upon thread exit the storage for the thread must be reclaimed by another
+thread via a call to
+.Fn pthread_join .
+Alternatively,
+.Fn pthread_detach
+may be called on the thread to indicate that the system may automatically
+reclaim the thread storage upon exit.
+The
+.Fn pthread_attr_setdetachstate
+function may be used on the
+.Fa attr
+argument passed to
+.Fn pthread_create
+in order to achieve the same effect as a call to
+.Fn pthread_detach
+on the newly created thread.
+.Pp
+The signal state of the new thread is initialized as:
+.Bl -bullet -offset indent
+.It
+The signal mask is inherited from the creating thread.
+.It
+The set of signals pending for the new thread is empty.
+.El
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_create
+function will return zero.
+Otherwise, an error number will be returned to
+indicate the error.
+.Sh ERRORS
+.Fn pthread_create
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The system lacked the necessary resources to create another thread, or
+the system-imposed limit on the total number of threads in a process
+[PTHREAD_THREADS_MAX] would be exceeded.
+.It Bq Er EINVAL
+The value specified by
+.Fa attr
+is invalid.
+.El
+.Sh SEE ALSO
+.Xr fork 2 ,
+.Xr pthread_cleanup_pop 3 ,
+.Xr pthread_cleanup_push 3 ,
+.Xr pthread_detach 3 ,
+.Xr pthread_exit 3 ,
+.Xr pthread_join 3
+.Sh STANDARDS
+.Fn pthread_create
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1996-1998 John Birrell <jb@cimlogic.com.au>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by John Birrell.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_detach.3,v 1.6.2.5 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd April 4, 1996
+.Dt PTHREAD_DETACH 3
+.Os
+.Sh NAME
+.Nm pthread_detach
+.Nd detach a thread
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_detach
+.Fa "pthread_t thread"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_detach
+function is used to indicate to the implementation that storage for the
+thread
+.Fa thread
+can be reclaimed when the thread terminates.
+If
+.Fa thread
+has not terminated,
+.Fn pthread_detach
+will not cause it to terminate.
+The effect of multiple
+.Fn pthread_detach
+calls on the same target thread is unspecified.
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_detach
+function will return zero.
+Otherwise, an error number will be returned to
+indicate the error.
+Note that the function does not change the value
+of errno, as it did for some drafts of the standard.
+These early drafts
+also passed a pointer to pthread_t as the argument.
+Beware!
+.Sh ERRORS
+.Fn pthread_detach
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The implementation has detected that the value specified by
+.Fa thread
+does not refer to a joinable thread.
+.It Bq Er ESRCH
+No thread could be found corresponding to that specified by the given
+thread ID,
+.Fa thread .
+.El
+.Sh SEE ALSO
+.Xr pthread_join 3
+.Sh STANDARDS
+.Fn pthread_detach
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by John Birrell.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_equal.3,v 1.4.2.5 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd April 4, 1996
+.Dt PTHREAD_EQUAL 3
+.Os
+.Sh NAME
+.Nm pthread_equal
+.Nd compare thread IDs
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_equal
+.Fa "pthread_t t1"
+.Fa "pthread_t t2"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_equal
+function compares the thread IDs
+.Fa t1
+and
+.Fa t2 .
+.Sh RETURN VALUES
+The
+.Fn pthread_equal
+function will return non-zero if the thread IDs
+.Fa t1
+and
+.Fa t2
+correspond to the same thread. Otherwise, it will return zero.
+.Sh ERRORS
+None.
+.Sh SEE ALSO
+.Xr pthread_create 3 ,
+.Xr pthread_exit 3
+.Sh STANDARDS
+.Fn pthread_equal
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by John Birrell.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_exit.3,v 1.8.2.6 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd April 4, 1996
+.Dt PTHREAD_EXIT 3
+.Os
+.Sh NAME
+.Nm pthread_exit
+.Nd terminate the calling thread
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft void
+.Fo pthread_exit
+.Fa "void *value_ptr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_exit
+function terminates the calling thread and makes the value
+.Fa value_ptr
+available to any successful join with the terminating thread.
+Any
+cancellation cleanup handlers that have been pushed and are not yet popped
+are popped in the reverse order that they were pushed and then executed.
+After all cancellation handlers have been executed, if the thread has any
+thread-specific data, appropriate destructor functions are called in an
+unspecified order.
+Thread termination does not release any application
+visible process resources, including, but not limited to, mutexes and
+file descriptors, nor does it perform any process level cleanup
+actions, including, but not limited to, calling
+.Fn atexit
+routines that may exist.
+.Pp
+An implicit call to
+.Fn pthread_exit
+is made when a thread other than the thread in which
+.Fn main
+was first invoked returns from the start routine that was used to create
+it. The function's return value serves as the thread's exit status.
+.Pp
+The behavior of
+.Fn pthread_exit
+is undefined if called from a cancellation handler or destructor function
+that was invoked as the result of an implicit or explicit call to
+.Fn pthread_exit .
+.Pp
+After a thread has terminated, the result of access to local (auto)
+variables of the thread is undefined.
+Thus, references to local variables
+of the exiting thread should not be used for the
+.Fn pthread_exit
+.Fa value_ptr
+parameter value.
+.Pp
+The process will exit with an exit status of 0 after the last thread has
+been terminated.
+The behavior is as if the implementation called
+.Fn exit
+with a zero argument at thread termination time.
+.Sh RETURN VALUES
+The
+.Fn pthread_exit
+function cannot return to its caller.
+.Sh ERRORS
+None.
+.Sh SEE ALSO
+.Xr _exit 2 ,
+.Xr exit 3 ,
+.Xr pthread_create 3 ,
+.Xr pthread_join 3
+.Sh STANDARDS
+.Fn pthread_exit
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (C) 2000 Jason Evans <jasone@FreeBSD.org>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_schedparam.3,v 1.2.2.4 2001/08/17 15:42:52 ru Exp $
+.Dd May 1, 2000
+.Dt PTHREAD_SCHEDPARAM 3
+.Os
+.Sh NAME
+.Nm pthread_getschedparam ,
+.Nm pthread_setschedparam
+.Nd thread scheduling parameter manipulation
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_getschedparam
+.Fa "pthread_t thread"
+.Fa "int *restrict policy"
+.Fa "struct sched_param *restrict param"
+.Fc
+.Ft int
+.Fo pthread_setschedparam
+.Fa "pthread_t thread"
+.Fa "int policy"
+.Fa "const struct sched_param *param"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_getschedparam
+and
+.Fn pthread_setschedparam
+functions get and set the scheduling parameters of individual threads.
+The scheduling policy for a thread can either be
+.Dv SCHED_FIFO
+(first in, first out) or
+.Dv SCHED_RR
+(round-robin).
+The thread priority (accessed via
+.Va param->sched_priority )
+must be at least
+.Dv PTHREAD_MIN_PRIORITY
+and no more than
+.Dv PTHREAD_MAX_PRIORITY .
+.Sh RETURN VALUES
+If successful, these functions return 0.
+Otherwise, an error number is returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_getschedparam
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ESRCH
+Non-existent thread
+.Va thread .
+.El
+.Pp
+.Fn pthread_setschedparam
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Invalid value for
+.Va policy .
+.It Bq Er ENOTSUP
+Invalid value for scheduling parameters.
+.It Bq Er ESRCH
+Non-existent thread
+.Va thread .
+.El
+.Sh STANDARDS
+.Fn pthread_setschedparam
+and
+.Fn pthread_getschedparam
+conform to
+.St -susv2
--- /dev/null
+.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by John Birrell.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_getspecific.3,v 1.6.2.3 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd April 4, 1996
+.Dt PTHREAD_GETSPECIFIC 3
+.Os
+.Sh NAME
+.Nm pthread_getspecific
+.Nd get a thread-specific data value
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft void *
+.Fo pthread_getspecific
+.Fa "pthread_key_t key"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_getspecific
+function returns the value that is currently bound to the specified
+.Fa key ,
+on behalf of the calling thread.
+.Pp
+The effect of calling
+.Fn pthread_getspecific
+with a
+.Fa key
+value that was not obtained from
+.Fn pthread_key_create ,
+or after a
+.Fa key
+has been deleted with
+.Fn pthread_key_delete ,
+is undefined.
+.Pp
+.Fn pthread_getspecific
+may be called from a thread-specific data destructor function.
+.Sh RETURN VALUES
+The
+.Fn pthread_getspecific
+function will return the thread-specific data value associated with the given
+.Fa key .
+If no thread-specific data value is associated with
+.Fa key ,
+the value NULL is returned.
+.Sh ERRORS
+None.
+.Sh SEE ALSO
+.Xr pthread_key_create 3 ,
+.Xr pthread_key_delete 3 ,
+.Xr pthread_setspecific 3
+.Sh STANDARDS
+.Fn pthread_getspecific
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1996-1998 John Birrell <jb@cimlogic.com.au>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by John Birrell.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_join.3,v 1.7.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd April 4, 1996
+.Dt PTHREAD_JOIN 3
+.Os
+.Sh NAME
+.Nm pthread_join
+.Nd wait for thread termination
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_join
+.Fa "pthread_t thread"
+.Fa "void **value_ptr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_join
+function suspends execution of the calling thread until the target
+.Fa thread
+terminates, unless the target
+.Fa thread
+has already terminated.
+.Pp
+On return from a successful
+.Fn pthread_join
+call with a non-NULL
+.Fa value_ptr
+argument, the value passed to
+.Fn pthread_exit
+by the terminating thread is stored in the location referenced by
+.Fa value_ptr .
+When a
+.Fn pthread_join
+returns successfully, the target thread has been terminated.
+The results
+of multiple simultaneous calls to
+.Fn pthread_join ,
+specifying the same target thread, are undefined.
+If the thread calling
+.Fn pthread_join
+is cancelled, the target thread is not detached.
+.Pp
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_join
+function will return zero.
+Otherwise, an error number will be returned to
+indicate the error.
+.Sh ERRORS
+.Fn pthread_join
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EDEADLK
+A deadlock was detected or the value of
+.Fa thread
+specifies the calling thread.
+.It Bq Er EINVAL
+The implementation has detected that the value specified by
+.Fa thread
+does not refer to a joinable thread.
+.It Bq Er ESRCH
+No thread could be found corresponding to that specified by the given
+thread ID,
+.Fa thread .
+.El
+.Sh SEE ALSO
+.Xr wait 2 ,
+.Xr pthread_create 3
+.Sh STANDARDS
+.Fn pthread_join
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by John Birrell.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_key_create.3,v 1.6.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd April 4, 1996
+.Dt PTHREAD_KEY_CREATE 3
+.Os
+.Sh NAME
+.Nm pthread_key_create
+.Nd thread-specific data key creation
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_key_create
+.Fa "pthread_key_t *key"
+.Fa "void (*destructor)(void *)"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_key_create
+function creates a thread-specific data key
+that is visible to all threads in the process.
+Key values provided by
+.Fn pthread_key_create
+are opaque objects, used to locate thread-specific data.
+Although the same
+key value may be used by different threads, the values bound to the key
+by
+.Fn pthread_setspecific
+are maintained on a per-thread basis and persist for the life of the calling
+thread.
+.Pp
+Upon key creation, the value NULL is associated with the new key in all
+active threads.
+Upon thread creation, the value NULL is associated with all
+defined keys in the new thread.
+.Pp
+An optional destructor function may be associated with each key value.
+If a key value has a non-NULL destructor function pointer, and the thread has
+a non-NULL value associated with the key at the time of thread exit, then the
+key value is set to NULL and the destructor function is called with the
+previous key value as its argument.
+The order of destructor calls at thread exit is unspecified.
+.Pp
+If, after all the destructors have been called for all non-NULL values
+with associated destructors, there are still some non-NULL values with
+associated destructors, then the process is repeated.
+If, after at least
+[PTHREAD_DESTRUCTOR_ITERATIONS] iterations of destructor calls for
+outstanding non-NULL values, there are still some non-NULL values with
+associated destructors, the implementation stops calling destructors.
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_key_create
+function will store the newly created key value at the location specified by
+.Fa key
+and returns zero.
+Otherwise, an error number will be returned to indicate
+the error.
+.Sh ERRORS
+.Fn pthread_key_create
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The system lacked the necessary resources to create another thread-specific
+data key, or the system-imposed limit on the total number of keys per process
+[PTHREAD_KEYS_MAX] would be exceeded.
+.It Bq Er ENOMEM
+Insufficient memory exists to create the key.
+.El
+.Sh SEE ALSO
+.Xr pthread_getspecific 3 ,
+.Xr pthread_key_delete 3 ,
+.Xr pthread_setspecific 3
+.Sh STANDARDS
+.Fn pthread_key_create
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by John Birrell.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_key_delete.3,v 1.6.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd April 4, 1996
+.Dt PTHREAD_KEY_DELETE 3
+.Os
+.Sh NAME
+.Nm pthread_key_delete
+.Nd delete a thread-specific data key
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_key_delete
+.Fa "pthread_key_t key"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_key_delete
+function deletes a thread-specific data key, previously returned by
+.Fn pthread_key_create .
+The thread-specific data values associated with
+.Fa key
+need not be NULL at the time that
+.Fn pthread_key_delete
+is called.
+It is the responsibility of the application to free any
+application storage or perform any cleanup actions for data structures
+related to the deleted key or associated thread-specific data in any threads;
+this cleanup can be done either before or after
+.Fn pthread_key_delete
+is called.
+Any attempt to use
+.Fa key
+following the call to
+.Fn pthread_key_delete
+results in undefined behavior.
+.Pp
+The
+.Fn pthread_key_delete
+function is callable from within destructor functions.
+Destructor functions
+are not invoked by
+.Fn pthread_key_delete .
+Any destructor function that may have been associated with
+.Fa key
+will no longer be called upon thread exit.
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_key_delete
+function will return zero.
+Otherwise, an error number will be returned to
+indicate the error.
+.Sh ERRORS
+.Fn pthread_key_delete
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa key
+value is invalid.
+.El
+.Sh SEE ALSO
+.Xr pthread_getspecific 3 ,
+.Xr pthread_key_create 3 ,
+.Xr pthread_setspecific 3
+.Sh STANDARDS
+.Fn pthread_key_delete
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Darwin
+.\"
+.\" Copyright (C) 2000 Jason Evans <jasone@FreeBSD.org>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_kill.3,v 1.8 2001/10/01 16:09:09 ru Exp $
+.Dd Feb 05, 2002
+.Dt PTHREAD_KILL 2
+.Os
+.Sh NAME
+.Nm pthread_kill
+.Nd send a signal to a specified thread
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fn pthread_kill "pthread_t thread" "int sig"
+.Sh DESCRIPTION
+The
+.Fn pthread_kill
+function sends a signal, specified by
+.Fa sig ,
+to a thread, specified by
+.Fa thread .
+If
+.Fa sig
+is 0, error checking is performed, but no signal is actually sent.
+.Sh RETURN VALUES
+If successful,
+.Fn pthread_kill
+returns 0.
+Otherwise, an error number is returned.
+.Sh ERRORS
+.Fn pthread_kill
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+.Fa sig
+is an invalid or unsupported signal number.
+.It Bq Er ESRCH
+.Fa thread
+is an invalid thread ID.
+.El
+.Sh LEGACY SYNOPSIS
+.Fd #include <pthread.h>
+.Fd #include <signal.h>
+.Pp
+The include file
+.In pthread.h
+is necessary.
+.Sh SEE ALSO
+.Xr kill 2 ,
+.Xr pthread_self 3 ,
+.Xr raise 3 ,
+.Xr compat 5
+.Sh STANDARDS
+.Fn pthread_kill
+conforms to ISO/IEC 9945-1:1996 (``POSIX.1'')
--- /dev/null
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_mutex_destroy.3,v 1.5.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd July 29, 1998
+.Dt PTHREAD_MUTEX_DESTROY 3
+.Os
+.Sh NAME
+.Nm pthread_mutex_destroy
+.Nd free resources allocated for a mutex
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_mutex_destroy
+.Fa "pthread_mutex_t *mutex"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_mutex_destroy
+function frees the resources allocated for
+.Fa mutex .
+.Sh RETURN VALUES
+If successful,
+.Fn pthread_mutex_destroy
+will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_mutex_destroy
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+.Fa Mutex
+is locked by a thread.
+.It Bq Er EINVAL
+The value specified by
+.Fa mutex
+is invalid.
+.El
+.Sh SEE ALSO
+.Xr pthread_mutex_init 3 ,
+.Xr pthread_mutex_lock 3 ,
+.Xr pthread_mutex_trylock 3 ,
+.Xr pthread_mutex_unlock 3
+.Sh STANDARDS
+.Fn pthread_mutex_destroy
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_mutex_init.3,v 1.6.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd July 29, 1998
+.Dt PTHREAD_MUTEX_INIT 3
+.Os
+.Sh NAME
+.Nm pthread_mutex_init
+.Nd create a mutex
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_mutex_init
+.Fa "pthread_mutex_t *restrict mutex"
+.Fa "const pthread_mutexattr_t *restrict attr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_mutex_init
+function creates a new mutex, with attributes specified with
+.Fa attr .
+If
+.Fa attr
+is NULL, the default attributes are used.
+.Sh RETURN VALUES
+If successful,
+.Fn pthread_mutex_init
+will return zero and put the new mutex id into
+.Fa mutex .
+Otherwise, an error number will be returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_mutex_init
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The system temporarily lacks the resources to create another mutex.
+.It Bq Er EINVAL
+The value specified by
+.Fa attr
+is invalid.
+.It Bq Er ENOMEM
+The process cannot allocate enough memory to create another mutex.
+.El
+.Sh SEE ALSO
+.Xr pthread_mutex_destroy 3 ,
+.Xr pthread_mutex_lock 3 ,
+.Xr pthread_mutex_trylock 3 ,
+.Xr pthread_mutex_unlock 3
+.Sh STANDARDS
+.Fn pthread_mutex_init
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_mutex_lock.3,v 1.5.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd July 30, 1998
+.Dt PTHREAD_MUTEX_LOCK 3
+.Os
+.Sh NAME
+.Nm pthread_mutex_lock
+.Nd lock a mutex
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_mutex_lock
+.Fa "pthread_mutex_t *mutex"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_mutex_lock
+function locks
+.Fa mutex .
+If the mutex is already locked, the calling thread will block until the
+mutex becomes available.
+.Sh RETURN VALUES
+If successful,
+.Fn pthread_mutex_lock
+will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_mutex_lock
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EDEADLK
+A deadlock would occur if the thread blocked waiting for
+.Fa mutex .
+.It Bq Er EINVAL
+The value specified by
+.Fa mutex
+is invalid.
+.El
+.Sh SEE ALSO
+.Xr pthread_mutex_destroy 3 ,
+.Xr pthread_mutex_init 3 ,
+.Xr pthread_mutex_trylock 3 ,
+.Xr pthread_mutex_unlock 3
+.Sh STANDARDS
+.Fn pthread_mutex_lock
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_mutex_trylock.3,v 1.5.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd July 30, 1998
+.Dt PTHREAD_MUTEX_TRYLOCK 3
+.Os
+.Sh NAME
+.Nm pthread_mutex_trylock
+.Nd attempt to lock a mutex without blocking
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_mutex_trylock
+.Fa "pthread_mutex_t *mutex"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_mutex_trylock
+function locks
+.Fa mutex .
+If the mutex is already locked,
+.Fn pthread_mutex_trylock
+will not block waiting for the mutex, but will return an error condition.
+.Sh RETURN VALUES
+If successful,
+.Fn pthread_mutex_trylock
+will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_mutex_trylock
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+.Fa Mutex
+is already locked.
+.It Bq Er EINVAL
+The value specified by
+.Fa mutex
+is invalid.
+.El
+.Sh SEE ALSO
+.Xr pthread_mutex_destroy 3 ,
+.Xr pthread_mutex_init 3 ,
+.Xr pthread_mutex_lock 3 ,
+.Xr pthread_mutex_unlock 3
+.Sh STANDARDS
+.Fn pthread_mutex_trylock
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1997 Brian Cully <shmit@kublai.com>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_mutex_unlock.3,v 1.5.2.4 2001/08/17 15:42:51 ru Exp $
+.\"
+.Dd July 30, 1998
+.Dt PTHREAD_MUTEX_UNLOCK 3
+.Os
+.Sh NAME
+.Nm pthread_mutex_unlock
+.Nd unlock a mutex
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_mutex_unlock
+.Fa "pthread_mutex_t *mutex"
+.Fc
+.Sh DESCRIPTION
+If the current thread holds the lock on
+.Fa mutex ,
+then the
+.Fn pthread_mutex_unlock
+function unlocks
+.Fa mutex .
+.Pp
+Calling
+.Fn pthread_mutex_unlock
+with a
+.Fa mutex
+that the calling thread does not hold will result
+in undefined behavior.
+.Sh RETURN VALUES
+If successful,
+.Fn pthread_mutex_unlock
+will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_mutex_unlock
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value specified by
+.Fa mutex
+is invalid.
+.It Bq Er EPERM
+The current thread does not hold a lock on
+.Fa mutex .
+.El
+.Sh SEE ALSO
+.Xr pthread_mutex_destroy 3 ,
+.Xr pthread_mutex_init 3 ,
+.Xr pthread_mutex_lock 3 ,
+.Xr pthread_mutex_trylock 3
+.Sh STANDARDS
+.Fn pthread_mutex_unlock
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" $NetBSD: pthread_mutexattr.3,v 1.3 2003/07/04 08:36:06 wiz Exp $
+.\"
+.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. Neither the name of The NetBSD Foundation nor the names of its
+.\" contributors may be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" Copyright (C) 2000 Jason Evans <jasone@FreeBSD.org>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libpthread/man/pthread_mutexattr.3,v 1.8 2002/09/16 19:29:29 mini Exp $
+.Dd January 30, 2003
+.Dt PTHREAD_MUTEXATTR 3
+.Os
+.Sh NAME
+.Nm pthread_mutexattr_destroy ,
+.Nm pthread_mutexattr_getprioceiling ,
+.Nm pthread_mutexattr_getprotocol ,
+.Nm pthread_mutexattr_gettype ,
+.Nm pthread_mutexattr_init ,
+.Nm pthread_mutexattr_setprioceiling ,
+.Nm pthread_mutexattr_setprotocol ,
+.Nm pthread_mutexattr_settype
+.Nd mutex attribute operations
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_mutexattr_destroy
+.Fa "pthread_mutexattr_t *attr"
+.Fc
+.Ft int
+.Fo pthread_mutexattr_getprioceiling
+.Fa "const pthread_mutexattr_t *restrict attr"
+.Fa "int *restrict prioceiling"
+.Fc
+.\" To match the SUS, this should be:
+.\" .Ft int
+.\" .Fo pthread_mutexattr_getprioceiling
+.\" .Fa "pthread_mutexattr_t *restrict attr"
+.\" .Fa "int *restrict prioceiling"
+.\" .Fc
+.Ft int
+.Fo pthread_mutexattr_getprotocol
+.Fa "const pthread_mutexattr_t *restrict attr"
+.Fa "int *restrict protocol"
+.Fc
+.\" To match the SUS, this should be:
+.\" .Ft int
+.\" .Fo pthread_mutexattr_getprotocol
+.\" .Fa "pthread_mutexattr_t *restrict attr"
+.\" .Fa "int *restrict protocol"
+.\" .Fc
+.Ft int
+.Fo pthread_mutexattr_gettype
+.Fa "const pthread_mutexattr_t *restrict attr"
+.Fa "int *restrict type"
+.Fc
+.\" To match the SUS, this should be:
+.\" .Ft int
+.\" .Fo pthread_mutexattr_gettype
+.\" .Fa "pthread_mutexattr_t *restrict attr"
+.\" .Fa "int *restrict type"
+.\" .Fc
+.Ft int
+.Fo pthread_mutexattr_init
+.Fa "pthread_mutexattr_t *attr"
+.Fc
+.Ft int
+.Fo pthread_mutexattr_setprioceiling
+.Fa "pthread_mutexattr_t *attr"
+.Fa "int prioceiling"
+.Fc
+.Ft int
+.Fo pthread_mutexattr_setprotocol
+.Fa "pthread_mutexattr_t *attr"
+.Fa "int protocol"
+.Fc
+.Ft int
+.Fo pthread_mutexattr_settype
+.Fa "pthread_mutexattr_t *attr"
+.Fa "int type"
+.Fc
+.Sh DESCRIPTION
+Mutex attributes are used to specify parameters to
+.Fn pthread_mutex_init .
+One attribute object can be used in multiple calls to
+.Fn pthread_mutex_init ,
+with or without modifications between calls.
+.Pp
+The
+.Fn pthread_mutexattr_init
+function initializes
+.Fa attr
+with all of the default mutex attributes.
+.Pp
+The
+.Fn pthread_mutexattr_destroy
+function destroys
+.Fa attr .
+.Pp
+The
+.Fn pthread_mutexattr_settype
+function sets the mutex type value of the attribute. Valid mutex types are:
+.Dv PTHREAD_MUTEX_NORMAL ,
+.Dv PTHREAD_MUTEX_ERRORCHECK ,
+.Dv PTHREAD_MUTEX_RECURSIVE ,
+and
+.Dv PTHREAD_MUTEX_DEFAULT .
+The default mutex type for
+.Fn pthread_mutexattr_init
+is
+.Dv PTHREAD_MUTEX_DEFAULT .
+.Pp
+.Dv PTHREAD_MUTEX_NORMAL
+mutexes do not check for usage errors.
+.Dv PTHREAD_MUTEX_NORMAL
+mutexes will deadlock if reentered, and result in undefined behavior if a
+locked mutex is unlocked by another thread. Attempts to unlock an already
+unlocked
+.Dv PTHREAD_MUTEX_NORMAL
+mutex will result in undefined behavior.
+.Pp
+.Dv PTHREAD_MUTEX_ERRORCHECK
+mutexes do check for usage errors.
+If an attempt is made to relock a
+.Dv PTHREAD_MUTEX_ERRORCHECK
+mutex without first dropping the lock, an error will be returned.
+If a thread attempts to unlock a
+.Dv PTHREAD_MUTEX_ERRORCHECK
+mutex that is locked by another thread, an error will be returned. If a
+thread attempts to unlock a
+.Dv PTHREAD_MUTEX_ERRORCHECK
+thread that is unlocked, an error will be returned.
+.Pp
+.Dv PTHREAD_MUTEX_RECURSIVE
+mutexes allow recursive locking.
+An attempt to relock a
+.Dv PTHREAD_MUTEX_RECURSIVE
+mutex that is already locked by the same thread succeeds. An equivalent
+number of
+.Xr pthread_mutex_unlock 3
+calls are needed before the mutex will wake another thread waiting on this
+lock. If a thread attempts to unlock a
+.Dv PTHREAD_MUTEX_RECURSIVE
+mutex that is locked by another thread, an error will be returned. If a thread attemps to unlock a
+.Dv PTHREAD_MUTEX_RECURSIVE
+thread that is unlocked, an error will be returned.
+.Pp
+.Dv PTHREAD_MUTEX_DEFAULT
+mutexes result in undefined behavior if reentered.
+Unlocking a
+.Dv PTHREAD_MUTEX_DEFAULT
+mutex locked by another thread will result in undefined behavior. Attempts to unlock an already
+unlocked
+.Dv PTHREAD_MUTEX_DEFAULT
+mutex will result in undefined behavior.
+.Pp
+.Fn pthread_mutexattr_gettype
+functions copy the type value of the attribute to the location pointed to by the second parameter.
+.Pp
+The
+.Fn pthread_mutexattr_set*
+functions set the attribute that corresponds to each function name.
+.Pp
+The
+.Fn pthread_mutexattr_get*
+functions copy the value of the attribute that corresponds to each function name
+to the location pointed to by the second function parameter.
+.Sh RETURN VALUES
+If successful, these functions return 0.
+Otherwise, an error number is returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_mutexattr_init
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Out of memory.
+.El
+.Pp
+.Fn pthread_mutexattr_destroy
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.El
+.Pp
+.Fn pthread_mutexattr_setprioceiling
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr ,
+or invalid value for
+.Fa prioceiling .
+.El
+.Pp
+.Fn pthread_mutexattr_getprioceiling
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.El
+.Pp
+.Fn pthread_mutexattr_setprotocol
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr ,
+or invalid value for
+.Fa protocol .
+.El
+.Pp
+.Fn pthread_mutexattr_getprotocol
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.El
+.Pp
+.Fn pthread_mutexattr_settype
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr ,
+or invalid value for
+.Fa type .
+.El
+.Pp
+.Fn pthread_mutexattr_gettype
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+Invalid value for
+.Fa attr .
+.El
+.Sh SEE ALSO
+.Xr pthread_mutex_init 3
+.Sh STANDARDS
+.Fn pthread_mutexattr_init
+and
+.Fn pthread_mutexattr_destroy
+conform to
+.St -p1003.1-96
+.Pp
+.Fn pthread_mutexattr_setprioceiling ,
+.Fn pthread_mutexattr_getprioceiling ,
+.Fn pthread_mutexattr_setprotocol ,
+.Fn pthread_mutexattr_getprotocol ,
+.Fn pthread_mutexattr_settype ,
+and
+.Fn pthread_mutexattr_gettype
+conform to
+.St -susv2
--- /dev/null
+.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by John Birrell.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_once.3,v 1.6.2.6 2001/08/17 15:42:52 ru Exp $
+.\"
+.Dd April 4, 1996
+.Dt PTHREAD_ONCE 3
+.Os
+.Sh NAME
+.Nm pthread_once
+.Nd dynamic package initialization
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Pp
+pthread_once_t
+.Fa once_control
+= PTHREAD_ONCE_INIT;
+.Ft int
+.Fn pthread_once "pthread_once_t *once_control" "void (*init_routine)(void)"
+.Sh DESCRIPTION
+The first call to
+.Fn pthread_once
+by any thread in a process, with a given
+.Fa once_control ,
+will call the
+.Fn init_routine
+with no arguments.
+Subsequent calls to
+.Fn pthread_once
+with the same
+.Fa once_control
+will not call the
+.Fn init_routine .
+On return from
+.Fn pthread_once ,
+it is guaranteed that
+.Fn init_routine
+has completed.
+The
+.Fa once_control
+parameter is used to determine whether the associated initialization
+routine has been called.
+.Pp
+The function
+.Fn pthread_once
+is not a cancellation point.
+However, if
+.Fn init_routine
+is a cancellation point and is cancelled, the effect on
+.Fa once_control is as if
+.Fn pthread_once
+was never called.
+.Pp
+The constant
+.Fa PTHREAD_ONCE_INIT
+is defined by header
+.Aq Pa pthread.h .
+.Pp
+The behavior of
+.Fn pthread_once
+is undefined if
+.Fa once_control
+has automatic storage duration or is not initialized by
+.Fa PTHREAD_ONCE_INIT .
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_once
+function will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh ERRORS
+None.
+.Sh STANDARDS
+.Fn pthread_once
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (c) 1998 Alex Nash
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_rwlock_destroy.3,v 1.6 2001/10/01 16:09:09 ru Exp $
+.\"
+.Dd August 4, 1998
+.Dt PTHREAD_RWLOCK_DESTROY 3
+.Os
+.Sh NAME
+.Nm pthread_rwlock_destroy
+.Nd destroy a read/write lock
+.Sh SYNOPSIS
+.In pthread.h
+.Ft int
+.Fo pthread_rwlock_destroy
+.Fa "pthread_rwlock_t *rwlock"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_rwlock_destroy
+function is used to destroy a read/write lock previously created with
+.Fn pthread_rwlock_init .
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_rwlock_destroy
+function will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh SEE ALSO
+.Xr pthread_rwlock_init 3
+.Sh STANDARDS
+The
+.Fn pthread_rwlock_destroy
+function is expected to conform to
+.St -susv2 .
+.Sh ERRORS
+The
+.Fn pthread_rwlock_destroy
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EPERM
+The caller does not have the privilege to perform the operation.
+.El
+.Pp
+The
+.Fn pthread_rwlock_destroy
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The system has detected an attempt to destroy the object referenced by
+.Fa rwlock
+while it is locked.
+.It Bq Er EINVAL
+The value specified by
+.Fa rwlock
+is invalid.
+.El
+.Sh HISTORY
+The
+.Fn pthread_rwlock_destroy
+function first appeared in
+.Fx 3.0 .
--- /dev/null
+.\" Copyright (c) 1998 Alex Nash
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_rwlock_init.3,v 1.5 2001/10/01 16:09:09 ru Exp $
+.\"
+.Dd August 4, 1998
+.Dt PTHREAD_RWLOCK_INIT 3
+.Os
+.Sh NAME
+.Nm pthread_rwlock_init
+.Nd initialize a read/write lock
+.Sh SYNOPSIS
+.In pthread.h
+.Ft int
+.Fo pthread_rwlock_init
+.Fa "pthread_rwlock_t *restrict rwlock"
+.Fa "const pthread_rwlockattr_t *restrict attr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_rwlock_init
+function is used to initialize a read/write lock, with attributes
+specified by
+.Fa attr .
+If
+.Fa attr
+is NULL, the default read/write lock attributes are used.
+.Pp
+The results of calling
+.Fn pthread_rwlock_init
+with an already initialized lock are undefined.
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_rwlock_init
+function will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh SEE ALSO
+.Xr pthread_rwlock_destroy 3 ,
+.Xr pthread_rwlockattr_init 3 ,
+.Xr pthread_rwlockattr_setpshared 3
+.Sh STANDARDS
+The
+.Fn pthread_rwlock_init
+function is expected to conform to
+.St -susv2 .
+.Sh ERRORS
+The
+.Fn pthread_rwlock_init
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The system lacked the necessary resources (other than memory) to
+initialize the lock.
+.It Bq Er ENOMEM
+Insufficient memory exists to initialize the lock.
+.It Bq Er EPERM
+The caller does not have sufficient privilege to perform the
+operation.
+.El
+.Pp
+The
+.Fn pthread_rwlock_init
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The system has detected an attempt to re-initialize the object
+referenced by
+.Fa rwlock ,
+a previously initialized but not yet destroyed read/write lock.
+.It Bq Er EINVAL
+The value specified by
+.Fa attr
+is invalid.
+.El
+.Sh HISTORY
+The
+.Fn pthread_rwlock_init
+function first appeared in
+.Fx 3.0 .
+.Sh BUGS
+The PTHREAD_PROCESS_SHARED attribute is not supported.
--- /dev/null
+.\" Copyright (c) 1998 Alex Nash
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_rwlock_rdlock.3,v 1.4 2001/10/01 16:09:09 ru Exp $
+.\"
+.Dd August 4, 1998
+.Dt PTHREAD_RWLOCK_RDLOCK 3
+.Os
+.Sh NAME
+.Nm pthread_rwlock_rdlock ,
+.Nm pthread_rwlock_tryrdlock
+.Nd acquire a read/write lock for reading
+.Sh SYNOPSIS
+.In pthread.h
+.Ft int
+.Fo pthread_rwlock_rdlock
+.Fa "pthread_rwlock_t *rwlock"
+.Fc
+.Ft int
+.Fo pthread_rwlock_tryrdlock
+.Fa "pthread_rwlock_t *rwlock"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_rwlock_rdlock
+function acquires a read lock on
+.Fa rwlock ,
+provided that
+.Fa rwlock
+is not presently held for writing and no writer threads are
+presently blocked on the lock. If the read lock cannot be
+immediately acquired, the calling thread blocks until it can
+acquire the lock.
+.Pp
+The
+.Fn pthread_rwlock_tryrdlock
+function performs the same action, but does not block if the lock
+cannot be immediately obtained (i.e., the lock is held for writing
+or there are waiting writers).
+.Pp
+A thread may hold multiple concurrent read locks. If so,
+.Fn pthread_rwlock_unlock
+must be called once for each lock obtained.
+.Pp
+The results of acquiring a read lock while the calling thread holds
+a write lock are undefined.
+.Sh IMPLEMENTATION NOTES
+To prevent writer starvation, writers are favored over readers.
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_rwlock_rdlock
+and
+.Fn pthread_rwlock_tryrdlock
+functions will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh SEE ALSO
+.Xr pthread_rwlock_init 3 ,
+.Xr pthread_rwlock_trywrlock 3 ,
+.Xr pthread_rwlock_unlock 3 ,
+.Xr pthread_rwlock_wrlock 3
+.Sh STANDARDS
+The
+.Fn pthread_rwlock_rdlock
+and
+.Fn pthread_rwlock_tryrdlock
+functions are expected to conform to
+.St -susv2 .
+.Sh ERRORS
+The
+.Fn pthread_rwlock_tryrdlock
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The lock could not be acquired, because a writer holds the lock or
+was blocked on it.
+.El
+.Pp
+The
+.Fn pthread_rwlock_rdlock
+and
+.Fn pthread_rwlock_tryrdlock
+functions may fail if:
+.Bl -tag -width Er
+.It Bq Er EAGAIN
+The lock could not be acquired, because the maximum number of read locks
+against
+.Fa lock
+has been exceeded.
+.It Bq Er EDEADLK
+The current thread already owns
+.Fa rwlock
+for writing.
+.It Bq Er EINVAL
+The value specified by
+.Fa rwlock
+is invalid.
+.It Bq Er ENOMEM
+Insufficient memory exists to initialize the lock (applies to
+statically initialized locks only).
+.El
+.Sh HISTORY
+The
+.Fn pthread_rwlock_rdlock
+function first appeared in
+.Fx 3.0 .
--- /dev/null
+.\" Copyright (c) 1998 Alex Nash
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_rwlock_unlock.3,v 1.4 2001/10/01 16:09:09 ru Exp $
+.\"
+.Dd August 4, 1998
+.Dt PTHREAD_RWLOCK_UNLOCK 3
+.Os
+.Sh NAME
+.Nm pthread_rwlock_unlock
+.Nd release a read/write lock
+.Sh SYNOPSIS
+.In pthread.h
+.Ft int
+.Fo pthread_rwlock_unlock
+.Fa "pthread_rwlock_t *rwlock"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_rwlock_unlock
+function is used to release the read/write lock previously obtained by
+.Fn pthread_rwlock_rdlock ,
+.Fn pthread_rwlock_wrlock ,
+.Fn pthread_rwlock_tryrdlock ,
+or
+.Fn pthread_rwlock_trywrlock .
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_rwlock_unlock
+function will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Pp
+The results are undefined if
+.Fa rwlock
+is not held by the calling thread.
+.Sh SEE ALSO
+.Xr pthread_rwlock_rdlock 3 ,
+.Xr pthread_rwlock_wrlock 3
+.Sh STANDARDS
+The
+.Fn pthread_rwlock_unlock
+function is expected to conform to
+.St -susv2 .
+.Sh ERRORS
+The
+.Fn pthread_rwlock_unlock
+function may fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value specified by
+.Fa rwlock
+is invalid.
+.It Bq Er EPERM
+The current thread does not own the read/write lock.
+.El
+.Sh HISTORY
+The
+.Fn pthread_rwlock_unlock
+function first appeared in
+.Fx 3.0 .
--- /dev/null
+.\" Copyright (c) 1998 Alex Nash
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_rwlock_wrlock.3,v 1.4 2001/10/01 16:09:09 ru Exp $
+.\"
+.Dd August 4, 1998
+.Dt PTHREAD_RWLOCK_WRLOCK 3
+.Os
+.Sh NAME
+.Nm pthread_rwlock_trywrlock ,
+.Nm pthread_rwlock_wrlock
+.Nd acquire a read/write lock for writing
+.Sh SYNOPSIS
+.In pthread.h
+.Ft int
+.Fo pthread_rwlock_trywrlock
+.Fa "pthread_rwlock_t *rwlock"
+.Fc
+.Ft int
+.Fo pthread_rwlock_wrlock
+.Fa "pthread_rwlock_t *rwlock"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_rwlock_wrlock
+function blocks until a write lock can be acquired against
+.Fa rwlock .
+The
+.Fn pthread_rwlock_trywrlock
+function performs the same action, but does not block if the lock
+cannot be immediately obtained.
+.Pp
+The results are undefined if the calling thread already holds the
+lock at the time the call is made.
+.Sh IMPLEMENTATION NOTES
+To prevent writer starvation, writers are favored over readers.
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_rwlock_wrlock
+and
+.Fn pthread_rwlock_trywrlock
+functions will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh SEE ALSO
+.Xr pthread_rwlock_trywrlock 3 ,
+.Xr pthread_rwlock_unlock 3 ,
+.Xr pthread_rwlock_wrlock 3
+.Sh STANDARDS
+The
+.Fn pthread_rwlock_wrlock
+and
+.Fn pthread_rwlock_trywrlock
+functions are expected to conform to
+.St -susv2 .
+.Sh ERRORS
+The
+.Fn pthread_rwlock_trywrlock
+function will fail if:
+.Bl -tag -width Er
+.It Bq Er EBUSY
+The calling thread is not able to acquire the lock without blocking.
+.El
+.Pp
+The
+.Fn pthread_rwlock_wrlock
+and
+.Fn pthread_rwlock_trywrlock
+functions may fail if:
+.Bl -tag -width Er
+.It Bq Er EDEADLK
+The calling thread already owns the read/write lock (for reading
+or writing).
+.It Bq Er EINVAL
+The value specified by
+.Fa rwlock
+is invalid.
+.It Bq Er ENOMEM
+Insufficient memory exists to initialize the lock (applies to
+statically initialized locks only).
+.El
+.Sh HISTORY
+The
+.Fn pthread_rwlock_wrlock
+function first appeared in
+.Fx 3.0 .
--- /dev/null
+.\" Copyright (c) 1998 Alex Nash
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_rwlockattr_destroy.3,v 1.6 2001/10/01 16:09:09 ru Exp $
+.\"
+.Dd August 4, 1998
+.Dt PTHREAD_RWLOCKATTR_DESTROY 3
+.Os
+.Sh NAME
+.Nm pthread_rwlockattr_destroy
+.Nd destroy a read/write lock
+.Sh SYNOPSIS
+.In pthread.h
+.Ft int
+.Fo pthread_rwlockattr_destroy
+.Fa "pthread_rwlockattr_t *attr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_rwlockattr_destroy
+function is used to destroy a read/write lock attribute object,
+previously created with
+.Fn pthread_rwlockattr_init .
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_rwlockattr_destroy
+function will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh SEE ALSO
+.Xr pthread_rwlockattr_init 3
+.Sh STANDARDS
+The
+.Fn pthread_rwlockattr_destroy
+function is expected to conform to
+.St -susv2 .
+.Sh ERRORS
+.Fn pthread_rwlockattr_destroy
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value specified by
+.Fa attr
+is invalid.
+.El
+.Sh HISTORY
+The
+.Fn pthread_rwlockattr_destroy
+function first appeared in
+.Fx 3.0 .
--- /dev/null
+.\" Copyright (c) 1998 Alex Nash
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_rwlockattr_getpshared.3,v 1.8 2001/10/01 16:09:09 ru Exp $
+.\"
+.Dd March 22, 1999
+.Dt PTHREAD_RWLOCKATTR_GETPSHARED 3
+.Os
+.Sh NAME
+.Nm pthread_rwlockattr_getpshared
+.Nd get the process shared attribute
+.Sh SYNOPSIS
+.In pthread.h
+.Ft int
+.Fo pthread_rwlockattr_getpshared
+.Fa "const pthread_rwlockattr_t *restrict attr"
+.Fa "int *restrict pshared"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_rwlockattr_getpshared
+function is used to get the process-shared setting of a read/write
+lock attribute object. The setting is returned via
+.Fa pshared ,
+and may be one of two values:
+.Bl -tag -width PTHREAD_PROCESS_PRIVATE
+.It Dv PTHREAD_PROCESS_SHARED
+Any thread of any process that has access to the memory where the
+read/write lock resides can manipulate the lock.
+.It Dv PTHREAD_PROCESS_PRIVATE
+Only threads created within the same process as the thread that
+initialized the read/write lock can manipulate the lock. This is
+the default value.
+.El
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_rwlockattr_getpshared
+function will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh SEE ALSO
+.Xr pthread_rwlock_init 3 ,
+.Xr pthread_rwlockattr_init 3 ,
+.Xr pthread_rwlockattr_setpshared 3
+.Sh STANDARDS
+The
+.Fn pthread_rwlockattr_getpshared
+function is expected to conform to
+.St -susv2 .
+.Sh ERRORS
+.Fn pthread_rwlockattr_getpshared
+may fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value specified by
+.Fa attr
+is invalid.
+.El
+.Sh HISTORY
+The
+.Fn pthread_rwlockattr_getpshared
+function first appeared in
+.Fx 3.0 .
--- /dev/null
+.\" Copyright (c) 1998 Alex Nash
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_rwlockattr_init.3,v 1.6 2001/10/01 16:09:09 ru Exp $
+.\"
+.Dd August 4, 1998
+.Dt PTHREAD_RWLOCKATTR_INIT 3
+.Os
+.Sh NAME
+.Nm pthread_rwlockattr_init
+.Nd initialize a read/write lock
+.Sh SYNOPSIS
+.In pthread.h
+.Ft int
+.Fo pthread_rwlockattr_init
+.Fa "pthread_rwlockattr_t *attr"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_rwlockattr_init
+function is used to initialize a read/write lock attribute object.
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_rwlockattr_init
+function will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh SEE ALSO
+.Xr pthread_rwlock_init 3 ,
+.Xr pthread_rwlockattr_destroy 3 ,
+.Xr pthread_rwlockattr_getpshared 3 ,
+.Xr pthread_rwlockattr_setpshared 3
+.Sh STANDARDS
+The
+.Fn pthread_rwlockattr_init
+function is expected to conform to
+.St -susv2 .
+.Sh ERRORS
+.Fn pthread_rwlockattr_init
+will fail if:
+.Bl -tag -width Er
+.It Bq Er ENOMEM
+Insufficient memory exists to initialize the attribute object.
+.El
+.Sh HISTORY
+The
+.Fn pthread_rwlockattr_init
+function first appeared in
+.Fx 3.0 .
--- /dev/null
+.\" Copyright (c) 1998 Alex Nash
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_rwlockattr_setpshared.3,v 1.7 2001/10/01 16:09:09 ru Exp $
+.\"
+.Dd August 4, 1998
+.Dt PTHREAD_RWLOCKATTR_SETPSHARED 3
+.Os
+.Sh NAME
+.Nm pthread_rwlockattr_setpshared
+.Nd set the process shared attribute
+.Sh SYNOPSIS
+.In pthread.h
+.Ft int
+.Fo pthread_rwlockattr_setpshared
+.Fa "pthread_rwlockattr_t *attr"
+.Fa "int pshared"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_rwlockattr_setpshared
+function sets the process-shared attribute of
+.Fa attr
+to the value referenced by
+.Fa pshared .
+.Fa pshared
+may be one of two values:
+.Bl -tag -width PTHREAD_PROCESS_PRIVATE
+.It Dv PTHREAD_PROCESS_SHARED
+Any thread of any process that has access to the memory where the
+read/write lock resides can manipulate the lock.
+.It Dv PTHREAD_PROCESS_PRIVATE
+Only threads created within the same process as the thread that
+initialized the read/write lock can manipulate the lock. This is
+the default value.
+.El
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_rwlockattr_setpshared
+function will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh SEE ALSO
+.Xr pthread_rwlock_init 3 ,
+.Xr pthread_rwlockattr_init 3 ,
+.Xr pthread_rwlockattr_setpshared 3
+.Sh STANDARDS
+The
+.Fn pthread_rwlockattr_setpshared
+function is expected to conform to
+.St -susv2 .
+.Sh ERRORS
+.Fn pthread_rwlockattr_setpshared
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The value specified by
+.Fa attr
+or
+.Fa pshared
+is invalid.
+.El
+.Sh HISTORY
+The
+.Fn pthread_rwlockattr_setpshared
+function first appeared in
+.Fx 3.0 .
+.Sh BUGS
+The
+.Dv PTHREAD_PROCESS_SHARED
+attribute is not supported.
--- /dev/null
+.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by John Birrell.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_self.3,v 1.4.2.4 2001/08/17 15:42:52 ru Exp $
+.\"
+.Dd April 4, 1996
+.Dt PTHREAD_SELF 3
+.Os
+.Sh NAME
+.Nm pthread_self
+.Nd get the calling thread's ID
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft pthread_t
+.Fn pthread_self "void"
+.Sh DESCRIPTION
+The
+.Fn pthread_self
+function returns the thread ID of the calling thread.
+.Sh RETURN VALUES
+The
+.Fn pthread_self
+function returns the thread ID of the calling thread.
+.Sh ERRORS
+None.
+.Sh SEE ALSO
+.Xr pthread_create 3 ,
+.Xr pthread_equal 3
+.Sh STANDARDS
+.Fn pthread_self
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" $FreeBSD: src/lib/libc_r/man/pthread_testcancel.3,v 1.2.2.3 2001/08/17 15:42:52 ru Exp $
+.Dd January 17, 1999
+.Dt PTHREAD_TESTCANCEL 3
+.Os
+.Sh NAME
+.Nm pthread_setcancelstate ,
+.Nm pthread_setcanceltype ,
+.Nm pthread_testcancel
+.Nd set cancelability state
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_setcancelstate
+.Fa "int state"
+.Fa "int *oldstate"
+.Fc
+.Ft int
+.Fo pthread_setcanceltype
+.Fa "int type"
+.Fa "int *oldtype"
+.Fc
+.Ft void
+.Fo pthread_testcancel
+.Fa "void"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_setcancelstate
+function atomically both sets the calling thread's cancelability state
+to the indicated
+.Fa state
+and returns the previous cancelability state at the location referenced by
+.Fa oldstate .
+Legal values for
+.Fa state
+are
+.Dv PTHREAD_CANCEL_ENABLE
+and
+.Dv PTHREAD_CANCEL_DISABLE .
+.Pp
+The
+.Fn pthread_setcanceltype
+function atomically both sets the calling thread's cancelability type
+to the indicated
+.Fa type
+and returns the previous cancelability type at the location referenced by
+.Fa oldtype .
+Legal values for
+.Fa type
+are
+.Dv PTHREAD_CANCEL_DEFERRED
+and
+.Dv PTHREAD_CANCEL_ASYNCHRONOUS .
+.Pp
+The cancelability state and type of any newly created threads, including the
+thread in which
+.Fn main
+was first invoked, are
+.Dv PTHREAD_CANCEL_ENABLE
+and
+.Dv PTHREAD_CANCEL_DEFERRED
+respectively.
+.Pp
+The
+.Fn pthread_testcancel
+function creates a cancellation point in the calling thread.
+The
+.Fn pthread_testcancel
+function has no effect if cancelability is disabled.
+.Pp
+.Ss Cancelability States
+The cancelability state of a thread determines the action taken upon
+receipt of a cancellation request.
+The thread may control cancellation in
+a number of ways.
+.Pp
+Each thread maintains its own
+.Dq cancelability state
+which may be encoded in two bits:
+.Bl -hang
+.It Em Cancelability Enable
+When cancelability is
+.Dv PTHREAD_CANCEL_DISABLE ,
+cancellation requests against the target thread are held pending.
+.It Em Cancelability Type
+When cancelability is enabled and the cancelability type is
+.Dv PTHREAD_CANCEL_ASYNCHRONOUS ,
+new or pending cancellation requests may be acted upon at any time.
+When cancelability is enabled and the cancelability type is
+.Dv PTHREAD_CANCEL_DEFERRED ,
+cancellation requests are held pending until a cancellation point (see
+below) is reached.
+If cancelability is disabled, the setting of the
+cancelability type has no immediate effect as all cancellation requests
+are held pending; however, once cancelability is enabled again the new
+type will be in effect.
+.El
+.Ss Cancellation Points
+Cancellation points will occur when a thread is executing the following
+functions:
+.Fn accept ,
+.Fn aio_suspend ,
+.Fn close ,
+.\" .Fn clock_nanosleep ,
+.Fn connect ,
+.Fn creat ,
+.Fn fcntl ,
+.\" .Fn fdatasync ,
+.Fn fsync ,
+.\" .Fn getmsg ,
+.\" .Fn getpmsg ,
+.Fn lockf ,
+.\" .Fn mq_receive ,
+.\" .Fn mq_send ,
+.\" .Fn mq_timedreceive ,
+.\" .Fn mq_timedsend ,
+.Fn msgrcv ,
+.Fn msgsnd ,
+.Fn msync ,
+.Fn nanosleep ,
+.Fn open ,
+.Fn pause ,
+.Fn poll ,
+.Fn pread ,
+.Fn pselect ,
+.Fn pthread_cond_timedwait ,
+.Fn pthread_cond_wait ,
+.Fn pthread_join ,
+.Fn pthread_testcancel ,
+.\" .Fn putmsg ,
+.\" .Fn putpmsg ,
+.Fn pwrite ,
+.Fn read ,
+.Fn readv ,
+.Fn recv ,
+.Fn recvfrom ,
+.Fn recvmsg ,
+.Fn select ,
+.\" .Fn sem_timedwait ,
+.Fn sem_wait ,
+.Fn send ,
+.Fn sendmsg ,
+.Fn sendto ,
+.Fn sigpause ,
+.Fn sigsuspend ,
+.\" .Fn sigtimedwait ,
+.Fn sigwait ,
+.\" .Fn sigwaitinfo ,
+.Fn sleep ,
+.Fn system ,
+.Fn tcdrain ,
+.Fn usleep ,
+.Fn wait ,
+.Fn waitpid ,
+.Fn write ,
+.Fn writev .
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_setcancelstate
+and
+.Fn pthread_setcanceltype
+functions will return zero.
+Otherwise, an error number shall be returned to
+indicate the error.
+.Pp
+The
+.Fn pthread_setcancelstate
+and
+.Fn pthread_setcanceltype
+functions are used to control the points at which a thread may be
+asynchronously canceled.
+For cancellation control to be usable in modular
+fashion, some rules must be followed.
+.Pp
+For purposes of this discussion, consider an object to be a generalization
+of a procedure.
+It is a set of procedures and global variables written as
+a unit and called by clients not known by the object.
+Objects may depend
+on other objects.
+.Pp
+First, cancelability should only be disabled on entry to an object, never
+explicitly enabled.
+On exit from an object, the cancelability state should
+always be restored to its value on entry to the object.
+.Pp
+This follows from a modularity argument: if the client of an object (or the
+client of an object that uses that object) has disabled cancelability, it is
+because the client doesn't want to have to worry about how to clean up if the
+thread is canceled while executing some sequence of actions.
+If an object
+is called in such a state and it enables cancelability and a cancellation
+request is pending for that thread, then the thread will be canceled,
+contrary to the wish of the client that disabled.
+.Pp
+Second, the cancelability type may be explicitly set to either
+.Em deferred
+or
+.Em asynchronous
+upon entry to an object.
+But, as with the cancelability state, on exit from
+an object that cancelability type should always be restored to its value on
+entry to the object.
+.Pp
+Finally, only functions that are cancel-safe may be called from a thread that
+is asynchronously cancelable.
+.Sh ERRORS
+The function
+.Fn pthread_setcancelstate
+may fail with:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The specified state is not
+.Dv PTHREAD_CANCEL_ENABLE
+or
+.Dv PTHREAD_CANCEL_DISABLE .
+.El
+.Pp
+The function
+.Fn pthread_setcanceltype
+may fail with:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The specified state is not
+.Dv PTHREAD_CANCEL_DEFERRED
+or
+.Dv PTHREAD_CANCEL_ASYNCHRONOUS .
+.El
+.Sh SEE ALSO
+.Xr pthread_cancel 3
+.Sh STANDARDS
+.Fn pthread_testcancel
+conforms to
+.St -p1003.1-96 .
+.Sh AUTHORS
+This man page was written by
+.An David Leonard Aq d@openbsd.org
+for the
+.Ox
+implementation of
+.Xr pthread_cancel 3 .
--- /dev/null
+.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by John Birrell.
+.\" 4. Neither the name of the author nor the names of any co-contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_setspecific.3,v 1.6.2.4 2001/08/17 15:42:52 ru Exp $
+.\"
+.Dd April 4, 1996
+.Dt PTHREAD_SETSPECIFIC 3
+.Os
+.Sh NAME
+.Nm pthread_setspecific
+.Nd set a thread-specific data value
+.Sh SYNOPSIS
+.Fd #include <pthread.h>
+.Ft int
+.Fo pthread_setspecific
+.Fa "pthread_key_t key"
+.Fa "const void *value"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_setspecific
+function associates a thread-specific value with a
+.Fa key
+obtained via a previous call to
+.Fn pthread_key_create .
+Different threads may bind different values to the same key.
+These values are
+typically pointers to blocks of dynamically allocated memory that have been
+reserved for use by the calling thread.
+.Pp
+The effect of calling
+.Fn pthread_setspecific
+with a key value not obtained from
+.Fn pthread_key_create ,
+or after
+.Fa key
+has been deleted with
+.Fn pthread_key_delete ,
+is undefined.
+.Pp
+.Fn pthread_setspecific
+may be called from a thread-specific data destructor function;
+however, this may result in lost storage or infinite loops.
+.Sh RETURN VALUES
+If successful, the
+.Fn pthread_setspecific
+function will return zero.
+Otherwise, an error number will be returned to indicate the error.
+.Sh ERRORS
+.Fn pthread_setspecific
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa key
+value is invalid.
+.It Bq Er ENOMEM
+Insufficient memory exists to associate the value with the
+.Fa key .
+.El
+.Sh SEE ALSO
+.Xr pthread_getspecific 3 ,
+.Xr pthread_key_create 3 ,
+.Xr pthread_key_delete 3
+.Sh STANDARDS
+.Fn pthread_setspecific
+conforms to
+.St -p1003.1-96 .
--- /dev/null
+.\" Copyright (C) 2000 Jason Evans <jasone@FreeBSD.org>.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice(s), this list of conditions and the following disclaimer as
+.\" the first lines of this file unmodified other than the possible
+.\" addition of one or more copyright notices.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice(s), this list of conditions and the following disclaimer in
+.\" the documentation and/or other materials provided with the
+.\" distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
+.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" $FreeBSD: src/lib/libc_r/man/pthread_sigmask.3,v 1.9 2001/10/01 16:09:09 ru Exp $
+.Dd April 27, 2000
+.Dt PTHREAD_SIGMASK 2
+.Os
+.Sh NAME
+.Nm pthread_sigmask
+.Nd examine and/or change a thread's signal mask
+.Sh SYNOPSIS
+.In signal.h
+.Ft int
+.Fo pthread_sigmask
+.Fa "int how"
+.Fa "const sigset_t *restrict set"
+.Fa "sigset_t *restrict oset"
+.Fc
+.Sh DESCRIPTION
+The
+.Fn pthread_sigmask
+function examines and/or changes the calling thread's signal mask.
+.Pp
+If
+.Fa set
+is not
+.Dv NULL ,
+it specifies a set of signals to be modified, and
+.Fa how
+specifies what to set the signal mask to:
+.Bl -tag -width SIG_UNBLOCK
+.It Dv SIG_BLOCK
+Union of the current mask and
+.Fa set .
+.It Dv SIG_UNBLOCK
+Intersection of the current mask and the complement of
+.Fa set .
+.It Dv SIG_SETMASK
+.Fa set .
+.El
+.Pp
+If
+.Fa oset
+is not NULL, the previous signal mask is stored in the location pointed to by
+.Fa oset .
+.Pp
+.Dv SIGKILL
+and
+.Dv SIGSTOP
+cannot be blocked, and will be silently ignored if included in the signal mask.
+.Sh RETURN VALUES
+If successful,
+.Fn pthread_sigmask
+returns 0.
+Otherwise, an error is returned.
+.Sh ERRORS
+.Fn pthread_sigmask
+will fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+.Fa how
+is not one of the defined values.
+.El
+.Sh LEGACY SYNOPSIS
+.Fd #include <pthread.h>
+.Fd #include <signal.h>
+.Pp
+The include file
+.In pthread.h
+is necessary.
+.Sh SEE ALSO
+.Xr sigaction 2 ,
+.Xr sigpending 2 ,
+.Xr sigprocmask 2 ,
+.Xr sigsuspend 2 ,
+.Xr sigsetops 3 ,
+.Xr compat 5
+.Sh STANDARDS
+.Fn pthread_sigmask
+conforms to ISO/IEC 9945-1:1996 (``POSIX.1'')
--- /dev/null
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#ifndef __PTHREAD_INTROSPECTION_PRIVATE__
+#define __PTHREAD_INTROSPECTION_PRIVATE__
+
+#include <sys/cdefs.h>
+#include <pthread/pthread.h>
+#include <Availability.h>
+
+/*!
+ * @header
+ *
+ * @abstract
+ * Introspection SPI for libpthread.
+ */
+
+__BEGIN_DECLS
+
+/*!
+ * @typedef pthread_introspection_hook_t
+ *
+ * @abstract
+ * A function pointer called at various points in a PThread's lifetime.
+ *
+ * @param event
+ * One of the events in pthread_introspection_event_t.
+ *
+ * @param thread
+ * pthread_t associated with the event.
+ *
+ * @param addr
+ * Address associated with the event.
+ *
+ * @param size
+ * Size associated with the event.
+ */
+typedef void (*pthread_introspection_hook_t)(unsigned int event,
+ pthread_t thread, void *addr, size_t size);
+
+/*!
+ * @enum pthread_introspection_event_t
+ *
+ * @constant PTHREAD_INTROSPECTION_THREAD_CREATE
+ * pthread_t was created.
+ *
+ * @constant PTHREAD_INTROSPECTION_THREAD_START
+ * Thread has started and stack was allocated.
+ *
+ * @constant PTHREAD_INTROSPECTION_THREAD_TERMINATE
+ * Thread is about to be terminated and stack will be deallocated.
+ *
+ * @constant PTHREAD_INTROSPECTION_THREAD_DESTROY
+ * pthread_t is about to be destroyed.
+ */
+enum {
+ PTHREAD_INTROSPECTION_THREAD_CREATE = 1,
+ PTHREAD_INTROSPECTION_THREAD_START,
+ PTHREAD_INTROSPECTION_THREAD_TERMINATE,
+ PTHREAD_INTROSPECTION_THREAD_DESTROY,
+};
+
+/*!
+ * @function pthread_introspection_hook_install
+ *
+ * @abstract
+ * Install introspection hook function into libpthread.
+ *
+ * @discussion
+ * The caller is responsible for implementing chaining to the hook that was
+ * previously installed (if any).
+ *
+ * @param hook
+ * Pointer to hook function.
+ *
+ * @result
+ * Previously installed hook function or NULL.
+ */
+
+__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
+__attribute__((__nonnull__, __warn_unused_result__))
+extern pthread_introspection_hook_t
+pthread_introspection_hook_install(pthread_introspection_hook_t hook);
+
+__END_DECLS
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * MkLinux
+ */
+
+/*
+ * POSIX Realtime Scheduling Framework - IEEE 1003.1b
+ */
+
+#ifndef _POSIX_SCHED_H
+#define _POSIX_SCHED_H
+
+struct sched_param
+{
+ int sched_priority;
+ int quantum;
+};
+
+/*
+ * POSIX scheduling policies
+ */
+
+#define SCHED_OTHER POLICY_TIMESHARE
+#define SCHED_FIFO POLICY_FIFO
+#define SCHED_RR POLICY_RR
+
+#endif /* _POSIX_SCHED_H */
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#ifndef __PTHREAD_PRIVATE_H__
+#define __PTHREAD_PRIVATE_H__
+
+#include <sys/cdefs.h>
+#include <Availability.h>
+#include <pthread/tsd_private.h>
+
+/* get the thread specific errno value */
+__header_always_inline int
+_pthread_get_errno_direct(void)
+{
+ return *(int*)_pthread_getspecific_direct(_PTHREAD_TSD_SLOT_ERRNO);
+}
+
+/* set the thread specific errno value */
+__header_always_inline void
+_pthread_set_errno_direct(int value)
+{
+ *((int*)_pthread_getspecific_direct(_PTHREAD_TSD_SLOT_ERRNO)) = value;
+}
+
+__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
+pthread_t pthread_main_thread_np(void);
+
+struct _libpthread_functions {
+ unsigned long version;
+ void (*exit)(int); // added with version=1
+ void *(*malloc)(size_t); // added with version=2
+ void (*free)(void *); // added with version=2
+};
+
+#endif // __PTHREAD_PRIVATE_H__
--- /dev/null
+/*
+ * Copyright (c) 2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#ifndef _QOS_LEGACY_H
+#define _QOS_LEGACY_H
+
+#include_next <pthread/qos.h>
+
+#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
+
+// <rdar://problem/16611709>
+#define QOS_CLASS_LEGACY QOS_CLASS_DEFAULT
+
+#ifdef __has_include
+#if __has_include(<pthread/qos_private.h>)
+#include <pthread/qos_private.h>
+#endif
+#endif
+
+#endif // __DARWIN_C_LEVEL >= __DARWIN_C_FULL
+
+#endif //_QOS_LEGACY_H
--- /dev/null
+/*
+ * Copyright (c) 2013-2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#ifndef _QOS_PRIVATE_H
+#define _QOS_PRIVATE_H
+
+#include <pthread/qos.h>
+#include <sys/qos_private.h>
+
+#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
+// allow __DARWIN_C_LEVEL to turn off the use of mach_port_t
+#include <mach/port.h>
+#endif
+
+// pthread_priority_t is an on opaque integer that is guaranteed to be ordered such that
+// combations of QoS classes and relative priorities are ordered numerically, according to
+// their combined priority.
+typedef unsigned long pthread_priority_t;
+
+// masks for splitting the handling the contents of a pthread_priority_t, the mapping from
+// qos_class_t to the class bits, however, is intentionally not exposed.
+#define _PTHREAD_PRIORITY_FLAGS_MASK (~0xffffff)
+#define _PTHREAD_PRIORITY_QOS_CLASS_MASK 0x00ffff00
+#define _PTHREAD_PRIORITY_QOS_CLASS_SHIFT (8ull)
+#define _PTHREAD_PRIORITY_PRIORITY_MASK 0x000000ff
+#define _PTHREAD_PRIORITY_PRIORITY_SHIFT (0)
+
+#define _PTHREAD_PRIORITY_OVERCOMMIT_FLAG 0x80000000
+#define _PTHREAD_PRIORITY_INHERIT_FLAG 0x40000000
+#define _PTHREAD_PRIORITY_ROOTQUEUE_FLAG 0x20000000
+#define _PTHREAD_PRIORITY_ENFORCE_FLAG 0x10000000
+#define _PTHREAD_PRIORITY_OVERRIDE_FLAG 0x08000000
+
+// redeffed here to avoid leaving __QOS_ENUM defined in the public header
+#define __QOS_ENUM(name, type, ...) enum { __VA_ARGS__ }; typedef type name##_t
+#define __QOS_AVAILABLE_STARTING(x, y)
+
+#if defined(__has_feature) && defined(__has_extension)
+#if __has_feature(objc_fixed_enum) || __has_extension(cxx_strong_enums)
+#undef __QOS_ENUM
+#define __QOS_ENUM(name, type, ...) typedef enum : type { __VA_ARGS__ } name##_t
+#endif
+#if __has_feature(enumerator_attributes)
+#undef __QOS_AVAILABLE_STARTING
+#define __QOS_AVAILABLE_STARTING __OSX_AVAILABLE_STARTING
+#endif
+#endif
+
+__QOS_ENUM(_pthread_set_flags, unsigned int,
+ _PTHREAD_SET_SELF_QOS_FLAG
+ __QOS_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) = 0x1,
+ _PTHREAD_SET_SELF_VOUCHER_FLAG
+ __QOS_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) = 0x2,
+ _PTHREAD_SET_SELF_FIXEDPRIORITY_FLAG
+ __QOS_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) = 0x4,
+);
+
+#undef __QOS_ENUM
+#undef __QOS_AVAILABLE_STARTING
+
+#ifndef KERNEL
+
+__BEGIN_DECLS
+
+/*!
+ * @function pthread_set_qos_class_np
+ *
+ * @abstract
+ * Sets the requested QOS class and relative priority of the current thread.
+ *
+ * @discussion
+ * The QOS class and relative priority represent an overall combination of
+ * system quality of service attributes on a thread.
+ *
+ * Subsequent calls to interfaces such as pthread_setschedparam() that are
+ * incompatible or in conflict with the QOS class system will unset the QOS
+ * class requested with this interface and pthread_get_qos_class_np() will
+ * return QOS_CLASS_UNSPECIFIED thereafter. A thread so modified is permanently
+ * opted-out of the QOS class system and calls to this function to request a QOS
+ * class for such a thread will fail and return EPERM.
+ *
+ * @param __pthread
+ * The current thread as returned by pthread_self().
+ * EINVAL will be returned if any other thread is provided.
+ *
+ * @param __qos_class
+ * A QOS class value:
+ * - QOS_CLASS_USER_INTERACTIVE
+ * - QOS_CLASS_USER_INITIATED
+ * - QOS_CLASS_DEFAULT
+ * - QOS_CLASS_UTILITY
+ * - QOS_CLASS_BACKGROUND
+ * - QOS_CLASS_MAINTENANCE
+ * EINVAL will be returned if any other value is provided.
+ *
+ * @param __relative_priority
+ * A relative priority within the QOS class. This value is a negative offset
+ * from the maximum supported scheduler priority for the given class.
+ * EINVAL will be returned if the value is greater than zero or less than
+ * QOS_MIN_RELATIVE_PRIORITY.
+ *
+ * @return
+ * Zero if successful, othwerise an errno value.
+ */
+__OSX_AVAILABLE_BUT_DEPRECATED_MSG(__MAC_10_10, __MAC_10_10, __IPHONE_8_0, __IPHONE_8_0, \
+ "Use pthread_set_qos_class_self_np() instead")
+int
+pthread_set_qos_class_np(pthread_t __pthread,
+ qos_class_t __qos_class,
+ int __relative_priority);
+
+/* Private interfaces for libdispatch to encode/decode specific values of pthread_priority_t. */
+
+// Encode a class+priority pair into a pthread_priority_t,
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+pthread_priority_t
+_pthread_qos_class_encode(qos_class_t qos_class, int relative_priority, unsigned long flags);
+
+// Decode a pthread_priority_t into a class+priority pair.
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+qos_class_t
+_pthread_qos_class_decode(pthread_priority_t priority, int *relative_priority, unsigned long *flags);
+
+// Encode a legacy workqueue API priority into a pthread_priority_t
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+pthread_priority_t
+_pthread_qos_class_encode_workqueue(int queue_priority, unsigned long flags);
+
+#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
+// Set QoS or voucher, or both, on pthread_self()
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+_pthread_set_properties_self(_pthread_set_flags_t flags, pthread_priority_t priority, mach_port_t voucher);
+
+// Set self to fixed priority without disturbing QoS or priority
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+pthread_set_fixedpriority_self(void);
+
+#endif
+
+__END_DECLS
+
+#endif // KERNEL
+
+#endif //_QOS_PRIVATE_H
--- /dev/null
+/*
+ * Copyright (c) 2003, 2013 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * MkLinux
+ */
+
+/*
+ * POSIX Threads - IEEE 1003.1c
+ */
+
+#ifndef _POSIX_PTHREAD_SPINLOCK_H
+#define _POSIX_PTHREAD_SPINLOCK_H
+
+#include <sys/cdefs.h>
+#include <mach/mach.h>
+#include <libkern/OSAtomic.h>
+
+typedef volatile OSSpinLock pthread_lock_t;
+
+#define LOCK_INIT(l) ((l) = OS_SPINLOCK_INIT)
+#define LOCK_INITIALIZER OS_SPINLOCK_INIT
+
+#define _DO_SPINLOCK_LOCK(v) OSSpinLockLock(v)
+#define _DO_SPINLOCK_UNLOCK(v) OSSpinLockUnlock(v)
+
+#define TRY_LOCK(v) OSSpinLockTry((volatile OSSpinLock *)&(v))
+#define LOCK(v) OSSpinLockLock((volatile OSSpinLock *)&(v))
+#define UNLOCK(v) OSSpinLockUnlock((volatile OSSpinLock *)&(v))
+
+extern void _spin_lock(pthread_lock_t *lockp) __deprecated_msg("Use OSSpinLockLock instead");
+extern int _spin_lock_try(pthread_lock_t *lockp) __deprecated_msg("Use OSSpinLockTry instead");
+extern void _spin_unlock(pthread_lock_t *lockp) __deprecated_msg("Use OSSpinLockUnlock instead");
+
+extern void spin_lock(pthread_lock_t *lockp) __deprecated_msg("Use OSSpinLockLock instead");
+extern int spin_lock_try(pthread_lock_t *lockp) __deprecated_msg("Use OSSpinLockTry instead");
+extern void spin_unlock(pthread_lock_t *lockp) __deprecated_msg("Use OSSpinLockUnlock instead");
+
+#endif /* _POSIX_PTHREAD_SPINLOCK_H */
--- /dev/null
+/*
+ * Copyright (c) 2003-2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * MkLinux
+ */
+
+#ifndef __PTHREAD_TSD_H__
+#define __PTHREAD_TSD_H__
+
+#ifndef __ASSEMBLER__
+
+#include <System/machine/cpu_capabilities.h>
+#include <sys/cdefs.h>
+#include <TargetConditionals.h>
+#include <os/tsd.h>
+#include <pthread/spinlock_private.h>
+
+#ifndef __TSD_MACH_THREAD_SELF
+#define __TSD_MACH_THREAD_SELF 3
+#endif
+
+#ifndef __TSD_THREAD_QOS_CLASS
+#define __TSD_THREAD_QOS_CLASS 4
+#endif
+
+/* Constant TSD slots for inline pthread_getspecific() usage. */
+
+/* Keys 0 - 9 are for Libsyscall/libplatform usage */
+#define _PTHREAD_TSD_SLOT_PTHREAD_SELF __TSD_THREAD_SELF
+#define _PTHREAD_TSD_SLOT_ERRNO __TSD_ERRNO
+#define _PTHREAD_TSD_SLOT_MIG_REPLY __TSD_MIG_REPLY
+#define _PTHREAD_TSD_SLOT_MACH_THREAD_SELF __TSD_MACH_THREAD_SELF
+#define _PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS __TSD_THREAD_QOS_CLASS
+//#define _PTHREAD_TSD_SLOT_SEMAPHORE_CACHE__TSD_SEMAPHORE_CACHE
+
+#define _PTHREAD_TSD_RESERVED_SLOT_COUNT _PTHREAD_TSD_RESERVED_SLOT_COUNT
+
+/* Keys 10 - 29 are for Libc/Libsystem internal usage */
+/* used as __pthread_tsd_first + Num */
+#define __PTK_LIBC_LOCALE_KEY 10
+#define __PTK_LIBC_TTYNAME_KEY 11
+#define __PTK_LIBC_LOCALTIME_KEY 12
+#define __PTK_LIBC_GMTIME_KEY 13
+#define __PTK_LIBC_GDTOA_BIGINT_KEY 14
+#define __PTK_LIBC_PARSEFLOAT_KEY 15
+/* for usage by dyld */
+#define __PTK_LIBC_DYLD_Unwind_SjLj_Key 18
+
+/* Keys 20-29 for libdispatch usage */
+#define __PTK_LIBDISPATCH_KEY0 20
+#define __PTK_LIBDISPATCH_KEY1 21
+#define __PTK_LIBDISPATCH_KEY2 22
+#define __PTK_LIBDISPATCH_KEY3 23
+#define __PTK_LIBDISPATCH_KEY4 24
+#define __PTK_LIBDISPATCH_KEY5 25
+#define __PTK_LIBDISPATCH_KEY6 26
+#define __PTK_LIBDISPATCH_KEY7 27
+#define __PTK_LIBDISPATCH_KEY8 28
+#define __PTK_LIBDISPATCH_KEY9 29
+
+/* Keys 30-255 for Non Libsystem usage */
+
+/* Keys 30-39 for Graphic frameworks usage */
+#define _PTHREAD_TSD_SLOT_OPENGL 30 /* backwards compat sake */
+#define __PTK_FRAMEWORK_OPENGL_KEY 30
+#define __PTK_FRAMEWORK_GRAPHICS_KEY1 31
+#define __PTK_FRAMEWORK_GRAPHICS_KEY2 32
+#define __PTK_FRAMEWORK_GRAPHICS_KEY3 33
+#define __PTK_FRAMEWORK_GRAPHICS_KEY4 34
+#define __PTK_FRAMEWORK_GRAPHICS_KEY5 35
+#define __PTK_FRAMEWORK_GRAPHICS_KEY6 36
+#define __PTK_FRAMEWORK_GRAPHICS_KEY7 37
+#define __PTK_FRAMEWORK_GRAPHICS_KEY8 38
+#define __PTK_FRAMEWORK_GRAPHICS_KEY9 39
+
+/* Keys 40-49 for Objective-C runtime usage */
+#define __PTK_FRAMEWORK_OBJC_KEY0 40
+#define __PTK_FRAMEWORK_OBJC_KEY1 41
+#define __PTK_FRAMEWORK_OBJC_KEY2 42
+#define __PTK_FRAMEWORK_OBJC_KEY3 43
+#define __PTK_FRAMEWORK_OBJC_KEY4 44
+#define __PTK_FRAMEWORK_OBJC_KEY5 45
+#define __PTK_FRAMEWORK_OBJC_KEY6 46
+#define __PTK_FRAMEWORK_OBJC_KEY7 47
+#define __PTK_FRAMEWORK_OBJC_KEY8 48
+#define __PTK_FRAMEWORK_OBJC_KEY9 49
+
+/* Keys 50-59 for Core Foundation usage */
+#define __PTK_FRAMEWORK_COREFOUNDATION_KEY0 50
+#define __PTK_FRAMEWORK_COREFOUNDATION_KEY1 51
+#define __PTK_FRAMEWORK_COREFOUNDATION_KEY2 52
+#define __PTK_FRAMEWORK_COREFOUNDATION_KEY3 53
+#define __PTK_FRAMEWORK_COREFOUNDATION_KEY4 54
+#define __PTK_FRAMEWORK_COREFOUNDATION_KEY5 55
+#define __PTK_FRAMEWORK_COREFOUNDATION_KEY6 56
+#define __PTK_FRAMEWORK_COREFOUNDATION_KEY7 57
+#define __PTK_FRAMEWORK_COREFOUNDATION_KEY8 58
+#define __PTK_FRAMEWORK_COREFOUNDATION_KEY9 59
+
+/* Keys 60-69 for Foundation usage */
+#define __PTK_FRAMEWORK_FOUNDATION_KEY0 60
+#define __PTK_FRAMEWORK_FOUNDATION_KEY1 61
+#define __PTK_FRAMEWORK_FOUNDATION_KEY2 62
+#define __PTK_FRAMEWORK_FOUNDATION_KEY3 63
+#define __PTK_FRAMEWORK_FOUNDATION_KEY4 64
+#define __PTK_FRAMEWORK_FOUNDATION_KEY5 65
+#define __PTK_FRAMEWORK_FOUNDATION_KEY6 66
+#define __PTK_FRAMEWORK_FOUNDATION_KEY7 67
+#define __PTK_FRAMEWORK_FOUNDATION_KEY8 68
+#define __PTK_FRAMEWORK_FOUNDATION_KEY9 69
+
+/* Keys 70-79 for Core Animation/QuartzCore usage */
+#define __PTK_FRAMEWORK_QUARTZCORE_KEY0 70
+#define __PTK_FRAMEWORK_QUARTZCORE_KEY1 71
+#define __PTK_FRAMEWORK_QUARTZCORE_KEY2 72
+#define __PTK_FRAMEWORK_QUARTZCORE_KEY3 73
+#define __PTK_FRAMEWORK_QUARTZCORE_KEY4 74
+#define __PTK_FRAMEWORK_QUARTZCORE_KEY5 75
+#define __PTK_FRAMEWORK_QUARTZCORE_KEY6 76
+#define __PTK_FRAMEWORK_QUARTZCORE_KEY7 77
+#define __PTK_FRAMEWORK_QUARTZCORE_KEY8 78
+#define __PTK_FRAMEWORK_QUARTZCORE_KEY9 79
+
+
+/* Keys 80-89 for CoreData */
+#define __PTK_FRAMEWORK_COREDATA_KEY0 80
+#define __PTK_FRAMEWORK_COREDATA_KEY1 81
+#define __PTK_FRAMEWORK_COREDATA_KEY2 82
+#define __PTK_FRAMEWORK_COREDATA_KEY3 83
+#define __PTK_FRAMEWORK_COREDATA_KEY4 84
+#define __PTK_FRAMEWORK_COREDATA_KEY5 85
+#define __PTK_FRAMEWORK_COREDATA_KEY6 86
+#define __PTK_FRAMEWORK_COREDATA_KEY7 87
+#define __PTK_FRAMEWORK_COREDATA_KEY8 88
+#define __PTK_FRAMEWORK_COREDATA_KEY9 89
+
+/* Keys 90-94 for JavaScriptCore Collection */
+#define __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY0 90
+#define __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY1 91
+#define __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY2 92
+#define __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY3 93
+#define __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY4 94
+/* Keys 95 for CoreText */
+#define __PTK_FRAMEWORK_CORETEXT_KEY0 95
+
+/* Keys 110-119 for Garbage Collection */
+#define __PTK_FRAMEWORK_GC_KEY0 110
+#define __PTK_FRAMEWORK_GC_KEY1 111
+#define __PTK_FRAMEWORK_GC_KEY2 112
+#define __PTK_FRAMEWORK_GC_KEY3 113
+#define __PTK_FRAMEWORK_GC_KEY4 114
+#define __PTK_FRAMEWORK_GC_KEY5 115
+#define __PTK_FRAMEWORK_GC_KEY6 116
+#define __PTK_FRAMEWORK_GC_KEY7 117
+#define __PTK_FRAMEWORK_GC_KEY8 118
+#define __PTK_FRAMEWORK_GC_KEY9 119
+
+/* Keys 210 - 229 are for libSystem usage within the iOS Simulator */
+/* They are offset from their corresponding libSystem keys by 200 */
+#define __PTK_LIBC_SIM_LOCALE_KEY 210
+#define __PTK_LIBC_SIM_TTYNAME_KEY 211
+#define __PTK_LIBC_SIM_LOCALTIME_KEY 212
+#define __PTK_LIBC_SIM_GMTIME_KEY 213
+#define __PTK_LIBC_SIM_GDTOA_BIGINT_KEY 214
+#define __PTK_LIBC_SIM_PARSEFLOAT_KEY 215
+
+__BEGIN_DECLS
+
+extern void *pthread_getspecific(unsigned long);
+extern int pthread_setspecific(unsigned long, const void *);
+/* setup destructor function for static key as it is not created with pthread_key_create() */
+extern int pthread_key_init_np(int, void (*)(void *));
+
+#if PTHREAD_LAYOUT_SPI
+
+/* SPI intended for CoreSymbolication only */
+
+__OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0)
+extern const struct pthread_layout_offsets_s {
+ // always add new fields at the end
+ const uint16_t plo_version;
+ // either of the next two fields may be 0; use whichever is set
+ // bytes from pthread_t to base of tsd
+ const uint16_t plo_pthread_tsd_base_offset;
+ // bytes from pthread_t to a pointer to base of tsd
+ const uint16_t plo_pthread_tsd_base_address_offset;
+ const uint16_t plo_pthread_tsd_entry_size;
+} pthread_layout_offsets;
+
+#endif // PTHREAD_LAYOUT_SPI
+__END_DECLS
+
+#if TARGET_IPHONE_SIMULATOR
+
+__header_always_inline int
+_pthread_has_direct_tsd(void)
+{
+ return 0;
+}
+
+#define _pthread_getspecific_direct(key) pthread_getspecific((key))
+#define _pthread_setspecific_direct(key, val) pthread_setspecific((key), (val))
+
+#else /* TARGET_IPHONE_SIMULATOR */
+
+__header_always_inline int
+_pthread_has_direct_tsd(void)
+{
+ return 1;
+}
+
+/* To be used with static constant keys only */
+__header_always_inline void *
+_pthread_getspecific_direct(unsigned long slot)
+{
+ return _os_tsd_get_direct(slot);
+}
+
+/* To be used with static constant keys only */
+__header_always_inline int
+_pthread_setspecific_direct(unsigned long slot, void * val)
+{
+ return _os_tsd_set_direct(slot, val);
+}
+
+#endif /* TARGET_IPHONE_SIMULATOR */
+
+#endif /* ! __ASSEMBLER__ */
+#endif /* __PTHREAD_TSD_H__ */
--- /dev/null
+/*
+ * Copyright (c) 2007, 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#ifndef __PTHREAD_WORKQUEUE_H__
+#define __PTHREAD_WORKQUEUE_H__
+
+#include <sys/cdefs.h>
+#include <Availability.h>
+#include <pthread/pthread.h>
+#include <pthread/qos.h>
+#ifndef _PTHREAD_BUILDING_PTHREAD_
+#include <pthread/qos_private.h>
+#endif
+
+#define PTHREAD_WORKQUEUE_SPI_VERSION 20140730
+
+/* Feature checking flags, returned by _pthread_workqueue_supported()
+ *
+ * Note: These bits should match the definition of PTHREAD_FEATURE_*
+ * bits defined in libpthread/kern/kern_internal.h */
+
+#define WORKQ_FEATURE_DISPATCHFUNC 0x01 // pthread_workqueue_setdispatch_np is supported (or not)
+#define WORKQ_FEATURE_FINEPRIO 0x02 // fine grained pthread workq priorities
+#define WORKQ_FEATURE_MAINTENANCE 0x10 // QOS class maintenance
+
+/* Legacy dispatch priority bands */
+
+#define WORKQ_NUM_PRIOQUEUE 4
+
+#define WORKQ_HIGH_PRIOQUEUE 0 // high priority queue
+#define WORKQ_DEFAULT_PRIOQUEUE 1 // default priority queue
+#define WORKQ_LOW_PRIOQUEUE 2 // low priority queue
+#define WORKQ_BG_PRIOQUEUE 3 // background priority queue
+#define WORKQ_NON_INTERACTIVE_PRIOQUEUE 128 // libdispatch SPI level
+
+/* Legacy dispatch workqueue function flags */
+#define WORKQ_ADDTHREADS_OPTION_OVERCOMMIT 0x00000001
+
+__BEGIN_DECLS
+
+// Legacy callback prototype, used with pthread_workqueue_setdispatch_np
+typedef void (*pthread_workqueue_function_t)(int queue_priority, int options, void *ctxt);
+// New callback prototype, used with pthread_workqueue_init
+typedef void (*pthread_workqueue_function2_t)(pthread_priority_t priority);
+
+// Initialises the pthread workqueue subsystem, passing the new-style callback prototype,
+// the dispatchoffset and an unused flags field.
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+_pthread_workqueue_init(pthread_workqueue_function2_t func, int offset, int flags);
+
+// Non-zero enables kill on current thread, zero disables it.
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2)
+int
+__pthread_workqueue_setkill(int);
+
+// Dispatch function to be called when new worker threads are created.
+__OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0)
+int
+pthread_workqueue_setdispatch_np(pthread_workqueue_function_t worker_func);
+
+// Dispatch offset to be set in the kernel.
+__OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_7_0)
+void
+pthread_workqueue_setdispatchoffset_np(int offset);
+
+// Request additional worker threads.
+__OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0)
+int
+pthread_workqueue_addthreads_np(int queue_priority, int options, int numthreads);
+
+// Retrieve the supported pthread feature set
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+_pthread_workqueue_supported(void);
+
+// Request worker threads (fine grained priority)
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+_pthread_workqueue_addthreads(int numthreads, pthread_priority_t priority);
+
+// Apply a QoS override without allocating userspace memory
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+_pthread_override_qos_class_start_direct(mach_port_t thread, pthread_priority_t priority);
+
+// Drop a corresponding QoS override made above.
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+_pthread_override_qos_class_end_direct(mach_port_t thread);
+
+// Apply a QoS override on a given workqueue thread.
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+_pthread_workqueue_override_start_direct(mach_port_t thread, pthread_priority_t priority);
+
+// Drop all QoS overrides on the current workqueue thread.
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+_pthread_workqueue_override_reset(void);
+
+__END_DECLS
+
+#endif // __PTHREAD_WORKQUEUE_H__
--- /dev/null
+/*
+ * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * MkLinux
+ */
+
+/*
+ * POSIX Threads - IEEE 1003.1c
+ */
+
+#ifndef _PTHREAD_H
+#define _PTHREAD_H
+
+#include <_types.h>
+#ifndef __POSIX_LIB__
+#include <pthread/pthread_impl.h>
+#endif
+#include <pthread/sched.h>
+#include <time.h>
+#include <sys/_pthread/_pthread_types.h>
+#include <sys/_pthread/_pthread_attr_t.h>
+#include <sys/_pthread/_pthread_cond_t.h>
+#include <sys/_pthread/_pthread_condattr_t.h>
+#include <sys/_pthread/_pthread_key_t.h>
+#include <sys/_pthread/_pthread_mutex_t.h>
+#include <sys/_pthread/_pthread_mutexattr_t.h>
+#include <sys/_pthread/_pthread_once_t.h>
+#include <sys/_pthread/_pthread_rwlock_t.h>
+#include <sys/_pthread/_pthread_rwlockattr_t.h>
+#include <sys/_pthread/_pthread_t.h>
+
+#include <pthread/qos.h>
+
+#if (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || defined(_DARWIN_C_SOURCE)
+
+#include <sys/_types/_mach_port_t.h>
+#include <sys/_types/_sigset_t.h>
+
+#endif /* (!_POSIX_C_SOURCE && !_XOPEN_SOURCE) || _DARWIN_C_SOURCE */
+
+/*
+ * These symbols indicate which [optional] features are available
+ * They can be tested at compile time via '#ifdef XXX'
+ * The way to check for pthreads is like so:
+
+ * #include <unistd.h>
+ * #ifdef _POSIX_THREADS
+ * #include <pthread.h>
+ * #endif
+
+ */
+
+/* These will be moved to unistd.h */
+
+/*
+ * Note: These data structures are meant to be opaque. Only enough
+ * structure is exposed to support initializers.
+ * All of the typedefs will be moved to <sys/types.h>
+ */
+
+#include <sys/cdefs.h>
+#include <Availability.h>
+
+__BEGIN_DECLS
+/*
+ * Threads
+ */
+
+
+/*
+ * Cancel cleanup handler management. Note, since these are implemented as macros,
+ * they *MUST* occur in matched pairs!
+ */
+
+#define pthread_cleanup_push(func, val) \
+ { \
+ struct __darwin_pthread_handler_rec __handler; \
+ pthread_t __self = pthread_self(); \
+ __handler.__routine = func; \
+ __handler.__arg = val; \
+ __handler.__next = __self->__cleanup_stack; \
+ __self->__cleanup_stack = &__handler;
+
+#define pthread_cleanup_pop(execute) \
+ /* Note: 'handler' must be in this same lexical context! */ \
+ __self->__cleanup_stack = __handler.__next; \
+ if (execute) (__handler.__routine)(__handler.__arg); \
+ }
+
+/*
+ * Thread attributes
+ */
+
+#define PTHREAD_CREATE_JOINABLE 1
+#define PTHREAD_CREATE_DETACHED 2
+
+#define PTHREAD_INHERIT_SCHED 1
+#define PTHREAD_EXPLICIT_SCHED 2
+
+#define PTHREAD_CANCEL_ENABLE 0x01 /* Cancel takes place at next cancellation point */
+#define PTHREAD_CANCEL_DISABLE 0x00 /* Cancel postponed */
+#define PTHREAD_CANCEL_DEFERRED 0x02 /* Cancel waits until cancellation point */
+#define PTHREAD_CANCEL_ASYNCHRONOUS 0x00 /* Cancel occurs immediately */
+
+/* Value returned from pthread_join() when a thread is canceled */
+#define PTHREAD_CANCELED ((void *) 1)
+
+/* We only support PTHREAD_SCOPE_SYSTEM */
+#define PTHREAD_SCOPE_SYSTEM 1
+#define PTHREAD_SCOPE_PROCESS 2
+
+/* We only support PTHREAD_PROCESS_PRIVATE */
+#define PTHREAD_PROCESS_SHARED 1
+#define PTHREAD_PROCESS_PRIVATE 2
+
+/*
+ * Mutex protocol attributes
+ */
+#define PTHREAD_PRIO_NONE 0
+#define PTHREAD_PRIO_INHERIT 1
+#define PTHREAD_PRIO_PROTECT 2
+
+/*
+ * Mutex type attributes
+ */
+#define PTHREAD_MUTEX_NORMAL 0
+#define PTHREAD_MUTEX_ERRORCHECK 1
+#define PTHREAD_MUTEX_RECURSIVE 2
+#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL
+
+/*
+ * RWLock variables
+ */
+#define PTHREAD_RWLOCK_INITIALIZER {_PTHREAD_RWLOCK_SIG_init, {0}}
+
+/*
+ * Mutex variables
+ */
+#define PTHREAD_MUTEX_INITIALIZER {_PTHREAD_MUTEX_SIG_init, {0}}
+
+/* <rdar://problem/10854763> */
+#if ((__MAC_OS_X_VERSION_MIN_REQUIRED && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) || (__IPHONE_OS_VERSION_MIN_REQUIRED && __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000))
+# if (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || defined(_DARWIN_C_SOURCE)
+# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER {_PTHREAD_ERRORCHECK_MUTEX_SIG_init, {0}}
+# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER {_PTHREAD_RECURSIVE_MUTEX_SIG_init, {0}}
+# endif /* (!_POSIX_C_SOURCE && !_XOPEN_SOURCE) || _DARWIN_C_SOURCE */
+#endif
+
+/*
+ * Condition variable attributes
+ */
+
+/*
+ * Condition variables
+ */
+
+#define PTHREAD_COND_INITIALIZER {_PTHREAD_COND_SIG_init, {0}}
+
+/*
+ * Initialization control (once) variables
+ */
+
+#define PTHREAD_ONCE_INIT {_PTHREAD_ONCE_SIG_init, {0}}
+
+/*
+ * Prototypes for all PTHREAD interfaces
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_atfork(void (*)(void), void (*)(void), void (*)(void));
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_destroy(pthread_attr_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_getdetachstate(const pthread_attr_t *, int *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_getguardsize(const pthread_attr_t * __restrict, size_t * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_getinheritsched(const pthread_attr_t * __restrict, int * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_getschedparam(const pthread_attr_t * __restrict,
+ struct sched_param * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_getschedpolicy(const pthread_attr_t * __restrict, int * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_getscope(const pthread_attr_t * __restrict, int * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_getstack(const pthread_attr_t * __restrict, void ** __restrict,
+ size_t * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_getstackaddr(const pthread_attr_t * __restrict, void ** __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_getstacksize(const pthread_attr_t * __restrict, size_t * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_init(pthread_attr_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_setdetachstate(pthread_attr_t *, int);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_setguardsize(pthread_attr_t *, size_t);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_setinheritsched(pthread_attr_t *, int);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_setschedparam(pthread_attr_t * __restrict,
+ const struct sched_param * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_setschedpolicy(pthread_attr_t *, int);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_setscope(pthread_attr_t *, int);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_setstack(pthread_attr_t *, void *, size_t);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_setstackaddr(pthread_attr_t *, void *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_attr_setstacksize(pthread_attr_t *, size_t);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_cancel(pthread_t) __DARWIN_ALIAS(pthread_cancel);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_cond_broadcast(pthread_cond_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_cond_destroy(pthread_cond_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_cond_init(pthread_cond_t * __restrict,
+ const pthread_condattr_t * __restrict) __DARWIN_ALIAS(pthread_cond_init);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_cond_signal(pthread_cond_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_cond_timedwait(pthread_cond_t * __restrict, pthread_mutex_t * __restrict,
+ const struct timespec * __restrict) __DARWIN_ALIAS_C(pthread_cond_timedwait);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_cond_wait(pthread_cond_t * __restrict,
+ pthread_mutex_t * __restrict) __DARWIN_ALIAS_C(pthread_cond_wait);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_condattr_destroy(pthread_condattr_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_condattr_init(pthread_condattr_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_condattr_getpshared(const pthread_condattr_t * __restrict,
+ int * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_condattr_setpshared(pthread_condattr_t *, int);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_create(pthread_t * __restrict, const pthread_attr_t * __restrict,
+ void *(*)(void *), void * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_detach(pthread_t);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_equal(pthread_t, pthread_t);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+void pthread_exit(void *) __dead2;
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_getconcurrency(void);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_getschedparam(pthread_t , int * __restrict,
+ struct sched_param * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+void* pthread_getspecific(pthread_key_t);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_join(pthread_t , void **) __DARWIN_ALIAS_C(pthread_join);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_key_create(pthread_key_t *, void (*)(void *));
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_key_delete(pthread_key_t);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutex_destroy(pthread_mutex_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutex_getprioceiling(const pthread_mutex_t * __restrict,
+ int * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutex_init(pthread_mutex_t * __restrict,
+ const pthread_mutexattr_t * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutex_lock(pthread_mutex_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutex_setprioceiling(pthread_mutex_t * __restrict, int,
+ int * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutex_trylock(pthread_mutex_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutex_unlock(pthread_mutex_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutexattr_destroy(pthread_mutexattr_t *) __DARWIN_ALIAS(pthread_mutexattr_destroy);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t * __restrict,
+ int * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutexattr_getprotocol(const pthread_mutexattr_t * __restrict,
+ int * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutexattr_getpshared(const pthread_mutexattr_t * __restrict,
+ int * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutexattr_gettype(const pthread_mutexattr_t * __restrict,
+ int * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutexattr_init(pthread_mutexattr_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_mutexattr_settype(pthread_mutexattr_t *, int);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_once(pthread_once_t *, void (*)(void));
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_rwlock_destroy(pthread_rwlock_t * ) __DARWIN_ALIAS(pthread_rwlock_destroy);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_rwlock_init(pthread_rwlock_t * __restrict,
+ const pthread_rwlockattr_t * __restrict) __DARWIN_ALIAS(pthread_rwlock_init);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_rwlock_rdlock(pthread_rwlock_t *) __DARWIN_ALIAS(pthread_rwlock_rdlock);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_rwlock_tryrdlock(pthread_rwlock_t *) __DARWIN_ALIAS(pthread_rwlock_tryrdlock);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_rwlock_trywrlock(pthread_rwlock_t *) __DARWIN_ALIAS(pthread_rwlock_trywrlock);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_rwlock_wrlock(pthread_rwlock_t *) __DARWIN_ALIAS(pthread_rwlock_wrlock);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_rwlock_unlock(pthread_rwlock_t *) __DARWIN_ALIAS(pthread_rwlock_unlock);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_rwlockattr_destroy(pthread_rwlockattr_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_rwlockattr_getpshared(const pthread_rwlockattr_t * __restrict,
+ int * __restrict);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_rwlockattr_init(pthread_rwlockattr_t *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *, int);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+pthread_t pthread_self(void);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_setcancelstate(int , int *) __DARWIN_ALIAS(pthread_setcancelstate);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_setcanceltype(int , int *) __DARWIN_ALIAS(pthread_setcanceltype);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_setconcurrency(int);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_setschedparam(pthread_t, int, const struct sched_param *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_setspecific(pthread_key_t , const void *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+void pthread_testcancel(void) __DARWIN_ALIAS(pthread_testcancel);
+
+#if (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || defined(_DARWIN_C_SOURCE)
+
+/* returns non-zero if pthread_create or cthread_fork have been called */
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_is_threaded_np(void);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2)
+int pthread_threadid_np(pthread_t,__uint64_t*);
+
+/*SPI to set and get pthread name*/
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2)
+int pthread_getname_np(pthread_t,char*,size_t);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2)
+int pthread_setname_np(const char*);
+
+/* returns non-zero if the current thread is the main thread */
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_main_np(void);
+
+/* return the mach thread bound to the pthread */
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+mach_port_t pthread_mach_thread_np(pthread_t);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+size_t pthread_get_stacksize_np(pthread_t);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+void* pthread_get_stackaddr_np(pthread_t);
+
+/* Like pthread_cond_signal(), but only wake up the specified pthread */
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_cond_signal_thread_np(pthread_cond_t *, pthread_t);
+
+/* Like pthread_cond_timedwait, but use a relative timeout */
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_cond_timedwait_relative_np(pthread_cond_t *, pthread_mutex_t *,
+ const struct timespec *);
+
+/* Like pthread_create(), but leaves the thread suspended */
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_create_suspended_np(pthread_t *, const pthread_attr_t *,
+ void *(*)(void *), void *);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_kill(pthread_t, int);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_5, __IPHONE_2_0)
+pthread_t pthread_from_mach_thread_np(mach_port_t);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+int pthread_sigmask(int, const sigset_t *, sigset_t *) __DARWIN_ALIAS(pthread_sigmask);
+
+__OSX_AVAILABLE_STARTING(__MAC_10_4, __IPHONE_2_0)
+void pthread_yield_np(void);
+
+#endif /* (!_POSIX_C_SOURCE && !_XOPEN_SOURCE) || _DARWIN_C_SOURCE */
+__END_DECLS
+#endif /* _PTHREAD_H */
--- /dev/null
+/*
+ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#ifndef _PTHREAD_IMPL_H_
+#define _PTHREAD_IMPL_H_
+/*
+ * Internal implementation details
+ */
+
+/* This whole header file will disappear, so don't depend on it... */
+
+#ifndef __POSIX_LIB__
+
+/*
+ * [Internal] data structure signatures
+ */
+#define _PTHREAD_MUTEX_SIG_init 0x32AAABA7
+
+#define _PTHREAD_ERRORCHECK_MUTEX_SIG_init 0x32AAABA1
+#define _PTHREAD_RECURSIVE_MUTEX_SIG_init 0x32AAABA2
+#define _PTHREAD_FIRSTFIT_MUTEX_SIG_init 0x32AAABA3
+
+#define _PTHREAD_COND_SIG_init 0x3CB0B1BB
+#define _PTHREAD_ONCE_SIG_init 0x30B1BCBA
+#define _PTHREAD_RWLOCK_SIG_init 0x2DA8B3B4
+
+/*
+ * POSIX scheduling policies
+ */
+#define SCHED_OTHER 1
+#define SCHED_FIFO 4
+#define SCHED_RR 2
+
+#define __SCHED_PARAM_SIZE__ 4
+
+#endif /* __POSIX_LIB__ */
+
+#endif /* _PTHREAD_IMPL_H_ */
--- /dev/null
+/*
+ * Copyright (c) 2000-2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * MkLinux
+ */
+
+/*
+ * Extension SPIs.
+ */
+
+#ifndef _PTHREAD_SPIS_H
+#define _PTHREAD_SPIS_H
+
+
+#include <pthread/pthread.h>
+
+__BEGIN_DECLS
+
+#if (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || defined(_DARWIN_C_SOURCE)
+/* firstfit */
+#define PTHREAD_FIRSTFIT_MUTEX_INITIALIZER {_PTHREAD_FIRSTFIT_MUTEX_SIG_init, {0}}
+/*
+ * Mutex attributes
+ */
+#define _PTHREAD_MUTEX_POLICY_NONE 0
+#define _PTHREAD_MUTEX_POLICY_FAIRSHARE 1
+#define _PTHREAD_MUTEX_POLICY_FIRSTFIT 2
+
+/* sets the mutex policy attributes */
+__OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_5_0)
+int pthread_mutexattr_setpolicy_np(pthread_mutexattr_t *, int );
+
+#endif /* (!_POSIX_C_SOURCE && !_XOPEN_SOURCE) || _DARWIN_C_SOURCE */
+
+__END_DECLS
+
+#endif /* _PTHREAD_SPIS_H */
--- /dev/null
+/*
+ * Copyright (c) 2013-2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#ifndef _PTHREAD_QOS_H
+#define _PTHREAD_QOS_H
+
+#include <sys/cdefs.h>
+#include <Availability.h>
+
+#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL
+
+#include <sys/qos.h>
+
+#ifndef KERNEL
+
+__BEGIN_DECLS
+
+/*!
+ * @function pthread_attr_set_qos_class_np
+ *
+ * @abstract
+ * Sets the QOS class and relative priority of a pthread attribute structure
+ * which may be used to specify the requested QOS class of newly created
+ * threads.
+ *
+ * @discussion
+ * The QOS class and relative priority represent an overall combination of
+ * system quality of service attributes on a thread.
+ *
+ * Subsequent calls to interfaces such as pthread_attr_setschedparam() that are
+ * incompatible or in conflict with the QOS class system will unset the QOS
+ * class requested with this interface and pthread_attr_get_qos_class_np() will
+ * return QOS_CLASS_UNSPECIFIED.
+ *
+ * @param __attr
+ * The pthread attribute structure to modify.
+ *
+ * @param __qos_class
+ * A QOS class value:
+ * - QOS_CLASS_USER_INTERACTIVE
+ * - QOS_CLASS_USER_INITIATED
+ * - QOS_CLASS_DEFAULT
+ * - QOS_CLASS_UTILITY
+ * - QOS_CLASS_BACKGROUND
+ * EINVAL will be returned if any other value is provided.
+ *
+ * @param __relative_priority
+ * A relative priority within the QOS class. This value is a negative offset
+ * from the maximum supported scheduler priority for the given class.
+ * EINVAL will be returned if the value is greater than zero or less than
+ * QOS_MIN_RELATIVE_PRIORITY.
+ *
+ * @return
+ * Zero if successful, otherwise an errno value.
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+pthread_attr_set_qos_class_np(pthread_attr_t *__attr,
+ qos_class_t __qos_class, int __relative_priority);
+
+/*!
+ * @function pthread_attr_get_qos_class_np
+ *
+ * @abstract
+ * Gets the QOS class and relative priority of a pthread attribute structure.
+ *
+ * @param __attr
+ * The pthread attribute structure to inspect.
+ *
+ * @param __qos_class
+ * On output, a QOS class value:
+ * - QOS_CLASS_USER_INTERACTIVE
+ * - QOS_CLASS_USER_INITIATED
+ * - QOS_CLASS_DEFAULT
+ * - QOS_CLASS_UTILITY
+ * - QOS_CLASS_BACKGROUND
+ * - QOS_CLASS_UNSPECIFIED
+ * This value may be NULL in which case no value is returned.
+ *
+ * @param __relative_priority
+ * On output, a relative priority offset within the QOS class.
+ * This value may be NULL in which case no value is returned.
+ *
+ * @return
+ * Zero if successful, otherwise an errno value.
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+pthread_attr_get_qos_class_np(pthread_attr_t * __restrict __attr,
+ qos_class_t * __restrict __qos_class,
+ int * __restrict __relative_priority);
+
+/*!
+ * @function pthread_set_qos_class_self_np
+ *
+ * @abstract
+ * Sets the requested QOS class and relative priority of the current thread.
+ *
+ * @discussion
+ * The QOS class and relative priority represent an overall combination of
+ * system quality of service attributes on a thread.
+ *
+ * Subsequent calls to interfaces such as pthread_setschedparam() that are
+ * incompatible or in conflict with the QOS class system will unset the QOS
+ * class requested with this interface and pthread_get_qos_class_np() will
+ * return QOS_CLASS_UNSPECIFIED thereafter. A thread so modified is permanently
+ * opted-out of the QOS class system and calls to this function to request a QOS
+ * class for such a thread will fail and return EPERM.
+ *
+ * @param __qos_class
+ * A QOS class value:
+ * - QOS_CLASS_USER_INTERACTIVE
+ * - QOS_CLASS_USER_INITIATED
+ * - QOS_CLASS_DEFAULT
+ * - QOS_CLASS_UTILITY
+ * - QOS_CLASS_BACKGROUND
+ * EINVAL will be returned if any other value is provided.
+ *
+ * @param __relative_priority
+ * A relative priority within the QOS class. This value is a negative offset
+ * from the maximum supported scheduler priority for the given class.
+ * EINVAL will be returned if the value is greater than zero or less than
+ * QOS_MIN_RELATIVE_PRIORITY.
+ *
+ * @return
+ * Zero if successful, otherwise an errno value.
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+pthread_set_qos_class_self_np(qos_class_t __qos_class,
+ int __relative_priority);
+
+/*!
+ * @function pthread_get_qos_class_np
+ *
+ * @abstract
+ * Gets the requested QOS class and relative priority of a thread.
+ *
+ * @param __pthread
+ * The target thread to inspect.
+ *
+ * @param __qos_class
+ * On output, a QOS class value:
+ * - QOS_CLASS_USER_INTERACTIVE
+ * - QOS_CLASS_USER_INITIATED
+ * - QOS_CLASS_DEFAULT
+ * - QOS_CLASS_UTILITY
+ * - QOS_CLASS_BACKGROUND
+ * - QOS_CLASS_UNSPECIFIED
+ * This value may be NULL in which case no value is returned.
+ *
+ * @param __relative_priority
+ * On output, a relative priority offset within the QOS class.
+ * This value may be NULL in which case no value is returned.
+ *
+ * @return
+ * Zero if successful, otherwise an errno value.
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+pthread_get_qos_class_np(pthread_t __pthread,
+ qos_class_t * __restrict __qos_class,
+ int * __restrict __relative_priority);
+
+/*!
+ * @typedef pthread_override_t
+ *
+ * @abstract
+ * An opaque object representing a QOS class override of a thread.
+ *
+ * @discussion
+ * A QOS class override of a target thread expresses that an item of pending
+ * work classified with a specific QOS class and relative priority depends on
+ * the completion of the work currently being executed by the thread (e.g. due
+ * to ordering requirements).
+ *
+ * While overrides are in effect, the target thread will execute at the maximum
+ * QOS class and relative priority of all overrides and of the QOS class
+ * requested by the thread itself.
+ *
+ * A QOS class override does not modify the target thread's requested QOS class
+ * value and the effect of an override is not visible to the qos_class_self()
+ * and pthread_get_qos_class_np() interfaces.
+ */
+
+typedef struct pthread_override_s* pthread_override_t;
+
+/*!
+ * @function pthread_override_qos_class_start_np
+ *
+ * @abstract
+ * Starts a QOS class override of the specified target thread.
+ *
+ * @discussion
+ * Starting a QOS class override of the specified target thread expresses that
+ * an item of pending work classified with the specified QOS class and relative
+ * priority depends on the completion of the work currently being executed by
+ * the thread (e.g. due to ordering requirements).
+ *
+ * While overrides are in effect, the specified target thread will execute at
+ * the maximum QOS class and relative priority of all overrides and of the QOS
+ * class requested by the thread itself.
+ *
+ * Starting a QOS class override does not modify the target thread's requested
+ * QOS class value and the effect of an override is not visible to the
+ * qos_class_self() and pthread_get_qos_class_np() interfaces.
+ *
+ * The returned newly allocated override object is intended to be associated
+ * with the item of pending work in question. Once the dependency has been
+ * satisfied and enabled that work to begin executing, the QOS class override
+ * must be ended by passing the associated override object to
+ * pthread_override_qos_class_end_np(). Failure to do so will result in the
+ * associated resources to be leaked and the target thread to be permanently
+ * executed at an inappropriately elevated QOS class.
+ *
+ * @param __pthread
+ * The target thread to modify.
+ *
+ * @param __qos_class
+ * A QOS class value:
+ * - QOS_CLASS_USER_INTERACTIVE
+ * - QOS_CLASS_USER_INITIATED
+ * - QOS_CLASS_DEFAULT
+ * - QOS_CLASS_UTILITY
+ * - QOS_CLASS_BACKGROUND
+ * NULL will be returned if any other value is provided.
+ *
+ * @param __relative_priority
+ * A relative priority within the QOS class. This value is a negative offset
+ * from the maximum supported scheduler priority for the given class.
+ * NULL will be returned if the value is greater than zero or less than
+ * QOS_MIN_RELATIVE_PRIORITY.
+ *
+ * @return
+ * A newly allocated override object if successful, or NULL if the override
+ * could not be started.
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+pthread_override_t
+pthread_override_qos_class_start_np(pthread_t __pthread,
+ qos_class_t __qos_class, int __relative_priority);
+
+/*!
+ * @function pthread_override_qos_class_end_np
+ *
+ * @abstract
+ * Ends a QOS class override.
+ *
+ * @discussion
+ * Passing an override object returned by pthread_override_qos_class_start_np()
+ * ends the QOS class override started by that call and deallocates all
+ * associated resources as well as the override object itself.
+ *
+ * The thread starting and the thread ending a QOS class override need not be
+ * identical. If the thread ending the override is the the target thread of the
+ * override itself, it should take care to elevate its requested QOS class
+ * appropriately with pthread_set_qos_class_self_np() before ending the
+ * override.
+ *
+ * @param __override
+ * An override object returned by pthread_override_qos_class_start_np().
+ *
+ * @return
+ * Zero if successful, otherwise an errno value.
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+pthread_override_qos_class_end_np(pthread_override_t __override);
+
+__END_DECLS
+
+#endif // KERNEL
+
+#endif // __DARWIN_C_LEVEL >= __DARWIN_C_FULL
+
+#endif // _PTHREAD_QOS_H
--- /dev/null
+/*
+ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#ifndef _SCHED_H_
+#define _SCHED_H_
+
+#include <pthread_impl.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+/*
+ * Scheduling paramters
+ */
+#ifndef __POSIX_LIB__
+struct sched_param { int sched_priority; char __opaque[__SCHED_PARAM_SIZE__]; };
+#endif
+
+extern int sched_yield(void);
+extern int sched_get_priority_min(int);
+extern int sched_get_priority_max(int);
+__END_DECLS
+
+#endif /* _SCHED_H_ */
+
--- /dev/null
+/*
+ * Copyright (c) 2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#ifndef _PTHREAD_SPAWN_H
+#define _PTHREAD_SPAWN_H
+
+/*!
+ * @group posix_spawn QOS class support
+ * Apple extensions to posix_spawn(2) and posix_spawnp(2)
+ */
+
+#include <pthread/pthread.h>
+#include <spawn.h>
+
+__BEGIN_DECLS
+
+/*!
+ * @function posix_spawnattr_set_qos_class_np
+ *
+ * @abstract
+ * Sets the QOS class property of a posix_spawn attributes object, which may be
+ * used to specify the QOS class a process should be spawned with.
+ *
+ * @discussion
+ * The QOS class specified at the time of process spawn determines both the
+ * initial requested QOS class of the main thread in the new process, and the
+ * interpretation by the system of all QOS class values requested by threads in
+ * the process.
+ *
+ * @param __attr
+ * The spawn attributes object to modify.
+ *
+ * @param __qos_class
+ * A QOS class value:
+ * - QOS_CLASS_UTILITY
+ * - QOS_CLASS_BACKGROUND
+ * EINVAL will be returned if any other value is provided.
+ *
+ * @return
+ * Zero if successful, otherwise an errno value.
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+posix_spawnattr_set_qos_class_np(posix_spawnattr_t * __restrict __attr,
+ qos_class_t __qos_class);
+
+/*!
+ * @function posix_spawnattr_get_qos_class_np
+ *
+ * @abstract
+ * Gets the QOS class property of a posix_spawn attributes object.
+ *
+ * @param __attr
+ * The spawn attributes object to inspect.
+ *
+ * @param __qos_class
+ * On output, a QOS class value:
+ * - QOS_CLASS_UTILITY
+ * - QOS_CLASS_BACKGROUND
+ * - QOS_CLASS_UNSPECIFIED
+ *
+ * @return
+ * Zero if successful, otherwise an errno value.
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+int
+posix_spawnattr_get_qos_class_np(const posix_spawnattr_t *__restrict __attr,
+ qos_class_t * __restrict __qos_class);
+
+__END_DECLS
+
+#endif // _PTHREAD_SPAWN_H
--- /dev/null
+/*
+ * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * MkLinux
+ */
+
+/*
+ * POSIX Threads - IEEE 1003.1c
+ */
+
+#ifndef _POSIX_PTHREAD_INTERNALS_H
+#define _POSIX_PTHREAD_INTERNALS_H
+
+#define _PTHREAD_BUILDING_PTHREAD_
+
+// suppress pthread_attr_t typedef in sys/signal.h
+#define _PTHREAD_ATTR_T
+struct _pthread_attr_t; /* forward reference */
+typedef struct _pthread_attr_t pthread_attr_t;
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <TargetConditionals.h>
+#include <libkern/OSAtomic.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <os/once_private.h>
+#include <sys/queue.h>
+
+#ifndef __POSIX_LIB__
+#define __POSIX_LIB__
+#endif
+
+#ifndef PTHREAD_LAYOUT_SPI
+#define PTHREAD_LAYOUT_SPI 1
+#endif
+
+#include "posix_sched.h"
+#include "tsd_private.h"
+#include "spinlock_private.h"
+
+#if TARGET_IPHONE_SIMULATOR
+#error Unsupported target
+#endif
+
+// List of all pthreads in the process.
+TAILQ_HEAD(__pthread_list, _pthread);
+extern struct __pthread_list __pthread_head;
+
+// Lock protects access to above list.
+extern pthread_lock_t _pthread_list_lock;
+
+extern int __is_threaded;
+
+/*
+ * Compiled-in limits
+ */
+#if TARGET_OS_EMBEDDED
+#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 MAXTHREADNAMESIZE 64
+#define _PTHREAD_T
+typedef struct _pthread {
+ //
+ // ABI - These fields are externally known as struct _opaque_pthread_t.
+ //
+ long sig; // _PTHREAD_SIG
+ struct __darwin_pthread_handler_rec *__cleanup_stack;
+
+ //
+ // SPI - These fields are private.
+ //
+ // these fields are globally protected by _pthread_list_lock:
+ uint32_t childrun:1,
+ parentcheck:1,
+ childexit:1,
+ pad3:29;
+
+ pthread_lock_t lock; // protect access to everything below
+ uint32_t detached:8,
+ inherit:8,
+ policy:8,
+ kernalloc:1,
+ schedset:1,
+ wqthread:1,
+ wqkillset:1,
+ pad:4;
+
+#if __LP64__
+ uint32_t pad0;
+#endif
+ uint64_t thread_id; // 64-bit unique thread id
+
+ void *(*fun)(void*); // thread start routine
+ void *arg; // thread start routine argument
+ void *exit_value; // thread exit value storage
+
+ semaphore_t joiner_notify; // pthread_join notification
+
+ int max_tsd_key;
+ int cancel_state; // whether the thread can be cancelled
+ int cancel_error;
+
+#ifdef __i386__
+ // i386 err_no must be at a 68 byte offset
+ // See <rdar://problem/13249323>
+ uint32_t __13249323_pad[3];
+#endif
+ int err_no; // thread-local errno
+
+ struct _pthread *joiner;
+
+ struct sched_param param; // [aligned]
+
+ TAILQ_ENTRY(_pthread) plist; // global thread list [aligned]
+
+ char pthread_name[MAXTHREADNAMESIZE]; // includes NUL [aligned]
+
+ void *stackaddr; // base of the stack (page aligned)
+ size_t stacksize; // size of stack (page multiple and >= PTHREAD_STACK_MIN)
+
+ void* freeaddr; // stack/thread allocation base address
+ size_t freesize; // stack/thread allocation size
+ size_t guardsize; // guard page size in bytes
+
+ // thread specific data
+ void *tsd[_EXTERNAL_POSIX_THREAD_KEYS_MAX + _INTERNAL_POSIX_THREAD_KEYS_MAX];
+} *pthread_t;
+
+
+struct _pthread_attr_t {
+ long sig;
+ pthread_lock_t lock;
+ uint32_t detached:8,
+ inherit:8,
+ policy:8,
+ fastpath:1,
+ schedset:1,
+ qosset:1,
+ unused:5;
+ struct sched_param param; // [aligned]
+ void *stackaddr; // stack base; vm_page_size aligned
+ size_t stacksize; // stack size; multiple of vm_page_size and >= PTHREAD_STACK_MIN
+ size_t guardsize; // size in bytes of stack overflow guard area
+ unsigned long qosclass;
+#if defined(__LP64__)
+ uint32_t _reserved[2];
+#else
+ uint32_t _reserved[1];
+#endif
+};
+
+/*
+ * Mutex attributes
+ */
+#define _PTHREAD_MUTEX_POLICY_NONE 0
+#define _PTHREAD_MUTEX_POLICY_FAIRSHARE 1
+#define _PTHREAD_MUTEX_POLICY_FIRSTFIT 2
+#define _PTHREAD_MUTEX_POLICY_REALTIME 3
+#define _PTHREAD_MUTEX_POLICY_ADAPTIVE 4
+#define _PTHREAD_MUTEX_POLICY_PRIPROTECT 5
+#define _PTHREAD_MUTEX_POLICY_PRIINHERIT 6
+
+#define _PTHREAD_MUTEXATTR_T
+typedef struct {
+ long sig;
+ int prioceiling;
+ uint32_t protocol:2,
+ type:2,
+ pshared:2,
+ policy:3,
+ unused:23;
+} pthread_mutexattr_t;
+
+struct _pthread_mutex_options {
+ uint32_t protocol:2,
+ type:2,
+ pshared:2,
+ policy:3,
+ hold:2,
+ misalign:1,
+ notify:1,
+ mutex:1,
+ unused:2,
+ lock_count:16;
+};
+
+typedef struct {
+ long sig;
+ pthread_lock_t lock;
+ union {
+ uint32_t value;
+ struct _pthread_mutex_options options;
+ } mtxopts;
+ int16_t prioceiling;
+ int16_t priority;
+#if defined(__LP64__)
+ uint32_t _pad;
+#endif
+ uint32_t m_tid[2]; // thread id of thread that has mutex locked, misaligned locks may span to first field of m_seq
+ uint32_t m_seq[3];
+#if defined(__LP64__)
+ uint32_t _reserved;
+#endif
+ void *reserved2[2];
+} _pthread_mutex;
+
+
+#define _PTHREAD_CONDATTR_T
+typedef struct {
+ long sig;
+ uint32_t pshared:2,
+ unsupported:30;
+} pthread_condattr_t;
+
+
+typedef struct {
+ long sig;
+ pthread_lock_t lock;
+ uint32_t unused:29,
+ misalign:1,
+ pshared:2;
+ _pthread_mutex *busy;
+ uint32_t c_seq[3];
+#if defined(__LP64__)
+ uint32_t _reserved[3];
+#endif
+} _pthread_cond;
+
+
+#define _PTHREAD_ONCE_T
+typedef struct {
+ long sig;
+ os_once_t once;
+} pthread_once_t;
+
+
+#define _PTHREAD_RWLOCKATTR_T
+typedef struct {
+ long sig;
+ int pshared;
+#if defined(__LP64__)
+ uint32_t _reserved[3];
+#else
+ uint32_t _reserved[2];
+#endif
+} pthread_rwlockattr_t;
+
+
+typedef struct {
+ long sig;
+ pthread_lock_t lock;
+ uint32_t unused:29,
+ misalign:1,
+ pshared:2;
+ uint32_t rw_flags;
+#if defined(__LP64__)
+ uint32_t _pad;
+#endif
+ volatile uint32_t rw_seq[4];
+ struct _pthread *rw_owner;
+ volatile uint32_t *rw_lcntaddr;
+ volatile uint32_t *rw_seqaddr;
+ volatile uint32_t *rw_ucntaddr;
+#if defined(__LP64__)
+ uint32_t _reserved[31];
+#else
+ uint32_t _reserved[19];
+#endif
+} _pthread_rwlock;
+
+#include "pthread_spis.h"
+
+// Internal references to pthread_self() use TSD slot 0 directly.
+inline static pthread_t __attribute__((__pure__))
+_pthread_self_direct(void)
+{
+ return _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF);
+}
+#define pthread_self() _pthread_self_direct()
+
+inline static pthread_t __attribute__((__pure__))
+_pthread_selfid_direct(void)
+{
+ return (_pthread_self_direct())->thread_id;
+}
+
+#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_NO_SIG 0x00000000
+#define _PTHREAD_MUTEX_ATTR_SIG 0x4D545841 /* 'MTXA' */
+#define _PTHREAD_MUTEX_SIG 0x4D555458 /* 'MUTX' */
+#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_CMP 0x32AAABA0
+#define _PTHREAD_COND_ATTR_SIG 0x434E4441 /* 'CNDA' */
+#define _PTHREAD_COND_SIG 0x434F4E44 /* 'COND' */
+#define _PTHREAD_COND_SIG_init 0x3CB0B1BB /* [almost] ~'COND' */
+#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' */
+
+
+#define _PTHREAD_KERN_COND_SIG 0x12345678 /* */
+#define _PTHREAD_KERN_MUTEX_SIG 0x34567812 /* */
+#define _PTHREAD_KERN_RWLOCK_SIG 0x56781234 /* */
+
+#define _PTHREAD_CREATE_PARENT 4
+#define _PTHREAD_EXITED 8
+// 4597450: begin
+#define _PTHREAD_WASCANCEL 0x10
+// 4597450: end
+
+#if defined(DEBUG)
+#define _PTHREAD_MUTEX_OWNER_SELF pthread_self()
+#else
+#define _PTHREAD_MUTEX_OWNER_SELF (pthread_t)0x12141968
+#endif
+#define _PTHREAD_MUTEX_OWNER_SWITCHING (pthread_t)(~0)
+
+#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 */
+
+extern boolean_t swtch_pri(int);
+
+#define PTHREAD_EXPORT extern __attribute__((visibility("default")))
+#define PTHREAD_EXTERN extern
+#define PTHREAD_NOEXPORT __attribute__((visibility("hidden")))
+#define PTHREAD_NORETURN __attribute__((__noreturn__))
+#define PTHREAD_ALWAYS_INLINE __attribute__((always_inline))
+#define PTHREAD_NOINLINE __attribute__((noinline))
+
+#include "kern/kern_internal.h"
+
+/* Prototypes. */
+
+/* Internal globals. */
+PTHREAD_NOEXPORT extern int __pthread_supported_features;
+
+/* Functions defined in machine-dependent files. */
+PTHREAD_NOEXPORT void _pthread_setup(pthread_t th, void (*f)(pthread_t), void *sp, int suspended, int needresume);
+
+PTHREAD_NOEXPORT void _pthread_tsd_cleanup(pthread_t self);
+
+PTHREAD_NOEXPORT int __mtx_droplock(_pthread_mutex *mutex, uint32_t * flagp, uint32_t ** pmtxp, uint32_t * mgenp, uint32_t * ugenp);
+
+/* internally redirected upcalls. */
+PTHREAD_NOEXPORT void* malloc(size_t);
+PTHREAD_NOEXPORT void free(void*);
+
+/* syscall interfaces */
+extern uint32_t __psynch_mutexwait(pthread_mutex_t * mutex, uint32_t mgen, uint32_t ugen, uint64_t tid, uint32_t flags);
+extern uint32_t __psynch_mutexdrop(pthread_mutex_t * mutex, uint32_t mgen, uint32_t ugen, uint64_t tid, uint32_t flags);
+
+extern uint32_t __psynch_cvbroad(pthread_cond_t * cv, uint64_t cvlsgen, uint64_t cvudgen, uint32_t flags, pthread_mutex_t * mutex, uint64_t mugen, uint64_t tid);
+extern uint32_t __psynch_cvsignal(pthread_cond_t * cv, uint64_t cvlsgen, uint32_t cvugen, int thread_port, pthread_mutex_t * mutex, uint64_t mugen, uint64_t tid, uint32_t flags);
+extern uint32_t __psynch_cvwait(pthread_cond_t * cv, uint64_t cvlsgen, uint32_t cvugen, pthread_mutex_t * mutex, uint64_t mugen, uint32_t flags, int64_t sec, uint32_t nsec);
+extern uint32_t __psynch_cvclrprepost(void * cv, uint32_t cvgen, uint32_t cvugen, uint32_t cvsgen, uint32_t prepocnt, uint32_t preposeq, uint32_t flags);
+extern uint32_t __psynch_rw_longrdlock(pthread_rwlock_t * rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags);
+extern uint32_t __psynch_rw_yieldwrlock(pthread_rwlock_t * rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags);
+extern int __psynch_rw_downgrade(pthread_rwlock_t * rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags);
+extern uint32_t __psynch_rw_upgrade(pthread_rwlock_t * rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags);
+extern uint32_t __psynch_rw_rdlock(pthread_rwlock_t * rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags);
+extern uint32_t __psynch_rw_wrlock(pthread_rwlock_t * rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags);
+extern uint32_t __psynch_rw_unlock(pthread_rwlock_t * rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags);
+extern uint32_t __psynch_rw_unlock2(pthread_rwlock_t * rwlock, uint32_t lgenval, uint32_t ugenval, uint32_t rw_wc, int flags);
+extern uint32_t __bsdthread_ctl(uintptr_t cmd, uintptr_t arg1, uintptr_t arg2, uintptr_t arg3);
+
+PTHREAD_EXTERN
+int
+__proc_info(int callnum, int pid, int flavor, uint64_t arg, void * buffer, int buffersize);
+
+PTHREAD_NOEXPORT int _pthread_lookup_thread(pthread_t thread, mach_port_t * port, int only_joinable);
+PTHREAD_NOEXPORT int _pthread_join_cleanup(pthread_t thread, void ** value_ptr, int conforming);
+
+PTHREAD_NORETURN PTHREAD_NOEXPORT
+void
+__pthread_abort(void);
+
+PTHREAD_NORETURN PTHREAD_NOEXPORT
+void
+__pthread_abort_reason(const char *fmt, ...);
+
+PTHREAD_NOEXPORT
+void
+_pthread_set_main_qos(pthread_priority_t qos);
+
+PTHREAD_EXPORT
+void
+_pthread_start(pthread_t self, mach_port_t kport, void *(*fun)(void *), void * funarg, size_t stacksize, unsigned int flags);
+
+PTHREAD_EXPORT
+void
+_pthread_wqthread(pthread_t self, mach_port_t kport, void *stackaddr, void *unused, int reuse);
+
+PTHREAD_NOEXPORT
+void
+__pthread_fork_child_internal(pthread_t p);
+
+PTHREAD_EXPORT
+void
+_pthread_clear_qos_tsd(mach_port_t thread_port);
+
+PTHREAD_EXPORT
+void
+_pthread_testcancel(pthread_t thread, int isconforming);
+
+PTHREAD_EXPORT
+void
+_pthread_exit_if_canceled(int error);
+
+PTHREAD_ALWAYS_INLINE
+static inline mach_port_t
+_pthread_kernel_thread(pthread_t t)
+{
+ return t->tsd[_PTHREAD_TSD_SLOT_MACH_THREAD_SELF];
+}
+
+PTHREAD_ALWAYS_INLINE
+static inline void
+_pthread_set_kernel_thread(pthread_t t, mach_port_t p)
+{
+ t->tsd[_PTHREAD_TSD_SLOT_MACH_THREAD_SELF] = p;
+}
+
+#define PTHREAD_ABORT(f,...) __pthread_abort_reason("%s:%s:%u: " f, __FILE__, __func__, __LINE__, ## __VA_ARGS__)
+
+#define PTHREAD_ASSERT(b) do { if (!(b)) PTHREAD_ABORT("failed assertion `%s'", #b); } while (0)
+
+#include <os/semaphore_private.h>
+#include <os/alloc_once_private.h>
+
+struct pthread_atfork_entry {
+ void (*prepare)(void);
+ void (*parent)(void);
+ void (*child)(void);
+};
+
+#define PTHREAD_ATFORK_INLINE_MAX 10
+#define PTHREAD_ATFORK_MAX (vm_page_size/sizeof(struct pthread_atfork_entry))
+
+struct pthread_globals_s {
+ // atfork.c
+ pthread_t psaved_self;
+ OSSpinLock psaved_self_global_lock;
+ OSSpinLock pthread_atfork_lock;
+
+ size_t atfork_count;
+ struct pthread_atfork_entry atfork_storage[PTHREAD_ATFORK_INLINE_MAX];
+ struct pthread_atfork_entry *atfork;
+};
+typedef struct pthread_globals_s *pthread_globals_t;
+
+__attribute__((__pure__))
+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 /* _POSIX_PTHREAD_INTERNALS_H */
--- /dev/null
+/*
+ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * MkLinux
+ */
+
+/*
+ * This program will generate the stuff necessary to "publish" the POSIX
+ * header <pthread.h> in a machine dependent fashion.
+ */
+
+#include <pthread_internals.h>
+#include <stdio.h>
+
+int
+main(void)
+{
+ printf("#ifndef _PTHREAD_IMPL_H_\n");
+ printf("#define _PTHREAD_IMPL_H_\n");
+ printf("/*\n");
+ printf(" * Internal implementation details\n");
+ printf(" */\n");
+ printf("\n");
+ printf("#define __PTHREAD_SIZE__ %zd\n", sizeof(struct _pthread)-sizeof(long));
+ printf("#define __PTHREAD_ATTR_SIZE__ %zd\n", sizeof(pthread_attr_t)-sizeof(long));
+ printf("#define __PTHREAD_MUTEXATTR_SIZE__ %zd\n", sizeof(pthread_mutexattr_t)-sizeof(long));
+ printf("#define __PTHREAD_MUTEX_SIZE__ %zd\n", sizeof(pthread_mutex_t)-sizeof(long));
+ printf("#define __PTHREAD_CONDATTR_SIZE__ %zd\n", sizeof(pthread_condattr_t)-sizeof(long));
+ printf("#define __PTHREAD_COND_SIZE__ %zd\n", sizeof(pthread_cond_t)-sizeof(long));
+ printf("#define __PTHREAD_ONCE_SIZE__ %zd\n", sizeof(pthread_once_t)-sizeof(long));
+ printf("#define __PTHREAD_sig_OFFSET__ %zd\n", offsetof(struct _pthread, sig));
+ printf("#define __PTHREAD_cleanup_stack_OFFSET__ %zd\n", offsetof(struct _pthread, __cleanup_stack));
+ printf("#define __PTHREAD_guardsize_OFFSET__ %zd\n", offsetof(struct _pthread, guardsize));
+ printf("#define __PTHREAD_param_OFFSET__ %zd\n", offsetof(struct _pthread, param));
+ printf("#define __PTHREAD_mutexes_OFFSET__ %zd\n", offsetof(struct _pthread, mutexes));
+ printf("#define __PTHREAD_joiner_OFFSET__ %zd\n", offsetof(struct _pthread, joiner));
+ printf("#define __PTHREAD_exit_value_OFFSET__ %zd\n", offsetof(struct _pthread, exit_value));
+ printf("#define __PTHREAD_death_OFFSET__ %zd\n", offsetof(struct _pthread, death));
+ printf("#define __PTHREAD_kernel_thread_OFFSET__ %zd\n", offsetof(struct _pthread, kernel_thread));
+ printf("#define __PTHREAD_fun_OFFSET__ %zd\n", offsetof(struct _pthread, fun));
+ printf("#define __PTHREAD_arg_OFFSET__ %zd\n", offsetof(struct _pthread, arg));
+ printf("#define __PTHREAD_cancel_state_OFFSET__ %zd\n", offsetof(struct _pthread, cancel_state));
+ printf("#define __PTHREAD_err_no_OFFSET__ %zd\n", offsetof(struct _pthread, err_no));
+ printf("#define __PTHREAD_tsd_OFFSET__ %zd\n", offsetof(struct _pthread, tsd));
+ printf("#define __PTHREAD_stackaddr_OFFSET__ %zd\n", offsetof(struct _pthread, stackaddr));
+ printf("#define __PTHREAD_stacksize_OFFSET__ %zd\n", offsetof(struct _pthread, stacksize));
+ printf("#define __PTHREAD_reply_port_OFFSET__ %zd\n", offsetof(struct _pthread, reply_port));
+ printf("#define __PTHREAD_cthread_self_OFFSET__ %zd\n", offsetof(struct _pthread, cthread_self));
+ printf("#define __PTHREAD_freeStackOnExit_OFFSET__ %zd\n", offsetof(struct _pthread, freeStackOnExit));
+ printf("#define __PTHREAD_plist_OFFSET__ %zd\n", offsetof(struct _pthread, plist));
+ printf("/*\n");
+ printf(" * [Internal] data structure signatures\n");
+ printf(" */\n");
+ printf("#define _PTHREAD_MUTEX_SIG_init 0x%08X\n", _PTHREAD_MUTEX_SIG_init);
+ printf("#define _PTHREAD_COND_SIG_init 0x%08X\n", _PTHREAD_COND_SIG_init);
+ printf("#define _PTHREAD_ONCE_SIG_init 0x%08X\n", _PTHREAD_ONCE_SIG_init);
+ printf("/*\n");
+ printf(" * POSIX scheduling policies \n");
+ printf(" */\n");
+ printf("#define SCHED_OTHER %d\n", SCHED_OTHER);
+ printf("#define SCHED_FIFO %d\n", SCHED_FIFO);
+ printf("#define SCHED_RR %d\n", SCHED_RR);
+ printf("\n");
+ printf("#define __SCHED_PARAM_SIZE__ %ld\n", (long) sizeof(struct sched_param)-sizeof(int));
+ printf("\n");
+ printf("#endif _PTHREAD_IMPL_H_\n");
+
+ exit(0);
+}
--- /dev/null
+typedef struct _opaque_pthread_mutex_t pthread_mutex_t;
+typedef struct _opaque_pthread_rwlock_t pthread_rwlock_t;
+
+provider plockstat {
+ probe mutex__acquire(pthread_mutex_t *mutex, int recursive, int spin_count);
+ probe mutex__release(pthread_mutex_t *mutex, int recursive);
+ probe mutex__error(pthread_mutex_t *mutex, int errno);
+ probe mutex__block(pthread_mutex_t *mutex);
+ probe mutex__blocked(pthread_mutex_t *mutex, int successful);
+ probe mutex__spin(pthread_mutex_t *mutex);
+ probe mutex__spun(pthread_mutex_t *mutex, int successful, int spin_count);
+
+ probe rw__acquire(pthread_rwlock_t *rwlock, int write_lock);
+ probe rw__block(pthread_rwlock_t *rwlock, int write_lock);
+ probe rw__blocked(pthread_rwlock_t *rwlock, int write_lock, int successful);
+ probe rw__release(pthread_rwlock_t *rwlock, int write_lock);
+ probe rw__error(pthread_rwlock_t *rwlock, int write_lock, int error);
+};
+
+#pragma D attributes Evolving/Evolving/ISA provider plockstat provider
+#pragma D attributes Private/Private/Unknown provider plockstat module
+#pragma D attributes Private/Private/Unknown provider plockstat function
+#pragma D attributes Evolving/Evolving/ISA provider plockstat name
+#pragma D attributes Evolving/Evolving/ISA provider plockstat args
--- /dev/null
+/*
+ * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * MkLinux
+ */
+
+/*
+ * POSIX Pthread Library
+ */
+
+#include "internal.h"
+#include "private.h"
+#include "workqueue_private.h"
+#include "introspection_private.h"
+#include "qos_private.h"
+
+#include <stdlib.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <mach/mach_init.h>
+#include <mach/mach_vm.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/queue.h>
+#include <sys/mman.h>
+#include <machine/vmparam.h>
+#define __APPLE_API_PRIVATE
+#include <machine/cpu_capabilities.h>
+#include <libkern/OSAtomic.h>
+
+#include <_simple.h>
+#include <platform/string.h>
+#include <platform/compat.h>
+
+extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
+ void *newp, size_t newlen);
+extern void __exit(int) __attribute__((noreturn));
+
+static void (*exitf)(int) = __exit;
+__private_extern__ void* (*_pthread_malloc)(size_t) = NULL;
+__private_extern__ void (*_pthread_free)(void *) = NULL;
+
+//
+// Global variables
+//
+
+// This global should be used (carefully) by anyone needing to know if a
+// pthread (other than the main thread) has been created.
+int __is_threaded = 0;
+
+int __unix_conforming = 0;
+
+// _pthread_list_lock protects _pthread_count, access to the __pthread_head
+// list, and the parentcheck, childrun and childexit flags of the pthread
+// structure. Externally imported by pthread_cancelable.c.
+__private_extern__ pthread_lock_t _pthread_list_lock = LOCK_INITIALIZER;
+__private_extern__ struct __pthread_list __pthread_head = TAILQ_HEAD_INITIALIZER(__pthread_head);
+static int _pthread_count = 1;
+
+#if PTHREAD_LAYOUT_SPI
+
+const struct pthread_layout_offsets_s pthread_layout_offsets = {
+ .plo_version = 1,
+ .plo_pthread_tsd_base_offset = offsetof(struct _pthread, tsd),
+ .plo_pthread_tsd_base_address_offset = 0,
+ .plo_pthread_tsd_entry_size = sizeof(((struct _pthread *)NULL)->tsd[0]),
+};
+
+#endif // PTHREAD_LAYOUT_SPI
+
+//
+// Static variables
+//
+
+// Mach message notification that a thread needs to be recycled.
+typedef struct _pthread_reap_msg_t {
+ mach_msg_header_t header;
+ pthread_t thread;
+ mach_msg_trailer_t trailer;
+} pthread_reap_msg_t;
+
+#define pthreadsize ((size_t)mach_vm_round_page(sizeof(struct _pthread)))
+static pthread_attr_t _pthread_attr_default = {0};
+static struct _pthread _thread = {0};
+
+static int default_priority;
+static int max_priority;
+static int min_priority;
+static int pthread_concurrency;
+
+// work queue support data
+static void (*__libdispatch_workerfunction)(pthread_priority_t) = NULL;
+static int __libdispatch_offset;
+
+// supported feature set
+int __pthread_supported_features;
+
+//
+// Function prototypes
+//
+
+// pthread primitives
+static int _pthread_allocate(pthread_t *thread, const pthread_attr_t *attrs, void **stack);
+static int _pthread_deallocate(pthread_t t);
+
+static void _pthread_terminate(pthread_t t);
+
+static void _pthread_struct_init(pthread_t t,
+ const pthread_attr_t *attrs,
+ void *stack,
+ size_t stacksize,
+ int kernalloc);
+
+extern void _pthread_set_self(pthread_t);
+
+static void _pthread_dealloc_reply_port(pthread_t t);
+
+static inline void __pthread_add_thread(pthread_t t, bool parent);
+static inline int __pthread_remove_thread(pthread_t t, bool child, bool *should_exit);
+
+static int _pthread_find_thread(pthread_t thread);
+
+static void _pthread_exit(pthread_t self, void *value_ptr) __dead2;
+static void _pthread_setcancelstate_exit(pthread_t self, void *value_ptr, int conforming);
+
+static inline void _pthread_introspection_thread_create(pthread_t t, bool destroy);
+static inline void _pthread_introspection_thread_start(pthread_t t);
+static inline void _pthread_introspection_thread_terminate(pthread_t t, void *freeaddr, size_t freesize, bool destroy);
+static inline void _pthread_introspection_thread_destroy(pthread_t t);
+
+extern void start_wqthread(pthread_t self, mach_port_t kport, void *stackaddr, void *unused, int reuse);
+extern void thread_start(pthread_t self, mach_port_t kport, void *(*fun)(void *), void * funarg, size_t stacksize, unsigned int flags);
+
+void pthread_workqueue_atfork_child(void);
+
+static bool __workq_newapi;
+
+/* Compatibility: previous pthread API used WORKQUEUE_OVERCOMMIT to request overcommit threads from
+ * the kernel. This definition is kept here, in userspace only, to perform the compatibility shimm
+ * from old API requests to the new kext conventions.
+ */
+#define WORKQUEUE_OVERCOMMIT 0x10000
+
+/*
+ * Flags filed passed to bsdthread_create and back in pthread_start
+31 <---------------------------------> 0
+_________________________________________
+| flags(8) | policy(8) | importance(16) |
+-----------------------------------------
+*/
+
+#define PTHREAD_START_CUSTOM 0x01000000
+#define PTHREAD_START_SETSCHED 0x02000000
+#define PTHREAD_START_DETACHED 0x04000000
+#define PTHREAD_START_QOSCLASS 0x08000000
+#define PTHREAD_START_QOSCLASS_MASK 0xffffff
+#define PTHREAD_START_POLICY_BITSHIFT 16
+#define PTHREAD_START_POLICY_MASK 0xff
+#define PTHREAD_START_IMPORTANCE_MASK 0xffff
+
+static int pthread_setschedparam_internal(pthread_t, mach_port_t, int, const struct sched_param *);
+extern pthread_t __bsdthread_create(void *(*func)(void *), void * func_arg, void * stack, pthread_t thread, unsigned int flags);
+extern int __bsdthread_register(void (*)(pthread_t, mach_port_t, void *(*)(void *), void *, size_t, unsigned int), void (*)(pthread_t, mach_port_t, void *, void *, int), int,void (*)(pthread_t, mach_port_t, void *(*)(void *), void *, size_t, unsigned int), int32_t *,__uint64_t);
+extern int __bsdthread_terminate(void * freeaddr, size_t freesize, mach_port_t kport, mach_port_t joinsem);
+extern __uint64_t __thread_selfid( void );
+extern int __pthread_canceled(int);
+extern int __pthread_kill(mach_port_t, int);
+
+extern int __workq_open(void);
+extern int __workq_kernreturn(int, void *, int, int);
+
+#if defined(__i386__) || defined(__x86_64__)
+static const mach_vm_address_t PTHREAD_STACK_HINT = 0xB0000000;
+#else
+#error no PTHREAD_STACK_HINT for this architecture
+#endif
+
+#ifdef __i386__
+// Check for regression of <rdar://problem/13249323>
+struct rdar_13249323_regression_static_assert { unsigned a[offsetof(struct _pthread, err_no) == 68 ? 1 : -1]; };
+#endif
+
+// Allocate a thread structure, stack and guard page.
+//
+// The thread structure may optionally be placed in the same allocation as the
+// stack, residing above the top of the stack. This cannot be done if a
+// custom stack address is provided.
+//
+// Similarly the guard page cannot be allocated if a custom stack address is
+// provided.
+//
+// The allocated thread structure is initialized with values that indicate how
+// it should be freed.
+
+static int
+_pthread_allocate(pthread_t *thread, const pthread_attr_t *attrs, void **stack)
+{
+ int res;
+ kern_return_t kr;
+ pthread_t t = NULL;
+ mach_vm_address_t allocaddr = PTHREAD_STACK_HINT;
+ size_t allocsize = 0;
+ size_t guardsize = 0;
+ size_t stacksize = 0;
+
+ PTHREAD_ASSERT(attrs->stacksize >= PTHREAD_STACK_MIN);
+
+ *thread = NULL;
+ *stack = NULL;
+
+ // Allocate a pthread structure if necessary
+
+ if (attrs->stackaddr != NULL) {
+ PTHREAD_ASSERT(((uintptr_t)attrs->stackaddr % vm_page_size) == 0);
+ *stack = attrs->stackaddr;
+ allocsize = pthreadsize;
+ } else {
+ guardsize = attrs->guardsize;
+ stacksize = attrs->stacksize;
+ allocsize = stacksize + guardsize + pthreadsize;
+ }
+
+ kr = mach_vm_map(mach_task_self(),
+ &allocaddr,
+ allocsize,
+ vm_page_size - 1,
+ VM_MAKE_TAG(VM_MEMORY_STACK)| VM_FLAGS_ANYWHERE,
+ MEMORY_OBJECT_NULL,
+ 0,
+ FALSE,
+ VM_PROT_DEFAULT,
+ VM_PROT_ALL,
+ VM_INHERIT_DEFAULT);
+
+ if (kr != KERN_SUCCESS) {
+ kr = mach_vm_allocate(mach_task_self(),
+ &allocaddr,
+ allocsize,
+ VM_MAKE_TAG(VM_MEMORY_STACK)| VM_FLAGS_ANYWHERE);
+ }
+
+ if (kr == KERN_SUCCESS) {
+ // The stack grows down.
+ // Set the guard page at the lowest address of the
+ // newly allocated stack. Return the highest address
+ // of the stack.
+ if (guardsize) {
+ (void)mach_vm_protect(mach_task_self(), allocaddr, guardsize, FALSE, VM_PROT_NONE);
+ }
+
+ // Thread structure resides at the top of the stack.
+ t = (void *)(allocaddr + stacksize + guardsize);
+ if (stacksize) {
+ // Returns the top of the stack.
+ *stack = t;
+ }
+ }
+
+ if (t != NULL) {
+ _pthread_struct_init(t, attrs, *stack, 0, 0);
+ t->freeaddr = (void *)allocaddr;
+ t->freesize = allocsize;
+ *thread = t;
+ res = 0;
+ } else {
+ res = EAGAIN;
+ }
+ return res;
+}
+
+static int
+_pthread_deallocate(pthread_t t)
+{
+ // Don't free the main thread.
+ if (t != &_thread) {
+ (void)mach_vm_deallocate(mach_task_self(), t->freeaddr, t->freesize);
+ }
+ return 0;
+}
+
+// Terminates the thread if called from the currently running thread.
+PTHREAD_NORETURN
+static void
+_pthread_terminate(pthread_t t)
+{
+ PTHREAD_ASSERT(t == pthread_self());
+
+ uintptr_t freeaddr = (uintptr_t)t->freeaddr;
+ size_t freesize = t->freesize - pthreadsize;
+
+ mach_port_t kport = _pthread_kernel_thread(t);
+ semaphore_t joinsem = t->joiner_notify;
+
+ _pthread_dealloc_reply_port(t);
+
+ // Shrink the pthread_t so that it does not include the stack
+ // so that we're always responsible for deallocating the stack.
+ t->freeaddr += freesize;
+ t->freesize = pthreadsize;
+
+ // After the call to __pthread_remove_thread, it is only safe to
+ // dereference the pthread_t structure if EBUSY has been returned.
+
+ bool destroy, should_exit;
+ destroy = (__pthread_remove_thread(t, true, &should_exit) != EBUSY);
+
+ if (t == &_thread) {
+ // Don't free the main thread.
+ freesize = 0;
+ } else if (destroy) {
+ // We were told not to keep the pthread_t structure around, so
+ // instead of just deallocating the stack, we should deallocate
+ // the entire structure.
+ freesize += pthreadsize;
+ }
+ if (freesize == 0) {
+ freeaddr = 0;
+ }
+ _pthread_introspection_thread_terminate(t, freeaddr, freesize, destroy);
+ if (should_exit) {
+ exitf(0);
+ }
+
+ __bsdthread_terminate((void *)freeaddr, freesize, kport, joinsem);
+ PTHREAD_ABORT("thread %p didn't terminate", t);
+}
+
+int
+pthread_attr_destroy(pthread_attr_t *attr)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ attr->sig = 0;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ *detachstate = attr->detached;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ *inheritsched = attr->inherit;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ *param = attr->param;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ *policy = attr->policy;
+ ret = 0;
+ }
+ return ret;
+}
+
+// Default stack size is 512KB; independent of the main thread's stack size.
+static const size_t DEFAULT_STACK_SIZE = 512 * 1024;
+
+int
+pthread_attr_init(pthread_attr_t *attr)
+{
+ attr->stacksize = DEFAULT_STACK_SIZE;
+ attr->stackaddr = NULL;
+ attr->sig = _PTHREAD_ATTR_SIG;
+ attr->param.sched_priority = default_priority;
+ attr->param.quantum = 10; /* quantum isn't public yet */
+ attr->detached = PTHREAD_CREATE_JOINABLE;
+ attr->inherit = _PTHREAD_DEFAULT_INHERITSCHED;
+ attr->policy = _PTHREAD_DEFAULT_POLICY;
+ attr->fastpath = 1;
+ attr->schedset = 0;
+ attr->guardsize = vm_page_size;
+ attr->qosclass = _pthread_priority_make_newest(QOS_CLASS_DEFAULT, 0, 0);
+ return 0;
+}
+
+int
+pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG &&
+ (detachstate == PTHREAD_CREATE_JOINABLE ||
+ detachstate == PTHREAD_CREATE_DETACHED)) {
+ attr->detached = detachstate;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG &&
+ (inheritsched == PTHREAD_INHERIT_SCHED ||
+ inheritsched == PTHREAD_EXPLICIT_SCHED)) {
+ attr->inherit = inheritsched;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ /* TODO: Validate sched_param fields */
+ attr->param = *param;
+ attr->schedset = 1;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG &&
+ (policy == SCHED_OTHER ||
+ policy == SCHED_RR ||
+ policy == SCHED_FIFO)) {
+ attr->policy = policy;
+ attr->schedset = 1;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_setscope(pthread_attr_t *attr, int scope)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ if (scope == PTHREAD_SCOPE_SYSTEM) {
+ // No attribute yet for the scope.
+ ret = 0;
+ } else if (scope == PTHREAD_SCOPE_PROCESS) {
+ ret = ENOTSUP;
+ }
+ }
+ return ret;
+}
+
+int
+pthread_attr_getscope(const pthread_attr_t *attr, int *scope)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ *scope = PTHREAD_SCOPE_SYSTEM;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ *stackaddr = attr->stackaddr;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG &&
+ ((uintptr_t)stackaddr % vm_page_size) == 0) {
+ attr->stackaddr = stackaddr;
+ attr->fastpath = 0;
+ attr->guardsize = 0;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ *stacksize = attr->stacksize;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG &&
+ (stacksize % vm_page_size) == 0 &&
+ stacksize >= PTHREAD_STACK_MIN) {
+ attr->stacksize = stacksize;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t * stacksize)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ *stackaddr = (void *)((uintptr_t)attr->stackaddr - attr->stacksize);
+ *stacksize = attr->stacksize;
+ ret = 0;
+ }
+ return ret;
+}
+
+// Per SUSv3, the stackaddr is the base address, the lowest addressable byte
+// address. This is not the same as in pthread_attr_setstackaddr.
+int
+pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG &&
+ ((uintptr_t)stackaddr % vm_page_size) == 0 &&
+ (stacksize % vm_page_size) == 0 &&
+ stacksize >= PTHREAD_STACK_MIN) {
+ attr->stackaddr = (void *)((uintptr_t)stackaddr + stacksize);
+ attr->stacksize = stacksize;
+ attr->fastpath = 0;
+ ret = 0;
+ }
+ return ret;
+}
+
+int
+pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ /* Guardsize of 0 is valid, ot means no guard */
+ if ((guardsize % vm_page_size) == 0) {
+ attr->guardsize = guardsize;
+ attr->fastpath = 0;
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+int
+pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
+{
+ int ret = EINVAL;
+ if (attr->sig == _PTHREAD_ATTR_SIG) {
+ *guardsize = attr->guardsize;
+ ret = 0;
+ }
+ return ret;
+}
+
+
+/*
+ * Create and start execution of a new thread.
+ */
+
+static void
+_pthread_body(pthread_t self)
+{
+ _pthread_set_self(self);
+ __pthread_add_thread(self, false);
+ _pthread_exit(self, (self->fun)(self->arg));
+}
+
+void
+_pthread_start(pthread_t self, mach_port_t kport, void *(*fun)(void *), void *arg, size_t stacksize, unsigned int pflags)
+{
+ if ((pflags & PTHREAD_START_CUSTOM) == 0) {
+ void *stackaddr = self;
+ _pthread_struct_init(self, &_pthread_attr_default, stackaddr, stacksize, 1);
+
+ if (pflags & PTHREAD_START_SETSCHED) {
+ self->policy = ((pflags >> PTHREAD_START_POLICY_BITSHIFT) & PTHREAD_START_POLICY_MASK);
+ self->param.sched_priority = (pflags & PTHREAD_START_IMPORTANCE_MASK);
+ }
+
+ if ((pflags & PTHREAD_START_DETACHED) == PTHREAD_START_DETACHED) {
+ self->detached &= ~PTHREAD_CREATE_JOINABLE;
+ self->detached |= PTHREAD_CREATE_DETACHED;
+ }
+ }
+
+ if ((pflags & PTHREAD_START_QOSCLASS) != 0) {
+ /* The QoS class is cached in the TSD of the pthread, so to reflect the
+ * class that the kernel brought us up at, the TSD must be primed from the
+ * flags parameter.
+ */
+ self->tsd[_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS] = (pflags & PTHREAD_START_QOSCLASS_MASK);
+ } else {
+ /* Give the thread a default QoS tier, of zero. */
+ self->tsd[_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS] = _pthread_priority_make_newest(QOS_CLASS_UNSPECIFIED, 0, 0);
+ }
+
+ _pthread_set_kernel_thread(self, kport);
+ self->fun = fun;
+ self->arg = arg;
+
+ _pthread_body(self);
+}
+
+static void
+_pthread_struct_init(pthread_t t,
+ const pthread_attr_t *attrs,
+ void *stack,
+ size_t stacksize,
+ int kernalloc)
+{
+ t->sig = _PTHREAD_SIG;
+ t->tsd[_PTHREAD_TSD_SLOT_PTHREAD_SELF] = t;
+ t->tsd[_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS] = _pthread_priority_make_newest(QOS_CLASS_UNSPECIFIED, 0, 0);
+ LOCK_INIT(t->lock);
+ t->kernalloc = kernalloc;
+ if (kernalloc != 0) {
+ uintptr_t stackaddr = (uintptr_t)t;
+ t->stacksize = stacksize;
+ t->stackaddr = (void *)stackaddr;
+ t->freeaddr = (void *)(uintptr_t)(stackaddr - stacksize - vm_page_size);
+ t->freesize = pthreadsize + stacksize + vm_page_size;
+ } else {
+ t->stacksize = attrs->stacksize;
+ t->stackaddr = (void *)stack;
+ }
+ t->guardsize = attrs->guardsize;
+ t->detached = attrs->detached;
+ t->inherit = attrs->inherit;
+ t->policy = attrs->policy;
+ t->schedset = attrs->schedset;
+ t->param = attrs->param;
+ t->cancel_state = PTHREAD_CANCEL_ENABLE | PTHREAD_CANCEL_DEFERRED;
+}
+
+/* Need to deprecate this in future */
+int
+_pthread_is_threaded(void)
+{
+ return __is_threaded;
+}
+
+/* Non portable public api to know whether this process has(had) atleast one thread
+ * apart from main thread. There could be race if there is a thread in the process of
+ * creation at the time of call . It does not tell whether there are more than one thread
+ * at this point of time.
+ */
+int
+pthread_is_threaded_np(void)
+{
+ return __is_threaded;
+}
+
+mach_port_t
+pthread_mach_thread_np(pthread_t t)
+{
+ mach_port_t kport = MACH_PORT_NULL;
+
+ if (t == pthread_self()) {
+ /*
+ * If the call is on self, return the kernel port. We cannot
+ * add this bypass for main thread as it might have exited,
+ * and we should not return stale port info.
+ */
+ kport = _pthread_kernel_thread(t);
+ } else {
+ (void)_pthread_lookup_thread(t, &kport, 0);
+ }
+
+ return kport;
+}
+
+pthread_t
+pthread_from_mach_thread_np(mach_port_t kernel_thread)
+{
+ struct _pthread *p = NULL;
+
+ /* No need to wait as mach port is already known */
+ LOCK(_pthread_list_lock);
+
+ TAILQ_FOREACH(p, &__pthread_head, plist) {
+ if (_pthread_kernel_thread(p) == kernel_thread) {
+ break;
+ }
+ }
+
+ UNLOCK(_pthread_list_lock);
+
+ return p;
+}
+
+size_t
+pthread_get_stacksize_np(pthread_t t)
+{
+ int ret;
+ size_t size = 0;
+
+ if (t == NULL) {
+ return ESRCH; // XXX bug?
+ }
+
+ // since the main thread will not get de-allocated from underneath us
+ if (t == pthread_self() || t == &_thread) {
+ return t->stacksize;
+ }
+
+ LOCK(_pthread_list_lock);
+
+ ret = _pthread_find_thread(t);
+ if (ret == 0) {
+ size = t->stacksize;
+ } else {
+ size = ret; // XXX bug?
+ }
+
+ UNLOCK(_pthread_list_lock);
+
+ return size;
+}
+
+void *
+pthread_get_stackaddr_np(pthread_t t)
+{
+ int ret;
+ void *addr = NULL;
+
+ if (t == NULL) {
+ return (void *)(uintptr_t)ESRCH; // XXX bug?
+ }
+
+ // since the main thread will not get de-allocated from underneath us
+ if (t == pthread_self() || t == &_thread) {
+ return t->stackaddr;
+ }
+
+ LOCK(_pthread_list_lock);
+
+ ret = _pthread_find_thread(t);
+ if (ret == 0) {
+ addr = t->stackaddr;
+ } else {
+ addr = (void *)(uintptr_t)ret; // XXX bug?
+ }
+
+ UNLOCK(_pthread_list_lock);
+
+ return addr;
+}
+
+static mach_port_t
+_pthread_reply_port(pthread_t t)
+{
+ void *p;
+ if (t == NULL) {
+ p = _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_MIG_REPLY);
+ } else {
+ p = t->tsd[_PTHREAD_TSD_SLOT_MIG_REPLY];
+ }
+ return (mach_port_t)(uintptr_t)p;
+}
+
+static void
+_pthread_set_reply_port(pthread_t t, mach_port_t reply_port)
+{
+ void *p = (void *)(uintptr_t)reply_port;
+ if (t == NULL) {
+ _pthread_setspecific_direct(_PTHREAD_TSD_SLOT_MIG_REPLY, p);
+ } else {
+ t->tsd[_PTHREAD_TSD_SLOT_MIG_REPLY] = p;
+ }
+}
+
+static void
+_pthread_dealloc_reply_port(pthread_t t)
+{
+ mach_port_t reply_port = _pthread_reply_port(t);
+ if (reply_port != MACH_PORT_NULL) {
+ mig_dealloc_reply_port(reply_port);
+ }
+}
+
+pthread_t
+pthread_main_thread_np(void)
+{
+ return &_thread;
+}
+
+/* returns non-zero if the current thread is the main thread */
+int
+pthread_main_np(void)
+{
+ pthread_t self = pthread_self();
+
+ return ((self->detached & _PTHREAD_CREATE_PARENT) == _PTHREAD_CREATE_PARENT);
+}
+
+
+/* if we are passed in a pthread_t that is NULL, then we return
+ the current thread's thread_id. So folks don't have to call
+ pthread_self, in addition to us doing it, if they just want
+ their thread_id.
+*/
+int
+pthread_threadid_np(pthread_t thread, uint64_t *thread_id)
+{
+ int res = 0;
+ pthread_t self = pthread_self();
+
+ if (thread_id == NULL) {
+ return EINVAL;
+ }
+
+ if (thread == NULL || thread == self) {
+ *thread_id = self->thread_id;
+ } else {
+ LOCK(_pthread_list_lock);
+ res = _pthread_find_thread(thread);
+ if (res == 0) {
+ *thread_id = thread->thread_id;
+ }
+ UNLOCK(_pthread_list_lock);
+ }
+ return res;
+}
+
+int
+pthread_getname_np(pthread_t thread, char *threadname, size_t len)
+{
+ int res;
+
+ if (thread == NULL) {
+ return ESRCH;
+ }
+
+ LOCK(_pthread_list_lock);
+ res = _pthread_find_thread(thread);
+ if (res == 0) {
+ strlcpy(threadname, thread->pthread_name, len);
+ }
+ UNLOCK(_pthread_list_lock);
+ return res;
+}
+
+int
+pthread_setname_np(const char *name)
+{
+ int res;
+ pthread_t self = pthread_self();
+
+ size_t len = 0;
+ if (name != NULL) {
+ len = strlen(name);
+ }
+
+ /* protytype is in pthread_internals.h */
+ res = __proc_info(5, getpid(), 2, (uint64_t)0, (void*)name, (int)len);
+ if (res == 0) {
+ if (len > 0) {
+ strlcpy(self->pthread_name, name, MAXTHREADNAMESIZE);
+ } else {
+ bzero(self->pthread_name, MAXTHREADNAMESIZE);
+ }
+ }
+ return res;
+
+}
+
+PTHREAD_ALWAYS_INLINE
+static inline void
+__pthread_add_thread(pthread_t t, bool parent)
+{
+ bool should_deallocate = false;
+ bool should_add = true;
+
+ LOCK(_pthread_list_lock);
+
+ // The parent and child threads race to add the thread to the list.
+ // When called by the parent:
+ // - set parentcheck to true
+ // - back off if childrun is true
+ // When called by the child:
+ // - set childrun to true
+ // - back off if parentcheck is true
+ if (parent) {
+ t->parentcheck = 1;
+ if (t->childrun) {
+ // child got here first, don't add.
+ should_add = false;
+ }
+
+ // If the child exits before we check in then it has to keep
+ // the thread structure memory alive so our dereferences above
+ // are valid. If it's a detached thread, then no joiner will
+ // deallocate the thread structure itself. So we do it here.
+ if (t->childexit) {
+ should_add = false;
+ should_deallocate = ((t->detached & PTHREAD_CREATE_DETACHED) == PTHREAD_CREATE_DETACHED);
+ }
+ } else {
+ t->childrun = 1;
+ if (t->parentcheck) {
+ // Parent got here first, don't add.
+ should_add = false;
+ }
+ if (t->wqthread) {
+ // Work queue threads have no parent. Simulate.
+ t->parentcheck = 1;
+ }
+ }
+
+ if (should_add) {
+ TAILQ_INSERT_TAIL(&__pthread_head, t, plist);
+ _pthread_count++;
+ }
+
+ UNLOCK(_pthread_list_lock);
+
+ if (parent) {
+ _pthread_introspection_thread_create(t, should_deallocate);
+ if (should_deallocate) {
+ _pthread_deallocate(t);
+ }
+ } else {
+ _pthread_introspection_thread_start(t);
+ }
+}
+
+// <rdar://problem/12544957> must always inline this function to avoid epilogues
+// Returns EBUSY if the thread structure should be kept alive (is joinable).
+// Returns ESRCH if the thread structure is no longer valid (was detached).
+PTHREAD_ALWAYS_INLINE
+static inline int
+__pthread_remove_thread(pthread_t t, bool child, bool *should_exit)
+{
+ int ret = 0;
+
+ bool should_remove = true;
+
+ LOCK(_pthread_list_lock);
+
+ // When a thread removes itself:
+ // - Set the childexit flag indicating that the thread has exited.
+ // - Return false if parentcheck is zero (must keep structure)
+ // - If the thread is joinable, keep it on the list so that
+ // the join operation succeeds. Still decrement the running
+ // thread count so that we exit if no threads are running.
+ // - Update the running thread count.
+ // When another thread removes a joinable thread:
+ // - CAREFUL not to dereference the thread before verifying that the
+ // reference is still valid using _pthread_find_thread().
+ // - Remove the thread from the list.
+
+ if (child) {
+ t->childexit = 1;
+ if (t->parentcheck == 0) {
+ ret = EBUSY;
+ }
+ if ((t->detached & PTHREAD_CREATE_JOINABLE) != 0) {
+ ret = EBUSY;
+ should_remove = false;
+ }
+ *should_exit = (--_pthread_count <= 0);
+ } else {
+ ret = _pthread_find_thread(t);
+ if (ret == 0) {
+ // If we found a thread but it's not joinable, bail.
+ if ((t->detached & PTHREAD_CREATE_JOINABLE) == 0) {
+ should_remove = false;
+ ret = ESRCH;
+ }
+ }
+ }
+ if (should_remove) {
+ TAILQ_REMOVE(&__pthread_head, t, plist);
+ }
+
+ UNLOCK(_pthread_list_lock);
+
+ return ret;
+}
+
+int
+pthread_create(pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*start_routine)(void *),
+ void *arg)
+{
+ pthread_t t = NULL;
+ unsigned int flags = 0;
+
+ pthread_attr_t *attrs = (pthread_attr_t *)attr;
+ if (attrs == NULL) {
+ attrs = &_pthread_attr_default;
+ } else if (attrs->sig != _PTHREAD_ATTR_SIG) {
+ return EINVAL;
+ }
+
+ if (attrs->detached == PTHREAD_CREATE_DETACHED) {
+ flags |= PTHREAD_START_DETACHED;
+ }
+
+ if (attrs->schedset != 0) {
+ flags |= PTHREAD_START_SETSCHED;
+ flags |= ((attrs->policy & PTHREAD_START_POLICY_MASK) << PTHREAD_START_POLICY_BITSHIFT);
+ flags |= (attrs->param.sched_priority & PTHREAD_START_IMPORTANCE_MASK);
+ } else if (attrs->qosclass != 0) {
+ flags |= PTHREAD_START_QOSCLASS;
+ flags |= (attrs->qosclass & PTHREAD_START_QOSCLASS_MASK);
+ }
+
+ __is_threaded = 1;
+
+ void *stack;
+
+ if (attrs->fastpath) {
+ // kernel will allocate thread and stack, pass stacksize.
+ stack = (void *)attrs->stacksize;
+ } else {
+ // allocate the thread and its stack
+ flags |= PTHREAD_START_CUSTOM;
+
+ int res;
+ res = _pthread_allocate(&t, attrs, &stack);
+ if (res) {
+ return res;
+ }
+
+ t->arg = arg;
+ t->fun = start_routine;
+ }
+
+ pthread_t t2;
+ t2 = __bsdthread_create(start_routine, arg, stack, t, flags);
+ if (t2 == (pthread_t)-1) {
+ if (flags & PTHREAD_START_CUSTOM) {
+ // free the thread and stack if we allocated it
+ _pthread_deallocate(t);
+ }
+ return EAGAIN;
+ }
+ if (t == NULL) {
+ t = t2;
+ }
+
+ __pthread_add_thread(t, true);
+
+ // XXX if a thread is created detached and exits, t will be invalid
+ *thread = t;
+ return 0;
+}
+
+int
+pthread_create_suspended_np(pthread_t *thread,
+ const pthread_attr_t *attr,
+ void *(*start_routine)(void *),
+ void *arg)
+{
+ int res;
+ void *stack;
+ mach_port_t kernel_thread = MACH_PORT_NULL;
+
+ const pthread_attr_t *attrs = attr;
+ if (attrs == NULL) {
+ attrs = &_pthread_attr_default;
+ } else if (attrs->sig != _PTHREAD_ATTR_SIG) {
+ return EINVAL;
+ }
+
+ pthread_t t;
+ res = _pthread_allocate(&t, attrs, &stack);
+ if (res) {
+ return res;
+ }
+
+ *thread = t;
+
+ kern_return_t kr;
+ kr = thread_create(mach_task_self(), &kernel_thread);
+ if (kr != KERN_SUCCESS) {
+ //PTHREAD_ABORT("thread_create() failed: %d", kern_res);
+ return EINVAL; /* Need better error here? */
+ }
+
+ _pthread_set_kernel_thread(t, kernel_thread);
+ (void)pthread_setschedparam_internal(t, kernel_thread, t->policy, &t->param);
+
+ __is_threaded = 1;
+
+ t->arg = arg;
+ t->fun = start_routine;
+
+ __pthread_add_thread(t, true);
+
+ // Set up a suspended thread.
+ _pthread_setup(t, _pthread_body, stack, 1, 0);
+ return res;
+}
+
+int
+pthread_detach(pthread_t thread)
+{
+ int res;
+ bool join = false;
+ semaphore_t sema = SEMAPHORE_NULL;
+
+ res = _pthread_lookup_thread(thread, NULL, 1);
+ if (res) {
+ return res; // Not a valid thread to detach.
+ }
+
+ LOCK(thread->lock);
+ if (thread->detached & PTHREAD_CREATE_JOINABLE) {
+ if (thread->detached & _PTHREAD_EXITED) {
+ // Join the thread if it's already exited.
+ join = true;
+ } else {
+ thread->detached &= ~PTHREAD_CREATE_JOINABLE;
+ thread->detached |= PTHREAD_CREATE_DETACHED;
+ sema = thread->joiner_notify;
+ }
+ } else {
+ res = EINVAL;
+ }
+ UNLOCK(thread->lock);
+
+ if (join) {
+ pthread_join(thread, NULL);
+ } else if (sema) {
+ semaphore_signal(sema);
+ }
+
+ return res;
+}
+
+int
+pthread_kill(pthread_t th, int sig)
+{
+ if (sig < 0 || sig > NSIG) {
+ return EINVAL;
+ }
+
+ mach_port_t kport = MACH_PORT_NULL;
+ if (_pthread_lookup_thread(th, &kport, 0) != 0) {
+ return ESRCH; // Not a valid thread.
+ }
+
+ // Don't signal workqueue threads.
+ if (th->wqthread != 0 && th->wqkillset == 0) {
+ return ENOTSUP;
+ }
+
+ int ret = __pthread_kill(kport, sig);
+
+ if (ret == -1) {
+ ret = errno;
+ }
+ return ret;
+}
+
+int
+__pthread_workqueue_setkill(int enable)
+{
+ pthread_t self = pthread_self();
+
+ LOCK(self->lock);
+ self->wqkillset = enable ? 1 : 0;
+ UNLOCK(self->lock);
+
+ return 0;
+}
+
+static void *
+__pthread_get_exit_value(pthread_t t, int conforming)
+{
+ const int flags = (PTHREAD_CANCEL_ENABLE|_PTHREAD_CANCEL_PENDING);
+ void *value = t->exit_value;
+ if (conforming) {
+ if ((t->cancel_state & flags) == flags) {
+ value = PTHREAD_CANCELED;
+ }
+ }
+ return value;
+}
+
+/* For compatibility... */
+
+pthread_t
+_pthread_self(void) {
+ return pthread_self();
+}
+
+/*
+ * Terminate a thread.
+ */
+int __disable_threadsignal(int);
+
+PTHREAD_NORETURN
+static void
+_pthread_exit(pthread_t self, void *value_ptr)
+{
+ struct __darwin_pthread_handler_rec *handler;
+
+ // Disable signal delivery while we clean up
+ __disable_threadsignal(1);
+
+ // Set cancel state to disable and type to deferred
+ _pthread_setcancelstate_exit(self, value_ptr, __unix_conforming);
+
+ while ((handler = self->__cleanup_stack) != 0) {
+ (handler->__routine)(handler->__arg);
+ self->__cleanup_stack = handler->__next;
+ }
+ _pthread_tsd_cleanup(self);
+
+ LOCK(self->lock);
+ self->detached |= _PTHREAD_EXITED;
+ self->exit_value = value_ptr;
+
+ if ((self->detached & PTHREAD_CREATE_JOINABLE) &&
+ self->joiner_notify == SEMAPHORE_NULL) {
+ self->joiner_notify = (semaphore_t)os_get_cached_semaphore();
+ }
+ UNLOCK(self->lock);
+
+ // Clear per-thread semaphore cache
+ os_put_cached_semaphore(SEMAPHORE_NULL);
+
+ _pthread_terminate(self);
+}
+
+void
+pthread_exit(void *value_ptr)
+{
+ pthread_t self = pthread_self();
+ if (self->wqthread == 0) {
+ _pthread_exit(self, value_ptr);
+ } else {
+ PTHREAD_ABORT("pthread_exit() may only be called against threads created via pthread_create()");
+ }
+}
+
+int
+pthread_getschedparam(pthread_t thread,
+ int *policy,
+ struct sched_param *param)
+{
+ int ret;
+
+ if (thread == NULL) {
+ return ESRCH;
+ }
+
+ LOCK(_pthread_list_lock);
+
+ ret = _pthread_find_thread(thread);
+ if (ret == 0) {
+ if (policy) {
+ *policy = thread->policy;
+ }
+ if (param) {
+ *param = thread->param;
+ }
+ }
+
+ UNLOCK(_pthread_list_lock);
+
+ return ret;
+}
+
+static int
+pthread_setschedparam_internal(pthread_t thread,
+ mach_port_t kport,
+ int policy,
+ const struct sched_param *param)
+{
+ policy_base_data_t bases;
+ policy_base_t base;
+ mach_msg_type_number_t count;
+ kern_return_t ret;
+
+ switch (policy) {
+ case SCHED_OTHER:
+ bases.ts.base_priority = param->sched_priority;
+ base = (policy_base_t)&bases.ts;
+ count = POLICY_TIMESHARE_BASE_COUNT;
+ break;
+ case SCHED_FIFO:
+ bases.fifo.base_priority = param->sched_priority;
+ base = (policy_base_t)&bases.fifo;
+ count = POLICY_FIFO_BASE_COUNT;
+ break;
+ case SCHED_RR:
+ bases.rr.base_priority = param->sched_priority;
+ /* quantum isn't public yet */
+ bases.rr.quantum = param->quantum;
+ base = (policy_base_t)&bases.rr;
+ count = POLICY_RR_BASE_COUNT;
+ break;
+ default:
+ return EINVAL;
+ }
+ ret = thread_policy(kport, policy, base, count, TRUE);
+ return (ret != KERN_SUCCESS) ? EINVAL : 0;
+}
+
+int
+pthread_setschedparam(pthread_t t, int policy, const struct sched_param *param)
+{
+ mach_port_t kport = MACH_PORT_NULL;
+ int res;
+ int bypass = 1;
+
+ // since the main thread will not get de-allocated from underneath us
+ if (t == pthread_self() || t == &_thread ) {
+ kport = _pthread_kernel_thread(t);
+ } else {
+ bypass = 0;
+ (void)_pthread_lookup_thread(t, &kport, 0);
+ }
+
+ res = pthread_setschedparam_internal(t, kport, policy, param);
+ if (res == 0) {
+ if (bypass == 0) {
+ // Ensure the thread is still valid.
+ LOCK(_pthread_list_lock);
+ res = _pthread_find_thread(t);
+ if (res == 0) {
+ t->policy = policy;
+ t->param = *param;
+ }
+ UNLOCK(_pthread_list_lock);
+ } else {
+ t->policy = policy;
+ t->param = *param;
+ }
+ }
+ return res;
+}
+
+int
+sched_get_priority_min(int policy)
+{
+ return default_priority - 16;
+}
+
+int
+sched_get_priority_max(int policy)
+{
+ return default_priority + 16;
+}
+
+int
+pthread_equal(pthread_t t1, pthread_t t2)
+{
+ return (t1 == t2);
+}
+
+// Force LLVM not to optimise this to a call to __pthread_set_self, if it does
+// then _pthread_set_self won't be bound when secondary threads try and start up.
+PTHREAD_NOINLINE
+void
+_pthread_set_self(pthread_t p)
+{
+ extern void __pthread_set_self(void *);
+
+ if (p == NULL) {
+ p = &_thread;
+ }
+
+ uint64_t tid = __thread_selfid();
+ if (tid == -1ull) {
+ PTHREAD_ABORT("failed to set thread_id");
+ }
+
+ p->tsd[_PTHREAD_TSD_SLOT_PTHREAD_SELF] = p;
+ p->tsd[_PTHREAD_TSD_SLOT_ERRNO] = &p->err_no;
+ p->thread_id = tid;
+ __pthread_set_self(&p->tsd[0]);
+}
+
+struct _pthread_once_context {
+ pthread_once_t *pthread_once;
+ void (*routine)(void);
+};
+
+static void
+__pthread_once_handler(void *context)
+{
+ struct _pthread_once_context *ctx = context;
+ pthread_cleanup_push((void*)__os_once_reset, &ctx->pthread_once->once);
+ ctx->routine();
+ pthread_cleanup_pop(0);
+ ctx->pthread_once->sig = _PTHREAD_ONCE_SIG;
+}
+
+int
+pthread_once(pthread_once_t *once_control, void (*init_routine)(void))
+{
+ struct _pthread_once_context ctx = { once_control, init_routine };
+ do {
+ os_once(&once_control->once, &ctx, __pthread_once_handler);
+ } while (once_control->sig == _PTHREAD_ONCE_SIG_init);
+ return 0;
+}
+
+void
+_pthread_testcancel(pthread_t thread, int isconforming)
+{
+ const int flags = (PTHREAD_CANCEL_ENABLE|_PTHREAD_CANCEL_PENDING);
+
+ LOCK(thread->lock);
+ bool canceled = ((thread->cancel_state & flags) == flags);
+ UNLOCK(thread->lock);
+
+ if (canceled) {
+ pthread_exit(isconforming ? PTHREAD_CANCELED : 0);
+ }
+}
+
+void
+_pthread_exit_if_canceled(int error)
+{
+ if (__unix_conforming && ((error & 0xff) == EINTR) && (__pthread_canceled(0) == 0)) {
+ pthread_t self = pthread_self();
+ if (self != NULL) {
+ self->cancel_error = error;
+ }
+ pthread_exit(PTHREAD_CANCELED);
+ }
+}
+
+int
+pthread_getconcurrency(void)
+{
+ return pthread_concurrency;
+}
+
+int
+pthread_setconcurrency(int new_level)
+{
+ if (new_level < 0) {
+ return EINVAL;
+ }
+ pthread_concurrency = new_level;
+ return 0;
+}
+
+void
+_pthread_set_pfz(uintptr_t address)
+{
+}
+
+#if !defined(PTHREAD_TARGET_EOS) && !defined(VARIANT_DYLD)
+void *
+malloc(size_t sz)
+{
+ if (_pthread_malloc) {
+ return _pthread_malloc(sz);
+ } else {
+ return NULL;
+ }
+}
+
+void
+free(void *p)
+{
+ if (_pthread_free) {
+ _pthread_free(p);
+ }
+}
+#endif
+
+/*
+ * Perform package initialization - called automatically when application starts
+ */
+struct ProgramVars; /* forward reference */
+
+int
+__pthread_init(const struct _libpthread_functions *pthread_funcs, const char *envp[] __unused,
+ const char *apple[] __unused, const struct ProgramVars *vars __unused)
+{
+ // Save our provided pushed-down functions
+ if (pthread_funcs) {
+ exitf = pthread_funcs->exit;
+
+ if (pthread_funcs->version >= 2) {
+ _pthread_malloc = pthread_funcs->malloc;
+ _pthread_free = pthread_funcs->free;
+ }
+ }
+
+ //
+ // Get host information
+ //
+
+ kern_return_t kr;
+ host_flavor_t flavor = HOST_PRIORITY_INFO;
+ mach_msg_type_number_t count = HOST_PRIORITY_INFO_COUNT;
+ host_priority_info_data_t priority_info;
+ host_t host = mach_host_self();
+ kr = host_info(host, flavor, (host_info_t)&priority_info, &count);
+ if (kr != KERN_SUCCESS) {
+ PTHREAD_ABORT("host_info(mach_host_self(), ...) failed: %s", mach_error_string(kr));
+ } else {
+ default_priority = priority_info.user_priority;
+ min_priority = priority_info.minimum_priority;
+ max_priority = priority_info.maximum_priority;
+ }
+ mach_port_deallocate(mach_task_self(), host);
+
+ //
+ // Set up the main thread structure
+ //
+
+ void *stackaddr;
+ size_t stacksize = DFLSSIZ;
+ size_t len = sizeof(stackaddr);
+ int mib[] = { CTL_KERN, KERN_USRSTACK };
+ if (__sysctl(mib, 2, &stackaddr, &len, NULL, 0) != 0) {
+ stackaddr = (void *)USRSTACK;
+ }
+
+ pthread_t thread = &_thread;
+ pthread_attr_init(&_pthread_attr_default);
+ _pthread_struct_init(thread, &_pthread_attr_default, stackaddr, stacksize, 0);
+ thread->detached = PTHREAD_CREATE_JOINABLE;
+
+ // Finish initialization with common code that is reinvoked on the
+ // child side of a fork.
+
+ // Finishes initialization of main thread attributes.
+ // Initializes the thread list and add the main thread.
+ // Calls _pthread_set_self() to prepare the main thread for execution.
+ __pthread_fork_child_internal(thread);
+
+ // Set up kernel entry points with __bsdthread_register.
+ pthread_workqueue_atfork_child();
+
+ return 0;
+}
+
+int
+sched_yield(void)
+{
+ swtch_pri(0);
+ return 0;
+}
+
+PTHREAD_NOEXPORT void
+__pthread_fork_child_internal(pthread_t p)
+{
+ TAILQ_INIT(&__pthread_head);
+ LOCK_INIT(_pthread_list_lock);
+
+ // Re-use the main thread's static storage if no thread was provided.
+ if (p == NULL) {
+ if (_thread.tsd[0] != 0) {
+ bzero(&_thread, sizeof(struct _pthread));
+ }
+ p = &_thread;
+ }
+
+ LOCK_INIT(p->lock);
+ _pthread_set_kernel_thread(p, mach_thread_self());
+ _pthread_set_reply_port(p, mach_reply_port());
+ p->__cleanup_stack = NULL;
+ p->joiner_notify = SEMAPHORE_NULL;
+ p->joiner = MACH_PORT_NULL;
+ p->detached |= _PTHREAD_CREATE_PARENT;
+ p->tsd[__TSD_SEMAPHORE_CACHE] = SEMAPHORE_NULL;
+
+ // Initialize the list of threads with the new main thread.
+ TAILQ_INSERT_HEAD(&__pthread_head, p, plist);
+ _pthread_count = 1;
+
+ _pthread_set_self(p);
+ _pthread_introspection_thread_start(p);
+}
+
+/*
+ * Query/update the cancelability 'state' of a thread
+ */
+PTHREAD_NOEXPORT int
+_pthread_setcancelstate_internal(int state, int *oldstate, int conforming)
+{
+ pthread_t self;
+
+ switch (state) {
+ case PTHREAD_CANCEL_ENABLE:
+ if (conforming) {
+ __pthread_canceled(1);
+ }
+ break;
+ case PTHREAD_CANCEL_DISABLE:
+ if (conforming) {
+ __pthread_canceled(2);
+ }
+ break;
+ default:
+ return EINVAL;
+ }
+
+ self = pthread_self();
+ LOCK(self->lock);
+ if (oldstate) {
+ *oldstate = self->cancel_state & _PTHREAD_CANCEL_STATE_MASK;
+ }
+ self->cancel_state &= ~_PTHREAD_CANCEL_STATE_MASK;
+ self->cancel_state |= state;
+ UNLOCK(self->lock);
+ if (!conforming) {
+ _pthread_testcancel(self, 0); /* See if we need to 'die' now... */
+ }
+ return 0;
+}
+
+/* When a thread exits set the cancellation state to DISABLE and DEFERRED */
+static void
+_pthread_setcancelstate_exit(pthread_t self, void * value_ptr, int conforming)
+{
+ LOCK(self->lock);
+ self->cancel_state &= ~(_PTHREAD_CANCEL_STATE_MASK | _PTHREAD_CANCEL_TYPE_MASK);
+ self->cancel_state |= (PTHREAD_CANCEL_DISABLE | PTHREAD_CANCEL_DEFERRED);
+ if (value_ptr == PTHREAD_CANCELED) {
+// 4597450: begin
+ self->detached |= _PTHREAD_WASCANCEL;
+// 4597450: end
+ }
+ UNLOCK(self->lock);
+}
+
+int
+_pthread_join_cleanup(pthread_t thread, void ** value_ptr, int conforming)
+{
+ // Returns ESRCH if the thread was not created joinable.
+ int ret = __pthread_remove_thread(thread, false, NULL);
+ if (ret != 0) {
+ return ret;
+ }
+
+ if (value_ptr) {
+ *value_ptr = __pthread_get_exit_value(thread, conforming);
+ }
+ _pthread_introspection_thread_destroy(thread);
+ _pthread_deallocate(thread);
+ return 0;
+}
+
+/* ALWAYS called with list lock and return with list lock */
+int
+_pthread_find_thread(pthread_t thread)
+{
+ if (thread != NULL) {
+ pthread_t p;
+loop:
+ TAILQ_FOREACH(p, &__pthread_head, plist) {
+ if (p == thread) {
+ if (_pthread_kernel_thread(thread) == MACH_PORT_NULL) {
+ UNLOCK(_pthread_list_lock);
+ sched_yield();
+ LOCK(_pthread_list_lock);
+ goto loop;
+ }
+ return 0;
+ }
+ }
+ }
+ return ESRCH;
+}
+
+int
+_pthread_lookup_thread(pthread_t thread, mach_port_t *portp, int only_joinable)
+{
+ mach_port_t kport = MACH_PORT_NULL;
+ int ret;
+
+ if (thread == NULL) {
+ return ESRCH;
+ }
+
+ LOCK(_pthread_list_lock);
+
+ ret = _pthread_find_thread(thread);
+ if (ret == 0) {
+ // Fail if we only want joinable threads and the thread found is
+ // not in the detached state.
+ if (only_joinable != 0 && (thread->detached & PTHREAD_CREATE_DETACHED) != 0) {
+ ret = EINVAL;
+ } else {
+ kport = _pthread_kernel_thread(thread);
+ }
+ }
+
+ UNLOCK(_pthread_list_lock);
+
+ if (portp != NULL) {
+ *portp = kport;
+ }
+
+ return ret;
+}
+
+void
+_pthread_clear_qos_tsd(mach_port_t thread_port)
+{
+ if (thread_port == MACH_PORT_NULL || (uintptr_t)_pthread_getspecific_direct(_PTHREAD_TSD_SLOT_MACH_THREAD_SELF) == thread_port) {
+ /* Clear the current thread's TSD, that can be done inline. */
+ _pthread_setspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS, _pthread_priority_make_newest(QOS_CLASS_UNSPECIFIED, 0, 0));
+ } else {
+ pthread_t p;
+
+ LOCK(_pthread_list_lock);
+
+ TAILQ_FOREACH(p, &__pthread_head, plist) {
+ mach_port_t kp;
+ while ((kp = _pthread_kernel_thread(p)) == MACH_PORT_NULL) {
+ UNLOCK(_pthread_list_lock);
+ sched_yield();
+ LOCK(_pthread_list_lock);
+ }
+ if (thread_port == kp) {
+ p->tsd[_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS] = _pthread_priority_make_newest(QOS_CLASS_UNSPECIFIED, 0, 0);
+ break;
+ }
+ }
+
+ UNLOCK(_pthread_list_lock);
+ }
+}
+
+/***** pthread workqueue support routines *****/
+
+PTHREAD_NOEXPORT void
+pthread_workqueue_atfork_child(void)
+{
+ struct _pthread_registration_data data = {
+ .dispatch_queue_offset = __PTK_LIBDISPATCH_KEY0 * sizeof(void *),
+ };
+
+ int rv = __bsdthread_register(thread_start,
+ start_wqthread,
+ (int)pthreadsize,
+ (void*)&data,
+ (uintptr_t)sizeof(data),
+ data.dispatch_queue_offset);
+
+ if (rv > 0) {
+ __pthread_supported_features = rv;
+ }
+
+ if (_pthread_priority_get_qos_newest(data.main_qos) != QOS_CLASS_UNSPECIFIED) {
+ _pthread_set_main_qos(data.main_qos);
+ _thread.tsd[_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS] = data.main_qos;
+ }
+
+ if (__libdispatch_workerfunction != NULL) {
+ // prepare the kernel for workq action
+ (void)__workq_open();
+ }
+}
+
+void
+_pthread_wqthread(pthread_t self, mach_port_t kport, void *stackaddr, void *unused, int flags)
+{
+ PTHREAD_ASSERT(flags & WQ_FLAG_THREAD_NEWSPI);
+
+ int thread_reuse = flags & WQ_FLAG_THREAD_REUSE;
+ int thread_class = flags & WQ_FLAG_THREAD_PRIOMASK;
+ int overcommit = (flags & WQ_FLAG_THREAD_OVERCOMMIT) != 0;
+
+ pthread_priority_t priority;
+
+ if ((__pthread_supported_features & PTHREAD_FEATURE_QOS_MAINTENANCE) == 0) {
+ priority = _pthread_priority_make_version2(thread_class, 0, (overcommit ? _PTHREAD_PRIORITY_OVERCOMMIT_FLAG : 0));
+ } else {
+ priority = _pthread_priority_make_newest(thread_class, 0, (overcommit ? _PTHREAD_PRIORITY_OVERCOMMIT_FLAG : 0));
+ }
+
+ if (thread_reuse == 0) {
+ // New thread created by kernel, needs initialization.
+ _pthread_struct_init(self, &_pthread_attr_default, stackaddr, DEFAULT_STACK_SIZE, 1);
+ _pthread_set_kernel_thread(self, kport);
+ self->wqthread = 1;
+ self->wqkillset = 0;
+
+ // Not a joinable thread.
+ self->detached &= ~PTHREAD_CREATE_JOINABLE;
+ self->detached |= PTHREAD_CREATE_DETACHED;
+
+ // Update the running thread count and set childrun bit.
+ // XXX this should be consolidated with pthread_body().
+ _pthread_set_self(self);
+ _pthread_introspection_thread_create(self, false);
+ __pthread_add_thread(self, false);
+
+ // If we're running with fine-grained priority, we also need to
+ // set this thread to have the QoS class provided to use by the kernel
+ if (__pthread_supported_features & PTHREAD_FEATURE_FINEPRIO) {
+ _pthread_setspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS, _pthread_priority_make_newest(thread_class, 0, 0));
+ }
+ }
+
+#if WQ_DEBUG
+ PTHREAD_ASSERT(self);
+ PTHREAD_ASSERT(self == pthread_self());
+#endif // WQ_DEBUG
+
+ self->fun = (void *(*)(void *))__libdispatch_workerfunction;
+ self->arg = (void *)(uintptr_t)thread_class;
+
+ if (__pthread_supported_features & PTHREAD_FEATURE_FINEPRIO) {
+ if (!__workq_newapi) {
+ /* Old thread priorities are inverted from where we have them in
+ * the new flexible priority scheme. The highest priority is zero,
+ * up to 2, with background at 3.
+ */
+ pthread_workqueue_function_t func = (pthread_workqueue_function_t)__libdispatch_workerfunction;
+
+ int opts = overcommit ? WORKQ_ADDTHREADS_OPTION_OVERCOMMIT : 0;
+
+ if ((__pthread_supported_features & PTHREAD_FEATURE_QOS_DEFAULT) == 0) {
+ /* Dirty hack to support kernels that don't have QOS_CLASS_DEFAULT. */
+ switch (thread_class) {
+ case QOS_CLASS_USER_INTERACTIVE:
+ thread_class = QOS_CLASS_USER_INITIATED;
+ break;
+ case QOS_CLASS_USER_INITIATED:
+ thread_class = QOS_CLASS_DEFAULT;
+ break;
+ default:
+ break;
+ }
+ }
+
+ switch (thread_class) {
+ /* QOS_CLASS_USER_INTERACTIVE is not currently requested by for old dispatch priority compatibility */
+ case QOS_CLASS_USER_INITIATED:
+ (*func)(WORKQ_HIGH_PRIOQUEUE, opts, NULL);
+ break;
+
+ case QOS_CLASS_DEFAULT:
+ /* B&I builders can't pass a QOS_CLASS_DEFAULT thread to dispatch, for fear of the QoS being
+ * picked up by NSThread (et al) and transported around the system. So change the TSD to
+ * make this thread look like QOS_CLASS_USER_INITIATED even though it will still run as legacy.
+ */
+ _pthread_setspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS, _pthread_priority_make_newest(QOS_CLASS_USER_INITIATED, 0, 0));
+ (*func)(WORKQ_DEFAULT_PRIOQUEUE, opts, NULL);
+ break;
+
+ case QOS_CLASS_UTILITY:
+ (*func)(WORKQ_LOW_PRIOQUEUE, opts, NULL);
+ break;
+
+ case QOS_CLASS_BACKGROUND:
+ (*func)(WORKQ_BG_PRIOQUEUE, opts, NULL);
+ break;
+
+ /* Legacy dispatch does not use QOS_CLASS_MAINTENANCE, so no need to handle it here */
+ }
+
+ } else {
+ /* "New" API, where dispatch is expecting to be given the thread priority */
+ (*__libdispatch_workerfunction)(priority);
+ }
+ } else {
+ /* We're the new library running on an old kext, so thread_class is really the workq priority. */
+ pthread_workqueue_function_t func = (pthread_workqueue_function_t)__libdispatch_workerfunction;
+ int options = overcommit ? WORKQ_ADDTHREADS_OPTION_OVERCOMMIT : 0;
+ (*func)(thread_class, options, NULL);
+ }
+
+ __workq_kernreturn(WQOPS_THREAD_RETURN, NULL, 0, 0);
+ _pthread_exit(self, NULL);
+}
+
+/***** pthread workqueue API for libdispatch *****/
+
+int
+_pthread_workqueue_init(pthread_workqueue_function2_t func, int offset, int flags)
+{
+ if (flags != 0) {
+ return ENOTSUP;
+ }
+
+ __workq_newapi = true;
+ __libdispatch_offset = offset;
+
+ int rv = pthread_workqueue_setdispatch_np((pthread_workqueue_function_t)func);
+ return rv;
+}
+
+void
+pthread_workqueue_setdispatchoffset_np(int offset)
+{
+ __libdispatch_offset = offset;
+}
+
+int
+pthread_workqueue_setdispatch_np(pthread_workqueue_function_t worker_func)
+{
+ int res = EBUSY;
+ if (__libdispatch_workerfunction == NULL) {
+ // Check whether the kernel supports new SPIs
+ res = __workq_kernreturn(WQOPS_QUEUE_NEWSPISUPP, NULL, __libdispatch_offset, 0);
+ if (res == -1){
+ res = ENOTSUP;
+ } else {
+ __libdispatch_workerfunction = (pthread_workqueue_function2_t)worker_func;
+
+ // Prepare the kernel for workq action
+ (void)__workq_open();
+ if (__is_threaded == 0) {
+ __is_threaded = 1;
+ }
+ }
+ }
+ return res;
+}
+
+int
+_pthread_workqueue_supported(void)
+{
+ return __pthread_supported_features;
+}
+
+int
+pthread_workqueue_addthreads_np(int queue_priority, int options, int numthreads)
+{
+ int res = 0;
+
+ // Cannot add threads without a worker function registered.
+ if (__libdispatch_workerfunction == NULL) {
+ return EPERM;
+ }
+
+ pthread_priority_t kp = 0;
+
+ if (__pthread_supported_features & PTHREAD_FEATURE_FINEPRIO) {
+ /* The new kernel API takes the new QoS class + relative priority style of
+ * priority. This entry point is here for compatibility with old libdispatch
+ * versions (ie. the simulator). We request the corresponding new bracket
+ * from the kernel, then on the way out run all dispatch queues that were
+ * requested.
+ */
+
+ int compat_priority = queue_priority & WQ_FLAG_THREAD_PRIOMASK;
+ int flags = 0;
+
+ /* To make sure the library does not issue more threads to dispatch than
+ * were requested, the total number of active requests is recorded in
+ * __workq_requests.
+ */
+ if (options & WORKQ_ADDTHREADS_OPTION_OVERCOMMIT) {
+ flags = _PTHREAD_PRIORITY_OVERCOMMIT_FLAG;
+ }
+
+ kp = _pthread_qos_class_encode_workqueue(compat_priority, flags);
+
+ } else {
+ /* Running on the old kernel, queue_priority is what we pass directly to
+ * the syscall.
+ */
+ kp = queue_priority & WQ_FLAG_THREAD_PRIOMASK;
+
+ if (options & WORKQ_ADDTHREADS_OPTION_OVERCOMMIT) {
+ kp |= WORKQUEUE_OVERCOMMIT;
+ }
+ }
+
+ res = __workq_kernreturn(WQOPS_QUEUE_REQTHREADS, NULL, numthreads, (int)kp);
+ if (res == -1) {
+ res = errno;
+ }
+ return res;
+}
+
+int
+_pthread_workqueue_addthreads(int numthreads, pthread_priority_t priority)
+{
+ int res = 0;
+
+ if (__libdispatch_workerfunction == NULL) {
+ return EPERM;
+ }
+
+ if ((__pthread_supported_features & PTHREAD_FEATURE_FINEPRIO) == 0) {
+ return ENOTSUP;
+ }
+
+ res = __workq_kernreturn(WQOPS_QUEUE_REQTHREADS, NULL, numthreads, (int)priority);
+ if (res == -1) {
+ res = errno;
+ }
+ return res;
+}
+
+/*
+ * Introspection SPI for libpthread.
+ */
+
+static pthread_introspection_hook_t _pthread_introspection_hook;
+
+pthread_introspection_hook_t
+pthread_introspection_hook_install(pthread_introspection_hook_t hook)
+{
+ if (os_slowpath(!hook)) {
+ PTHREAD_ABORT("pthread_introspection_hook_install was passed NULL");
+ }
+ pthread_introspection_hook_t prev;
+ prev = __sync_swap(&_pthread_introspection_hook, hook);
+ return prev;
+}
+
+PTHREAD_NOINLINE
+static void
+_pthread_introspection_hook_callout_thread_create(pthread_t t, bool destroy)
+{
+ _pthread_introspection_hook(PTHREAD_INTROSPECTION_THREAD_CREATE, t, t,
+ pthreadsize);
+ if (!destroy) return;
+ _pthread_introspection_thread_destroy(t);
+}
+
+static inline void
+_pthread_introspection_thread_create(pthread_t t, bool destroy)
+{
+ if (os_fastpath(!_pthread_introspection_hook)) return;
+ _pthread_introspection_hook_callout_thread_create(t, destroy);
+}
+
+PTHREAD_NOINLINE
+static void
+_pthread_introspection_hook_callout_thread_start(pthread_t t)
+{
+ size_t freesize;
+ void *freeaddr;
+ if (t == &_thread) {
+ freesize = t->stacksize + t->guardsize;
+ freeaddr = t->stackaddr - freesize;
+ } else {
+ freesize = t->freesize - pthreadsize;
+ freeaddr = t->freeaddr;
+ }
+ _pthread_introspection_hook(PTHREAD_INTROSPECTION_THREAD_START, t,
+ freeaddr, freesize);
+}
+
+static inline void
+_pthread_introspection_thread_start(pthread_t t)
+{
+ if (os_fastpath(!_pthread_introspection_hook)) return;
+ _pthread_introspection_hook_callout_thread_start(t);
+}
+
+PTHREAD_NOINLINE
+static void
+_pthread_introspection_hook_callout_thread_terminate(pthread_t t,
+ void *freeaddr, size_t freesize, bool destroy)
+{
+ if (destroy && freesize) {
+ freesize -= pthreadsize;
+ }
+ _pthread_introspection_hook(PTHREAD_INTROSPECTION_THREAD_TERMINATE, t,
+ freeaddr, freesize);
+ if (!destroy) return;
+ _pthread_introspection_thread_destroy(t);
+}
+
+static inline void
+_pthread_introspection_thread_terminate(pthread_t t, void *freeaddr,
+ size_t freesize, bool destroy)
+{
+ if (os_fastpath(!_pthread_introspection_hook)) return;
+ _pthread_introspection_hook_callout_thread_terminate(t, freeaddr, freesize,
+ destroy);
+}
+
+PTHREAD_NOINLINE
+static void
+_pthread_introspection_hook_callout_thread_destroy(pthread_t t)
+{
+ if (t == &_thread) return;
+ _pthread_introspection_hook(PTHREAD_INTROSPECTION_THREAD_DESTROY, t, t,
+ pthreadsize);
+}
+
+static inline void
+_pthread_introspection_thread_destroy(pthread_t t)
+{
+ if (os_fastpath(!_pthread_introspection_hook)) return;
+ _pthread_introspection_hook_callout_thread_destroy(t);
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#if defined(__x86_64__)
+
+#include <mach/i386/syscall_sw.h>
+
+ .text
+ .align 2, 0x90
+ .globl ___pthread_set_self
+___pthread_set_self:
+ movl $0, %esi // 0 as the second argument
+ movl $ SYSCALL_CONSTRUCT_MDEP(3), %eax // Machine-dependent syscall number 3
+ MACHDEP_SYSCALL_TRAP
+ ret
+
+#ifndef VARIANT_DYLD
+
+ .align 2, 0x90
+ .globl _start_wqthread
+_start_wqthread:
+ // This routine is never called directly by user code, jumped from kernel
+ push %rbp
+ mov %rsp,%rbp
+ sub $24,%rsp // align the stack
+ call __pthread_wqthread
+ leave
+ ret
+
+ .align 2, 0x90
+ .globl _thread_start
+_thread_start:
+ // This routine is never called directly by user code, jumped from kernel
+ push %rbp
+ mov %rsp,%rbp
+ sub $24,%rsp // align the stack
+ call __pthread_start
+ leave
+ ret
+
+#endif
+
+#elif defined(__i386__)
+
+#include <mach/i386/syscall_sw.h>
+
+ .text
+ .align 2, 0x90
+ .globl ___pthread_set_self
+___pthread_set_self:
+ pushl 4(%esp)
+ pushl $0
+ movl $3,%eax
+ MACHDEP_SYSCALL_TRAP
+ addl $8,%esp
+ ret
+
+#ifndef VARIANT_DYLD
+
+ .align 2, 0x90
+ .globl _start_wqthread
+_start_wqthread:
+ // This routine is never called directly by user code, jumped from kernel
+ push %ebp
+ mov %esp,%ebp
+ sub $28,%esp // align the stack
+ mov %edi,16(%esp) //arg5
+ mov %edx,12(%esp) //arg4
+ mov %ecx,8(%esp) //arg3
+ mov %ebx,4(%esp) //arg2
+ mov %eax,(%esp) //arg1
+ call __pthread_wqthread
+ leave
+ ret
+
+ .align 2, 0x90
+ .globl _thread_start
+_thread_start:
+ // This routine is never called directly by user code, jumped from kernel
+ push %ebp
+ mov %esp,%ebp
+ sub $28,%esp // align the stack
+ mov %esi,20(%esp) //arg6
+ mov %edi,16(%esp) //arg5
+ mov %edx,12(%esp) //arg4
+ mov %ecx,8(%esp) //arg3
+ mov %ebx,4(%esp) //arg2
+ mov %eax,(%esp) //arg1
+ call __pthread_start
+ leave
+ ret
+
+#endif
+
+#elif defined(__arm__)
+
+#include <mach/arm/syscall_sw.h>
+
+ .text
+ .align 2
+ .globl ___pthread_set_self
+___pthread_set_self:
+ /* fast trap for thread_set_cthread */
+ mov r3, #2
+ mov r12, #0x80000000
+ swi #SWI_SYSCALL
+ bx lr
+
+#ifndef VARIANT_DYLD
+
+// This routine is never called directly by user code, jumped from kernel
+// args 0 to 3 are already in the regs 0 to 3
+// should set stack with the 2 extra args before calling pthread_wqthread()
+// arg4 is in r[4]
+// arg5 is in r[5]
+
+ .text
+ .align 2
+ .globl _start_wqthread
+_start_wqthread:
+ stmfd sp!, {r4, r5}
+ bl __pthread_wqthread
+// Stackshots will show the routine that happens to link immediately following
+// _start_wqthread. So we add an extra instruction (nop) to make stackshots
+// more readable.
+ nop
+
+ .text
+ .align 2
+ .globl _thread_start
+_thread_start:
+ stmfd sp!, {r4, r5}
+ bl __pthread_start
+// See above
+ nop
+
+#endif
+
+#else
+#error Unsupported architecture
+#endif
--- /dev/null
+/*
+ * Copyright (c) 1999, 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#include "internal.h"
+
+#include <libkern/OSAtomic.h>
+#include <mach/mach_init.h>
+#include <mach/mach_vm.h>
+#include <platform/compat.h>
+
+PTHREAD_NOEXPORT void pthread_workqueue_atfork_child(void);
+PTHREAD_NOEXPORT void __pthread_fork_child_internal(pthread_t);
+
+int
+pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
+{
+ int res = 0;
+ size_t idx;
+ pthread_globals_t globals = _pthread_globals();
+
+ OSSpinLockLock(&globals->pthread_atfork_lock);
+ idx = globals->atfork_count++;
+
+ if (idx == 0) {
+ // Initialize pointer to inline storage.
+ globals->atfork = globals->atfork_storage;
+ } else if (idx == PTHREAD_ATFORK_INLINE_MAX) {
+ // Migrate to out-of-line storage.
+ kern_return_t kr;
+ mach_vm_address_t storage = 0;
+ mach_vm_size_t size = PTHREAD_ATFORK_MAX * sizeof(struct pthread_atfork_entry);
+ OSSpinLockUnlock(&globals->pthread_atfork_lock);
+ kr = mach_vm_map(mach_task_self(),
+ &storage,
+ size,
+ vm_page_size - 1,
+ VM_MAKE_TAG(VM_MEMORY_OS_ALLOC_ONCE)| VM_FLAGS_ANYWHERE,
+ MEMORY_OBJECT_NULL,
+ 0,
+ FALSE,
+ VM_PROT_DEFAULT,
+ VM_PROT_ALL,
+ VM_INHERIT_DEFAULT);
+ OSSpinLockLock(&globals->pthread_atfork_lock);
+ if (kr == KERN_SUCCESS) {
+ if (globals->atfork == globals->atfork_storage) {
+ globals->atfork = storage;
+ memmove(globals->atfork, globals->atfork_storage, sizeof(globals->atfork_storage));
+ bzero(globals->atfork_storage, sizeof(globals->atfork_storage));
+ } else {
+ // Another thread did vm_map first.
+ OSSpinLockUnlock(&globals->pthread_atfork_lock);
+ mach_vm_deallocate(mach_task_self(), storage, size);
+ OSSpinLockLock(&globals->pthread_atfork_lock);
+ }
+ } else {
+ res = ENOMEM;
+ }
+ } else if (idx >= PTHREAD_ATFORK_MAX) {
+ res = ENOMEM;
+ }
+
+ if (res == 0) {
+ struct pthread_atfork_entry *e = &globals->atfork[idx];
+ e->prepare = prepare;
+ e->parent = parent;
+ e->child = child;
+ }
+ OSSpinLockUnlock(&globals->pthread_atfork_lock);
+
+ return res;
+}
+
+// Called before the fork(2) system call is made in the parent process.
+// Iterate pthread_atfork prepare handlers.
+void
+_pthread_fork_prepare(void)
+{
+ pthread_globals_t globals = _pthread_globals();
+
+ OSSpinLockLock(&globals->pthread_atfork_lock);
+
+ size_t idx;
+ for (idx = globals->atfork_count; idx > 0; --idx) {
+ struct pthread_atfork_entry *e = &globals->atfork[idx-1];
+ if (e->prepare != NULL) {
+ e->prepare();
+ }
+ }
+
+ OSSpinLockLock(&globals->psaved_self_global_lock);
+ globals->psaved_self = pthread_self();
+ OSSpinLockLock(&globals->psaved_self->lock);
+}
+
+// Called after the fork(2) system call returns to the parent process.
+// Iterate pthread_atfork parent handlers.
+void
+_pthread_fork_parent(void)
+{
+ pthread_globals_t globals = _pthread_globals();
+
+ OSSpinLockUnlock(&globals->psaved_self->lock);
+ OSSpinLockUnlock(&globals->psaved_self_global_lock);
+
+ size_t idx;
+ for (idx = 0; idx < globals->atfork_count; ++idx) {
+ struct pthread_atfork_entry *e = &globals->atfork[idx];
+ if (e->parent != NULL) {
+ e->parent();
+ }
+ }
+ OSSpinLockUnlock(&globals->pthread_atfork_lock);
+}
+
+// Called after the fork(2) system call returns to the new child process.
+// Clean up data structures of other threads which no longer exist in the child.
+// Make the current thread the main thread.
+void
+_pthread_fork_child(void)
+{
+ pthread_globals_t globals = _pthread_globals();
+ globals->psaved_self_global_lock = OS_SPINLOCK_INIT;
+ __pthread_fork_child_internal(globals->psaved_self);
+ __is_threaded = 0;
+ pthread_workqueue_atfork_child();
+}
+
+// Iterate pthread_atfork child handlers.
+void
+_pthread_fork_child_postinit(void)
+{
+ pthread_globals_t globals = _pthread_globals();
+ size_t idx;
+ for (idx = 0; idx < globals->atfork_count; ++idx) {
+ struct pthread_atfork_entry *e = &globals->atfork[idx];
+ if (e->child != NULL) {
+ e->child();
+ }
+ }
+ globals->pthread_atfork_lock = OS_SPINLOCK_INIT;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000-2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * MkLinux
+ */
+
+/*
+ * POSIX Pthread Library
+ */
+
+#include "internal.h"
+
+#include <stdio.h> /* For printf(). */
+#include <stdlib.h>
+#include <errno.h> /* For __mach_errno_addr() prototype. */
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/queue.h>
+#include <machine/vmparam.h>
+#include <mach/vm_statistics.h>
+
+extern int __unix_conforming;
+extern int _pthread_setcancelstate_internal(int state, int *oldstate, int conforming);
+extern void _pthread_testcancel(pthread_t thread, int isconforming);
+extern int _pthread_cond_wait(pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime,
+ int isRelative,
+ int isconforming);
+extern int __sigwait(const sigset_t *set, int *sig);
+extern int __pthread_sigmask(int, const sigset_t *, sigset_t *);
+extern int __pthread_markcancel(int);
+
+#ifdef VARIANT_CANCELABLE
+extern int __semwait_signal(int cond_sem, int mutex_sem, int timeout, int relative, __int64_t tv_sec, __int32_t tv_nsec);
+#else
+extern int __semwait_signal(int cond_sem, int mutex_sem, int timeout, int relative, __int64_t tv_sec, __int32_t tv_nsec) __asm__("___semwait_signal_nocancel");
+#endif
+
+#ifndef VARIANT_CANCELABLE
+
+/*
+ * Cancel a thread
+ */
+int
+pthread_cancel(pthread_t thread)
+{
+#if __DARWIN_UNIX03
+ if (__unix_conforming == 0)
+ __unix_conforming = 1;
+#endif /* __DARWIN_UNIX03 */
+
+ if (_pthread_lookup_thread(thread, NULL, 0) != 0)
+ return(ESRCH);
+
+ /* if the thread is a workqueue thread, then return error */
+ if (thread->wqthread != 0) {
+ return(ENOTSUP);
+ }
+#if __DARWIN_UNIX03
+ int state;
+
+ LOCK(thread->lock);
+ state = thread->cancel_state |= _PTHREAD_CANCEL_PENDING;
+ UNLOCK(thread->lock);
+ if (state & PTHREAD_CANCEL_ENABLE)
+ __pthread_markcancel(_pthread_kernel_thread(thread));
+#else /* __DARWIN_UNIX03 */
+ thread->cancel_state |= _PTHREAD_CANCEL_PENDING;
+#endif /* __DARWIN_UNIX03 */
+ return (0);
+}
+
+void
+pthread_testcancel(void)
+{
+ pthread_t self = pthread_self();
+
+#if __DARWIN_UNIX03
+ if (__unix_conforming == 0)
+ __unix_conforming = 1;
+ _pthread_testcancel(self, 1);
+#else /* __DARWIN_UNIX03 */
+ _pthread_testcancel(self, 0);
+#endif /* __DARWIN_UNIX03 */
+}
+
+/*
+ * Query/update the cancelability 'state' of a thread
+ */
+int
+pthread_setcancelstate(int state, int *oldstate)
+{
+#if __DARWIN_UNIX03
+ if (__unix_conforming == 0) {
+ __unix_conforming = 1;
+ }
+ return (_pthread_setcancelstate_internal(state, oldstate, 1));
+#else /* __DARWIN_UNIX03 */
+ return (_pthread_setcancelstate_internal(state, oldstate, 0));
+#endif /* __DARWIN_UNIX03 */
+}
+
+/*
+ * Query/update the cancelability 'type' of a thread
+ */
+int
+pthread_setcanceltype(int type, int *oldtype)
+{
+ pthread_t self;
+
+#if __DARWIN_UNIX03
+ if (__unix_conforming == 0)
+ __unix_conforming = 1;
+#endif /* __DARWIN_UNIX03 */
+
+ if ((type != PTHREAD_CANCEL_DEFERRED) &&
+ (type != PTHREAD_CANCEL_ASYNCHRONOUS))
+ return EINVAL;
+ self = pthread_self();
+ LOCK(self->lock);
+ if (oldtype)
+ *oldtype = self->cancel_state & _PTHREAD_CANCEL_TYPE_MASK;
+ self->cancel_state &= ~_PTHREAD_CANCEL_TYPE_MASK;
+ self->cancel_state |= type;
+ UNLOCK(self->lock);
+#if !__DARWIN_UNIX03
+ _pthread_testcancel(self, 0); /* See if we need to 'die' now... */
+#endif /* __DARWIN_UNIX03 */
+ return (0);
+}
+
+int
+pthread_sigmask(int how, const sigset_t * set, sigset_t * oset)
+{
+#if __DARWIN_UNIX03
+ int err = 0;
+
+ if (__pthread_sigmask(how, set, oset) == -1) {
+ err = errno;
+ }
+ return(err);
+#else /* __DARWIN_UNIX03 */
+ return(__pthread_sigmask(how, set, oset));
+#endif /* __DARWIN_UNIX03 */
+}
+
+#endif /* VARIANT_CANCELABLE */
+
+#if __DARWIN_UNIX03
+
+static void
+__posix_join_cleanup(void *arg)
+{
+ pthread_t thread = (pthread_t)arg;
+
+ LOCK(thread->lock);
+ /* leave another thread to join */
+ thread->joiner = (struct _pthread *)NULL;
+ UNLOCK(thread->lock);
+}
+
+#endif /* __DARWIN_UNIX03 */
+
+/*
+ * Wait for a thread to terminate and obtain its exit value.
+ */
+int
+pthread_join(pthread_t thread,
+ void **value_ptr)
+{
+ int res = 0;
+ pthread_t self = pthread_self();
+ mach_port_t kthport;
+ int conforming = 0;
+#if !__DARWIN_UNIX03
+ kern_return_t kern_res;
+#endif
+
+#if __DARWIN_UNIX03
+ if (__unix_conforming == 0)
+ __unix_conforming = 1;
+
+#ifdef VARIANT_CANCELABLE
+ _pthread_testcancel(self, 1);
+#endif /* VARIANT_CANCELABLE */
+#endif /* __DARWIN_UNIX03 */
+
+ if ((res = _pthread_lookup_thread(thread, &kthport, 1)) != 0)
+ return(res);
+
+ if (thread->sig == _PTHREAD_SIG) {
+ semaphore_t death = SEMAPHORE_NULL; /* in case we need it */
+ semaphore_t joinsem = SEMAPHORE_NULL;
+
+ if (thread->joiner_notify == SEMAPHORE_NULL) {
+ death = (semaphore_t)os_get_cached_semaphore();
+ }
+
+ LOCK(thread->lock);
+ if ((thread->detached & PTHREAD_CREATE_JOINABLE) &&
+ (thread->joiner == NULL)) {
+ PTHREAD_ASSERT(_pthread_kernel_thread(thread) == kthport);
+ if (thread != self && (self == NULL || self->joiner != thread)) {
+ if (thread->joiner_notify == SEMAPHORE_NULL) {
+ thread->joiner_notify = death;
+ death = SEMAPHORE_NULL;
+ }
+ joinsem = thread->joiner_notify;
+ thread->joiner = self;
+ UNLOCK(thread->lock);
+
+ if (death != SEMAPHORE_NULL) {
+ os_put_cached_semaphore((os_semaphore_t)death);
+ death = SEMAPHORE_NULL;
+ }
+#if __DARWIN_UNIX03
+ /* Wait for it to signal... */
+ pthread_cleanup_push(__posix_join_cleanup, (void *)thread);
+ do {
+ res = __semwait_signal(joinsem, 0, 0, 0, (int64_t)0, (int32_t)0);
+ } while ((res < 0) && (errno == EINTR));
+ pthread_cleanup_pop(0);
+#else /* __DARWIN_UNIX03 */
+ /* Wait for it to signal... */
+ do {
+ kern_res = semaphore_wait(joinsem);
+ } while (kern_res != KERN_SUCCESS);
+#endif /* __DARWIN_UNIX03 */
+
+ os_put_cached_semaphore((os_semaphore_t)joinsem);
+ res = _pthread_join_cleanup(thread, value_ptr, conforming);
+ } else {
+ UNLOCK(thread->lock);
+ res = EDEADLK;
+ }
+ } else {
+ UNLOCK(thread->lock);
+ res = EINVAL;
+ }
+ if (death != SEMAPHORE_NULL) {
+ os_put_cached_semaphore((os_semaphore_t)death);
+ }
+ return res;
+ }
+ return ESRCH;
+}
+
+int
+pthread_cond_wait(pthread_cond_t *cond,
+ pthread_mutex_t *mutex)
+{
+ int conforming;
+#if __DARWIN_UNIX03
+
+ if (__unix_conforming == 0)
+ __unix_conforming = 1;
+
+#ifdef VARIANT_CANCELABLE
+ conforming = 1;
+#else /* !VARIANT_CANCELABLE */
+ conforming = -1;
+#endif /* VARIANT_CANCELABLE */
+#else /* __DARWIN_UNIX03 */
+ conforming = 0;
+#endif /* __DARWIN_UNIX03 */
+ return (_pthread_cond_wait(cond, mutex, (struct timespec *)NULL, 0, conforming));
+}
+
+int
+pthread_cond_timedwait(pthread_cond_t *cond,
+ pthread_mutex_t *mutex,
+ const struct timespec *abstime)
+{
+ int conforming;
+#if __DARWIN_UNIX03
+ if (__unix_conforming == 0)
+ __unix_conforming = 1;
+
+#ifdef VARIANT_CANCELABLE
+ conforming = 1;
+#else /* !VARIANT_CANCELABLE */
+ conforming = -1;
+#endif /* VARIANT_CANCELABLE */
+#else /* __DARWIN_UNIX03 */
+ conforming = 0;
+#endif /* __DARWIN_UNIX03 */
+
+ return (_pthread_cond_wait(cond, mutex, abstime, 0, conforming));
+}
+
+int
+sigwait(const sigset_t * set, int * sig)
+{
+#if __DARWIN_UNIX03
+ int err = 0;
+
+ if (__unix_conforming == 0)
+ __unix_conforming = 1;
+
+#ifdef VARIANT_CANCELABLE
+ _pthread_testcancel(pthread_self(), 1);
+#endif /* VARIANT_CANCELABLE */
+
+ if (__sigwait(set, sig) == -1) {
+ err = errno;
+
+#ifdef VARIANT_CANCELABLE
+ _pthread_testcancel(pthread_self(), 1);
+#endif /* VARIANT_CANCELABLE */
+
+ /*
+ * EINTR that isn't a result of pthread_cancel()
+ * is translated to 0.
+ */
+ if (err == EINTR) {
+ err = 0;
+ }
+ }
+ return(err);
+#else /* __DARWIN_UNIX03 */
+ if (__sigwait(set, sig) == -1) {
+ /*
+ * EINTR that isn't a result of pthread_cancel()
+ * is translated to 0.
+ */
+ if (errno != EINTR) {
+ return -1;
+ }
+ }
+
+ return 0;
+#endif /* __DARWIN_UNIX03 */
+}
--- /dev/null
+/*
+ * Copyright (c) 2000-2003, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * MkLinux
+ */
+
+/*
+ * POSIX Pthread Library
+ */
+
+#include "internal.h"
+#include <sys/time.h> /* For struct timespec and getclock(). */
+#include <stdio.h>
+
+#ifdef PLOCKSTAT
+#include "plockstat.h"
+#else /* !PLOCKSTAT */
+#define PLOCKSTAT_MUTEX_RELEASE(x, y)
+#endif /* PLOCKSTAT */
+
+__private_extern__ int _pthread_cond_init(_pthread_cond *, const pthread_condattr_t *, int);
+__private_extern__ int _pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime, int isRelative, int isconforming);
+
+extern int __gettimeofday(struct timeval *, struct timezone *);
+
+#ifndef BUILDING_VARIANT
+static void _pthread_cond_cleanup(void *arg);
+static void _pthread_cond_updateval(_pthread_cond * cond, int error, uint32_t updateval);
+#endif
+
+static void
+COND_GETSEQ_ADDR(_pthread_cond *cond,
+ volatile uint32_t **c_lseqcnt,
+ volatile uint32_t **c_useqcnt,
+ volatile uint32_t **c_sseqcnt)
+{
+ if (cond->misalign) {
+ *c_lseqcnt = &cond->c_seq[1];
+ *c_sseqcnt = &cond->c_seq[2];
+ *c_useqcnt = &cond->c_seq[0];
+ } else {
+ *c_lseqcnt = &cond->c_seq[0];
+ *c_sseqcnt = &cond->c_seq[1];
+ *c_useqcnt = &cond->c_seq[2];
+ }
+}
+
+#ifndef BUILDING_VARIANT /* [ */
+
+int
+pthread_condattr_init(pthread_condattr_t *attr)
+{
+ attr->sig = _PTHREAD_COND_ATTR_SIG;
+ attr->pshared = _PTHREAD_DEFAULT_PSHARED;
+ return 0;
+}
+
+int
+pthread_condattr_destroy(pthread_condattr_t *attr)
+{
+ attr->sig = _PTHREAD_NO_SIG;
+ return 0;
+}
+
+int
+pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared)
+{
+ int res = EINVAL;
+ if (attr->sig == _PTHREAD_COND_ATTR_SIG) {
+ *pshared = (int)attr->pshared;
+ res = 0;
+ }
+ return res;
+}
+
+int
+pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared)
+{
+ int res = EINVAL;
+ if (attr->sig == _PTHREAD_COND_ATTR_SIG) {
+#if __DARWIN_UNIX03
+ if (pshared == PTHREAD_PROCESS_PRIVATE || pshared == PTHREAD_PROCESS_SHARED)
+#else /* __DARWIN_UNIX03 */
+ if (pshared == PTHREAD_PROCESS_PRIVATE)
+#endif /* __DARWIN_UNIX03 */
+ {
+ attr->pshared = pshared;
+ res = 0;
+ }
+ }
+ return res;
+}
+
+__private_extern__ int
+_pthread_cond_init(_pthread_cond *cond, const pthread_condattr_t *attr, int conforming)
+{
+ volatile uint32_t *c_lseqcnt, *c_useqcnt, *c_sseqcnt;
+
+ cond->busy = NULL;
+ cond->c_seq[0] = 0;
+ cond->c_seq[1] = 0;
+ cond->c_seq[2] = 0;
+ cond->unused = 0;
+
+ cond->misalign = (((uintptr_t)&cond->c_seq[0]) & 0x7) != 0;
+ COND_GETSEQ_ADDR(cond, &c_lseqcnt, &c_useqcnt, &c_sseqcnt);
+ *c_sseqcnt = PTH_RWS_CV_CBIT; // set Sword to 0c
+
+ if (conforming) {
+ if (attr) {
+ cond->pshared = attr->pshared;
+ } else {
+ cond->pshared = _PTHREAD_DEFAULT_PSHARED;
+ }
+ } else {
+ cond->pshared = _PTHREAD_DEFAULT_PSHARED;
+ }
+
+ // Ensure all contents are properly set before setting signature.
+ OSMemoryBarrier();
+ cond->sig = _PTHREAD_COND_SIG;
+
+ return 0;
+}
+
+static int
+_pthread_cond_check_init(_pthread_cond *cond, bool *inited)
+{
+ int res = 0;
+ if (cond->sig != _PTHREAD_COND_SIG) {
+ res = EINVAL;
+ if (cond->sig == _PTHREAD_COND_SIG_init) {
+ LOCK(cond->lock);
+ if (cond->sig == _PTHREAD_COND_SIG_init) {
+ res = _pthread_cond_init(cond, NULL, 0);
+ if (inited) {
+ *inited = true;
+ }
+ } else if (cond->sig == _PTHREAD_COND_SIG) {
+ res = 0;
+ }
+ UNLOCK(cond->lock);
+ }
+ }
+ return res;
+}
+
+int
+pthread_cond_destroy(pthread_cond_t *ocond)
+{
+ _pthread_cond *cond = (_pthread_cond *)ocond;
+ int res = EINVAL;
+ if (cond->sig == _PTHREAD_COND_SIG) {
+ LOCK(cond->lock);
+
+ uint64_t oldval64, newval64;
+ uint32_t lcntval, ucntval, scntval;
+ volatile uint32_t *c_lseqcnt, *c_useqcnt, *c_sseqcnt;
+
+ COND_GETSEQ_ADDR(cond, &c_lseqcnt, &c_useqcnt, &c_sseqcnt);
+
+ do {
+ lcntval = *c_lseqcnt;
+ ucntval = *c_useqcnt;
+ scntval = *c_sseqcnt;
+
+ // validate it is not busy
+ if ((lcntval & PTHRW_COUNT_MASK) != (scntval & PTHRW_COUNT_MASK)) {
+ //res = EBUSY;
+ break;
+ }
+ oldval64 = (((uint64_t)scntval) << 32);
+ oldval64 |= lcntval;
+ newval64 = oldval64;
+ } while (OSAtomicCompareAndSwap64Barrier(oldval64, newval64, (volatile int64_t *)c_lseqcnt) != TRUE);
+
+ // <rdar://problem/13782056> Need to clear preposts.
+ uint32_t flags = 0;
+ bool needclearpre = ((scntval & PTH_RWS_CV_PBIT) != 0);
+ if (needclearpre && cond->pshared == PTHREAD_PROCESS_SHARED) {
+ flags |= _PTHREAD_MTX_OPT_PSHARED;
+ }
+
+ cond->sig = _PTHREAD_NO_SIG;
+ res = 0;
+
+ UNLOCK(cond->lock);
+
+ if (needclearpre) {
+ (void)__psynch_cvclrprepost(cond, lcntval, ucntval, scntval, 0, lcntval, flags);
+ }
+ } else if (cond->sig == _PTHREAD_COND_SIG_init) {
+ // Compatibility for misbehaving applications that attempt to
+ // destroy a statically initialized condition variable.
+ cond->sig = _PTHREAD_NO_SIG;
+ res = 0;
+ }
+ return res;
+}
+
+static int
+_pthread_cond_signal(pthread_cond_t *ocond, bool broadcast, mach_port_t thread)
+{
+ int res;
+ _pthread_cond *cond = (_pthread_cond *)ocond;
+
+ uint32_t updateval;
+ uint32_t diffgen;
+ uint32_t ulval;
+
+ uint64_t oldval64, newval64;
+ uint32_t lcntval, ucntval, scntval;
+ volatile uint32_t *c_lseqcnt, *c_useqcnt, *c_sseqcnt;
+
+ int retry_count = 0, uretry_count = 0;
+ int ucountreset = 0;
+
+ bool inited = false;
+ res = _pthread_cond_check_init(cond, &inited);
+ if (res != 0 || inited == true) {
+ return res;
+ }
+
+ COND_GETSEQ_ADDR(cond, &c_lseqcnt, &c_useqcnt, &c_sseqcnt);
+
+ bool retry;
+ do {
+ retry = false;
+
+ lcntval = *c_lseqcnt;
+ ucntval = *c_useqcnt;
+ scntval = *c_sseqcnt;
+
+ if (((lcntval & PTHRW_COUNT_MASK) == (scntval & PTHRW_COUNT_MASK)) ||
+ (thread == MACH_PORT_NULL && ((lcntval & PTHRW_COUNT_MASK) == (ucntval & PTHRW_COUNT_MASK)))) {
+ /* validate it is spurious and return */
+ oldval64 = (((uint64_t)scntval) << 32);
+ oldval64 |= lcntval;
+ newval64 = oldval64;
+
+ if (OSAtomicCompareAndSwap64Barrier(oldval64, newval64, (volatile int64_t *)c_lseqcnt) != TRUE) {
+ retry = true;
+ continue;
+ } else {
+ return 0;
+ }
+ }
+
+ if (thread) {
+ break;
+ }
+
+ /* validate to eliminate spurious values, race snapshots */
+ if (is_seqhigher((scntval & PTHRW_COUNT_MASK), (lcntval & PTHRW_COUNT_MASK))) {
+ /* since ucntval may be newer, just redo */
+ retry_count++;
+ if (retry_count > 8192) {
+ return EAGAIN;
+ } else {
+ sched_yield();
+ retry = true;
+ continue;
+ }
+ } else if (is_seqhigher((ucntval & PTHRW_COUNT_MASK), (lcntval & PTHRW_COUNT_MASK))) {
+ /* since ucntval may be newer, just redo */
+ uretry_count++;
+ if (uretry_count > 8192) {
+ /*
+ * U value if not used for a while can go out of sync
+ * set this to S value and try one more time.
+ */
+ if (ucountreset != 0) {
+ return EAGAIN;
+ } else if (OSAtomicCompareAndSwap32Barrier(ucntval, (scntval & PTHRW_COUNT_MASK), (volatile int32_t *)c_useqcnt) == TRUE) {
+ /* now the U is reset to S value */
+ ucountreset = 1;
+ uretry_count = 0;
+ }
+ }
+ sched_yield();
+ retry = true;
+ continue;
+ }
+
+ if (is_seqlower(ucntval & PTHRW_COUNT_MASK, scntval & PTHRW_COUNT_MASK) != 0) {
+ /* If U < S, set U = S+diff due to intr's TO, etc */
+ ulval = (scntval & PTHRW_COUNT_MASK);
+ } else {
+ /* If U >= S, set U = U+diff due to intr's TO, etc */
+ ulval = (ucntval & PTHRW_COUNT_MASK);
+ }
+
+ if (broadcast) {
+ diffgen = diff_genseq(lcntval, ulval);
+ // Set U = L
+ ulval = (lcntval & PTHRW_COUNT_MASK);
+ } else {
+ ulval += PTHRW_INC;
+ }
+
+ } while (retry || OSAtomicCompareAndSwap32Barrier(ucntval, ulval, (volatile int32_t *)c_useqcnt) != TRUE);
+
+ uint32_t flags = 0;
+ if (cond->pshared == PTHREAD_PROCESS_SHARED) {
+ flags |= _PTHREAD_MTX_OPT_PSHARED;
+ }
+
+ uint64_t cvlsgen = ((uint64_t)scntval << 32) | lcntval;
+
+ if (broadcast) {
+ // pass old U val so kernel will know the diffgen
+ uint64_t cvudgen = ((uint64_t)ucntval << 32) | diffgen;
+ updateval = __psynch_cvbroad(ocond, cvlsgen, cvudgen, flags, NULL, 0, 0);
+ } else {
+ updateval = __psynch_cvsignal(ocond, cvlsgen, ucntval, thread, NULL, 0, 0, flags);
+ }
+
+ if (updateval != (uint32_t)-1 && updateval != 0) {
+ _pthread_cond_updateval(cond, 0, updateval);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Signal a condition variable, waking up all threads waiting for it.
+ */
+int
+pthread_cond_broadcast(pthread_cond_t *ocond)
+{
+ return _pthread_cond_signal(ocond, true, MACH_PORT_NULL);
+}
+
+/*
+ * Signal a condition variable, waking a specified thread.
+ */
+int
+pthread_cond_signal_thread_np(pthread_cond_t *ocond, pthread_t thread)
+{
+ mach_port_t mp = MACH_PORT_NULL;
+ if (thread) {
+ mp = pthread_mach_thread_np(thread);
+ }
+ return _pthread_cond_signal(ocond, false, mp);
+}
+
+/*
+ * Signal a condition variable, waking only one thread.
+ */
+int
+pthread_cond_signal(pthread_cond_t *cond)
+{
+ return pthread_cond_signal_thread_np(cond, NULL);
+}
+
+/*
+ * Manage a list of condition variables associated with a mutex
+ */
+
+
+/*
+ * Suspend waiting for a condition variable.
+ * Note: we have to keep a list of condition variables which are using
+ * this same mutex variable so we can detect invalid 'destroy' sequences.
+ * If isconforming < 0, we skip the _pthread_testcancel(), but keep the
+ * remaining conforming behavior..
+ */
+__private_extern__ int
+_pthread_cond_wait(pthread_cond_t *ocond,
+ pthread_mutex_t *omutex,
+ const struct timespec *abstime,
+ int isRelative,
+ int isconforming)
+{
+ int res;
+ _pthread_cond *cond = (_pthread_cond *)ocond;
+ _pthread_mutex *mutex = (_pthread_mutex *)omutex;
+ struct timespec then = { 0, 0 };
+ uint32_t mtxgen, mtxugen, flags=0, updateval;
+ uint32_t lcntval, ucntval, scntval;
+ uint32_t nlval, ulval, savebits;
+ volatile uint32_t *c_lseqcnt, *c_useqcnt, *c_sseqcnt;
+ uint64_t oldval64, newval64, mugen, cvlsgen;
+ uint32_t *npmtx = NULL;
+
+extern void _pthread_testcancel(pthread_t thread, int isconforming);
+
+ res = _pthread_cond_check_init(cond, NULL);
+ if (res != 0) {
+ return res;
+ }
+
+ if (isconforming) {
+ if (mutex->sig != _PTHREAD_MUTEX_SIG && (mutex->sig & _PTHREAD_MUTEX_SIG_init_MASK) != _PTHREAD_MUTEX_SIG_CMP) {
+ return EINVAL;
+ }
+ if (isconforming > 0) {
+ _pthread_testcancel(pthread_self(), 1);
+ }
+ }
+
+ /* send relative time to kernel */
+ if (abstime) {
+ if (isRelative == 0) {
+ struct timespec now;
+ struct timeval tv;
+ __gettimeofday(&tv, NULL);
+ TIMEVAL_TO_TIMESPEC(&tv, &now);
+
+ /* Compute relative time to sleep */
+ then.tv_nsec = abstime->tv_nsec - now.tv_nsec;
+ then.tv_sec = abstime->tv_sec - now.tv_sec;
+ if (then.tv_nsec < 0) {
+ then.tv_nsec += NSEC_PER_SEC;
+ then.tv_sec--;
+ }
+ if (then.tv_sec < 0 || (then.tv_sec == 0 && then.tv_nsec == 0)) {
+ return ETIMEDOUT;
+ }
+ if (isconforming &&
+ (abstime->tv_sec < 0 ||
+ abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= NSEC_PER_SEC)) {
+ return EINVAL;
+ }
+ } else {
+ then.tv_sec = abstime->tv_sec;
+ then.tv_nsec = abstime->tv_nsec;
+ if ((then.tv_sec == 0) && (then.tv_nsec == 0)) {
+ return ETIMEDOUT;
+ }
+ }
+ if (isconforming && (then.tv_sec < 0 || then.tv_nsec < 0)) {
+ return EINVAL;
+ }
+ if (then.tv_nsec >= NSEC_PER_SEC) {
+ return EINVAL;
+ }
+ }
+
+ if (cond->busy != NULL && cond->busy != mutex) {
+ return EINVAL;
+ }
+
+ COND_GETSEQ_ADDR(cond, &c_lseqcnt, &c_useqcnt, &c_sseqcnt);
+
+ do {
+ lcntval = *c_lseqcnt;
+ ucntval = *c_useqcnt;
+ scntval = *c_sseqcnt;
+
+ oldval64 = (((uint64_t)scntval) << 32);
+ oldval64 |= lcntval;
+
+ /* remove c and p bits on S word */
+ savebits = scntval & PTH_RWS_CV_BITSALL;
+ ulval = (scntval & PTHRW_COUNT_MASK);
+ nlval = lcntval + PTHRW_INC;
+ newval64 = (((uint64_t)ulval) << 32);
+ newval64 |= nlval;
+ } while (OSAtomicCompareAndSwap64Barrier(oldval64, newval64, (volatile int64_t *)c_lseqcnt) != TRUE);
+
+ cond->busy = mutex;
+
+ res = __mtx_droplock(mutex, &flags, &npmtx, &mtxgen, &mtxugen);
+
+ /* TBD: cases are for normal (non owner for recursive mutex; error checking)*/
+ if (res != 0) {
+ return EINVAL;
+ }
+ if ((flags & _PTHREAD_MTX_OPT_NOTIFY) == 0) {
+ npmtx = NULL;
+ mugen = 0;
+ } else {
+ mugen = ((uint64_t)mtxugen << 32) | mtxgen;
+ }
+ flags &= ~_PTHREAD_MTX_OPT_MUTEX; /* reset the mutex bit as this is cvar */
+
+ cvlsgen = ((uint64_t)(ulval | savebits)<< 32) | nlval;
+
+ // SUSv3 requires pthread_cond_wait to be a cancellation point
+ if (isconforming) {
+ pthread_cleanup_push(_pthread_cond_cleanup, (void *)cond);
+ updateval = __psynch_cvwait(ocond, cvlsgen, ucntval, (pthread_mutex_t *)npmtx, mugen, flags, (int64_t)then.tv_sec, (int32_t)then.tv_nsec);
+ _pthread_testcancel(pthread_self(), isconforming);
+ pthread_cleanup_pop(0);
+ } else {
+ updateval = __psynch_cvwait(ocond, cvlsgen, ucntval, (pthread_mutex_t *)npmtx, mugen, flags, (int64_t)then.tv_sec, (int32_t)then.tv_nsec);
+ }
+
+ if (updateval == (uint32_t)-1) {
+ int err = errno;
+ switch (err & 0xff) {
+ case ETIMEDOUT:
+ res = ETIMEDOUT;
+ break;
+ case EINTR:
+ // spurious wakeup (unless canceled)
+ res = 0;
+ break;
+ default:
+ res = EINVAL;
+ break;
+ }
+
+ // add unlock ref to show one less waiter
+ _pthread_cond_updateval(cond, err, 0);
+ } else if (updateval != 0) {
+ // Successful wait
+ // The return due to prepost and might have bit states
+ // update S and return for prepo if needed
+ _pthread_cond_updateval(cond, 0, updateval);
+ }
+
+ pthread_mutex_lock(omutex);
+
+ return res;
+}
+
+static void
+_pthread_cond_cleanup(void *arg)
+{
+ _pthread_cond *cond = (_pthread_cond *)arg;
+ pthread_mutex_t *mutex;
+
+// 4597450: begin
+ pthread_t thread = pthread_self();
+ int thcanceled = 0;
+
+ LOCK(thread->lock);
+ thcanceled = (thread->detached & _PTHREAD_WASCANCEL);
+ UNLOCK(thread->lock);
+
+ if (thcanceled == 0) {
+ return;
+ }
+
+// 4597450: end
+ mutex = (pthread_mutex_t *)cond->busy;
+
+ // add unlock ref to show one less waiter
+ _pthread_cond_updateval(cond, thread->cancel_error, 0);
+
+ /*
+ ** Can't do anything if this fails -- we're on the way out
+ */
+ if (mutex != NULL) {
+ (void)pthread_mutex_lock(mutex);
+ }
+}
+
+#define ECVCERORR 256
+#define ECVPERORR 512
+
+static void
+_pthread_cond_updateval(_pthread_cond *cond, int error, uint32_t updateval)
+{
+ int needclearpre;
+
+ uint32_t diffgen, nsval;
+ uint64_t oldval64, newval64;
+ uint32_t lcntval, ucntval, scntval;
+ volatile uint32_t *c_lseqcnt, *c_useqcnt, *c_sseqcnt;
+
+ if (error != 0) {
+ updateval = PTHRW_INC;
+ if ((error & ECVCERORR) != 0) {
+ updateval |= PTH_RWS_CV_CBIT;
+ }
+ if ((error & ECVPERORR) != 0) {
+ updateval |= PTH_RWS_CV_PBIT;
+ }
+ }
+
+ COND_GETSEQ_ADDR(cond, &c_lseqcnt, &c_useqcnt, &c_sseqcnt);
+
+ do {
+ lcntval = *c_lseqcnt;
+ ucntval = *c_useqcnt;
+ scntval = *c_sseqcnt;
+
+ diffgen = diff_genseq(lcntval, scntval); // pending waiters
+
+ oldval64 = (((uint64_t)scntval) << 32);
+ oldval64 |= lcntval;
+
+ if (diffgen <= 0) {
+ /* TBD: Assert, should not be the case */
+ /* validate it is spurious and return */
+ newval64 = oldval64;
+ } else {
+ // update S by one
+
+ // update scntval with number of expected returns and bits
+ nsval = (scntval & PTHRW_COUNT_MASK) + (updateval & PTHRW_COUNT_MASK);
+ // set bits
+ nsval |= ((scntval & PTH_RWS_CV_BITSALL) | (updateval & PTH_RWS_CV_BITSALL));
+
+ // if L==S and c&p bits are set, needs clearpre
+ if (((nsval & PTHRW_COUNT_MASK) == (lcntval & PTHRW_COUNT_MASK)) &&
+ ((nsval & PTH_RWS_CV_BITSALL) == PTH_RWS_CV_BITSALL)) {
+ // reset p bit but retain c bit on the sword
+ nsval &= PTH_RWS_CV_RESET_PBIT;
+ needclearpre = 1;
+ } else {
+ needclearpre = 0;
+ }
+
+ newval64 = (((uint64_t)nsval) << 32);
+ newval64 |= lcntval;
+ }
+ } while (OSAtomicCompareAndSwap64Barrier(oldval64, newval64, (volatile int64_t *)c_lseqcnt) != TRUE);
+
+ if (diffgen > 0) {
+ // if L == S, then reset associated mutex
+ if ((nsval & PTHRW_COUNT_MASK) == (lcntval & PTHRW_COUNT_MASK)) {
+ cond->busy = NULL;
+ }
+
+ if (needclearpre != 0) {
+ uint32_t flags = 0;
+ if (cond->pshared == PTHREAD_PROCESS_SHARED) {
+ flags |= _PTHREAD_MTX_OPT_PSHARED;
+ }
+ (void)__psynch_cvclrprepost(cond, lcntval, ucntval, nsval, 0, lcntval, flags);
+ }
+ }
+}
+
+
+int
+pthread_cond_timedwait_relative_np(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
+{
+ return _pthread_cond_wait(cond, mutex, abstime, 1, 0);
+}
+
+#endif /* !BUILDING_VARIANT ] */
+
+int
+pthread_cond_init(pthread_cond_t *ocond, const pthread_condattr_t *attr)
+{
+ int conforming;
+
+#if __DARWIN_UNIX03
+ conforming = 1;
+#else /* __DARWIN_UNIX03 */
+ conforming = 0;
+#endif /* __DARWIN_UNIX03 */
+
+ _pthread_cond *cond = (_pthread_cond *)ocond;
+ LOCK_INIT(cond->lock);
+ return _pthread_cond_init(cond, attr, conforming);
+}
--- /dev/null
+/*
+ * Copyright (c) 2000-2003, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * MkLinux
+ */
+
+/*
+ * POSIX Pthread Library
+ * -- Mutex variable support
+ */
+
+#include "internal.h"
+#include "kern/kern_trace.h"
+#include <sys/syscall.h>
+
+#ifdef PLOCKSTAT
+#include "plockstat.h"
+#else /* !PLOCKSTAT */
+#define PLOCKSTAT_MUTEX_SPIN(x)
+#define PLOCKSTAT_MUTEX_SPUN(x, y, z)
+#define PLOCKSTAT_MUTEX_ERROR(x, y)
+#define PLOCKSTAT_MUTEX_BLOCK(x)
+#define PLOCKSTAT_MUTEX_BLOCKED(x, y)
+#define PLOCKSTAT_MUTEX_ACQUIRE(x, y, z)
+#define PLOCKSTAT_MUTEX_RELEASE(x, y)
+#endif /* PLOCKSTAT */
+
+extern int __unix_conforming;
+
+#ifndef BUILDING_VARIANT
+PTHREAD_NOEXPORT int __mtx_markprepost(_pthread_mutex *mutex, uint32_t oupdateval, int firstfit);
+#endif /* BUILDING_VARIANT */
+
+#define DEBUG_TRACE_POINTS 0
+
+#if DEBUG_TRACE_POINTS
+extern int __syscall(int number, ...);
+#define DEBUG_TRACE(x, a, b, c, d) __syscall(SYS_kdebug_trace, TRACE_##x, a, b, c, d)
+#else
+#define DEBUG_TRACE(x, a, b, c, d) do { } while(0)
+#endif
+
+#include <machine/cpu_capabilities.h>
+
+static int _pthread_mutex_init(_pthread_mutex *mutex, const pthread_mutexattr_t *attr, uint32_t static_type);
+
+#if !__LITTLE_ENDIAN__
+#error MUTEX_GETSEQ_ADDR assumes little endian layout of 2 32-bit sequence words
+#endif
+
+static void
+MUTEX_GETSEQ_ADDR(_pthread_mutex *mutex,
+ volatile uint64_t **seqaddr)
+{
+ if (mutex->mtxopts.options.misalign) {
+ *seqaddr = (volatile uint64_t *)&mutex->m_seq[1];
+ } else {
+ *seqaddr = (volatile uint64_t *)&mutex->m_seq[0];
+ }
+}
+
+static void
+MUTEX_GETTID_ADDR(_pthread_mutex *mutex,
+ volatile uint64_t **tidaddr)
+{
+ if (mutex->mtxopts.options.misalign) {
+ *tidaddr = (volatile uint64_t *)&mutex->m_tid[1];
+ } else {
+ *tidaddr = (volatile uint64_t *)&mutex->m_tid[0];
+ }
+}
+
+#ifndef BUILDING_VARIANT /* [ */
+
+#define BLOCK_FAIL_PLOCKSTAT 0
+#define BLOCK_SUCCESS_PLOCKSTAT 1
+
+/* This function is never called and exists to provide never-fired dtrace
+ * probes so that user d scripts don't get errors.
+ */
+__private_extern__ __attribute__((used)) void
+_plockstat_never_fired(void)
+{
+ PLOCKSTAT_MUTEX_SPIN(NULL);
+ PLOCKSTAT_MUTEX_SPUN(NULL, 0, 0);
+}
+
+
+/*
+ * Initialize a mutex variable, possibly with additional attributes.
+ * Public interface - so don't trust the lock - initialize it first.
+ */
+int
+pthread_mutex_init(pthread_mutex_t *omutex, const pthread_mutexattr_t *attr)
+{
+#if 0
+ /* conformance tests depend on not having this behavior */
+ /* The test for this behavior is optional */
+ if (mutex->sig == _PTHREAD_MUTEX_SIG)
+ return EBUSY;
+#endif
+ _pthread_mutex *mutex = (_pthread_mutex *)omutex;
+ LOCK_INIT(mutex->lock);
+ return (_pthread_mutex_init(mutex, attr, 0x7));
+}
+
+int
+pthread_mutex_getprioceiling(const pthread_mutex_t *omutex, int *prioceiling)
+{
+ int res = EINVAL;
+ _pthread_mutex *mutex = (_pthread_mutex *)omutex;
+ if (mutex->sig == _PTHREAD_MUTEX_SIG) {
+ LOCK(mutex->lock);
+ *prioceiling = mutex->prioceiling;
+ res = 0;
+ UNLOCK(mutex->lock);
+ }
+ return res;
+}
+
+int
+pthread_mutex_setprioceiling(pthread_mutex_t *omutex, int prioceiling, int *old_prioceiling)
+{
+ int res = EINVAL;
+ _pthread_mutex *mutex = (_pthread_mutex *)omutex;
+ if (mutex->sig == _PTHREAD_MUTEX_SIG) {
+ LOCK(mutex->lock);
+ if (prioceiling >= -999 || prioceiling <= 999) {
+ *old_prioceiling = mutex->prioceiling;
+ mutex->prioceiling = prioceiling;
+ res = 0;
+ }
+ UNLOCK(mutex->lock);
+ }
+ return res;
+}
+
+int
+pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *prioceiling)
+{
+ int res = EINVAL;
+ if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
+ *prioceiling = attr->prioceiling;
+ res = 0;
+ }
+ return res;
+}
+
+int
+pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol)
+{
+ int res = EINVAL;
+ if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
+ *protocol = attr->protocol;
+ res = 0;
+ }
+ return res;
+}
+
+int
+pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type)
+{
+ int res = EINVAL;
+ if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
+ *type = attr->type;
+ res = 0;
+ }
+ return res;
+}
+
+int
+pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared)
+{
+ int res = EINVAL;
+ if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
+ *pshared = (int)attr->pshared;
+ res = 0;
+ }
+ return res;
+}
+
+int
+pthread_mutexattr_init(pthread_mutexattr_t *attr)
+{
+ attr->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
+ attr->protocol = _PTHREAD_DEFAULT_PROTOCOL;
+ attr->policy = _PTHREAD_MUTEX_POLICY_FAIRSHARE;
+ attr->type = PTHREAD_MUTEX_DEFAULT;
+ attr->sig = _PTHREAD_MUTEX_ATTR_SIG;
+ attr->pshared = _PTHREAD_DEFAULT_PSHARED;
+ return 0;
+}
+
+int
+pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling)
+{
+ int res = EINVAL;
+ if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
+ if (prioceiling >= -999 || prioceiling <= 999) {
+ attr->prioceiling = prioceiling;
+ res = 0;
+ }
+ }
+ return res;
+}
+
+int
+pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol)
+{
+ int res = EINVAL;
+ if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
+ switch (protocol) {
+ case PTHREAD_PRIO_NONE:
+ case PTHREAD_PRIO_INHERIT:
+ case PTHREAD_PRIO_PROTECT:
+ attr->protocol = protocol;
+ res = 0;
+ break;
+ }
+ }
+ return res;
+}
+
+int
+pthread_mutexattr_setpolicy_np(pthread_mutexattr_t *attr, int policy)
+{
+ int res = EINVAL;
+ if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
+ switch (policy) {
+ case _PTHREAD_MUTEX_POLICY_FAIRSHARE:
+ case _PTHREAD_MUTEX_POLICY_FIRSTFIT:
+ attr->policy = policy;
+ res = 0;
+ break;
+ }
+ }
+ return res;
+}
+
+int
+pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type)
+{
+ int res = EINVAL;
+ if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
+ switch (type) {
+ case PTHREAD_MUTEX_NORMAL:
+ case PTHREAD_MUTEX_ERRORCHECK:
+ case PTHREAD_MUTEX_RECURSIVE:
+ //case PTHREAD_MUTEX_DEFAULT:
+ attr->type = type;
+ res = 0;
+ break;
+ }
+ }
+ return res;
+}
+
+// XXX remove
+void
+cthread_yield(void)
+{
+ sched_yield();
+}
+
+void
+pthread_yield_np(void)
+{
+ sched_yield();
+}
+
+
+/*
+ * Temp: till pshared is fixed correctly
+ */
+int
+pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared)
+{
+ int res = EINVAL;
+#if __DARWIN_UNIX03
+ if (__unix_conforming == 0) {
+ __unix_conforming = 1;
+ }
+#endif /* __DARWIN_UNIX03 */
+
+ if (attr->sig == _PTHREAD_MUTEX_ATTR_SIG) {
+#if __DARWIN_UNIX03
+ if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED))
+#else /* __DARWIN_UNIX03 */
+ if ( pshared == PTHREAD_PROCESS_PRIVATE)
+#endif /* __DARWIN_UNIX03 */
+ {
+ attr->pshared = pshared;
+ res = 0;
+ }
+ }
+ return res;
+}
+
+/*
+ * Sequence numbers and TID:
+ *
+ * In steady (and uncontended) state, an unlocked mutex will
+ * look like A=[L4 U4 TID0]. When it is being locked, it transitions
+ * to B=[L5+KE U4 TID0] and then C=[L5+KE U4 TID940]. For an uncontended mutex,
+ * the unlock path will then transition to D=[L5 U4 TID0] and then finally
+ * E=[L5 U5 TID0].
+ *
+ * If a contender comes in after B, the mutex will instead transition to E=[L6+KE U4 TID0]
+ * and then F=[L6+KE U4 TID940]. If a contender comes in after C, it will transition to
+ * F=[L6+KE U4 TID940] directly. In both cases, the contender will enter the kernel with either
+ * mutexwait(U4, TID0) or mutexwait(U4, TID940). The first owner will unlock the mutex
+ * by first updating the owner to G=[L6+KE U4 TID-1] and then doing the actual unlock to
+ * H=[L6+KE U5 TID=-1] before entering the kernel with mutexdrop(U5, -1) to signal the next waiter
+ * (potentially as a prepost). When the waiter comes out of the kernel, it will update the owner to
+ * I=[L6+KE U5 TID941]. An unlock at this point is simply J=[L6 U5 TID0] and then K=[L6 U6 TID0].
+ *
+ * At various points along these timelines, since the sequence words and TID are written independently,
+ * a thread may get preempted and another thread might see inconsistent data. In the worst case, another
+ * thread may see the TID in the SWITCHING (-1) state or unlocked (0) state for longer because the
+ * owning thread was preempted.
+
+/*
+ * Drop the mutex unlock references from cond_wait. or mutex_unlock.
+ */
+__private_extern__ int
+__mtx_droplock(_pthread_mutex *mutex, uint32_t *flagsp, uint32_t **pmtxp, uint32_t *mgenp, uint32_t *ugenp)
+{
+ bool firstfit = (mutex->mtxopts.options.policy == _PTHREAD_MUTEX_POLICY_FIRSTFIT);
+ uint32_t lgenval, ugenval, flags;
+ uint64_t oldtid, newtid;
+ volatile uint64_t *tidaddr;
+ MUTEX_GETTID_ADDR(mutex, &tidaddr);
+
+ flags = mutex->mtxopts.value;
+ flags &= ~_PTHREAD_MTX_OPT_NOTIFY; // no notification by default
+
+ if (mutex->mtxopts.options.type != PTHREAD_MUTEX_NORMAL) {
+ uint64_t selfid = _pthread_selfid_direct();
+
+ if (*tidaddr != selfid) {
+ //PTHREAD_ABORT("dropping recur or error mutex not owned by the thread\n");
+ PLOCKSTAT_MUTEX_ERROR((pthread_mutex_t *)mutex, EPERM);
+ return EPERM;
+ } else if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE &&
+ --mutex->mtxopts.options.lock_count) {
+ PLOCKSTAT_MUTEX_RELEASE((pthread_mutex_t *)mutex, 1);
+ if (flagsp != NULL) {
+ *flagsp = flags;
+ }
+ return 0;
+ }
+ }
+
+ uint64_t oldval64, newval64;
+ volatile uint64_t *seqaddr;
+ MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
+
+ bool clearprepost, clearnotify, spurious;
+ do {
+ oldval64 = *seqaddr;
+ oldtid = *tidaddr;
+ lgenval = (uint32_t)oldval64;
+ ugenval = (uint32_t)(oldval64 >> 32);
+
+ clearprepost = false;
+ clearnotify = false;
+ spurious = false;
+
+ int numwaiters = diff_genseq(lgenval, ugenval); // pending waiters
+
+ if (numwaiters == 0) {
+ // spurious unlock; do not touch tid
+ spurious = true;
+ } else {
+ ugenval += PTHRW_INC;
+
+ if ((lgenval & PTHRW_COUNT_MASK) == (ugenval & PTHRW_COUNT_MASK)) {
+ // our unlock sequence matches to lock sequence, so if the CAS is successful, the mutex is unlocked
+
+ /* do not reset Ibit, just K&E */
+ lgenval &= ~(PTH_RWL_KBIT | PTH_RWL_EBIT);
+ clearnotify = true;
+ newtid = 0; // clear owner
+ } else {
+ if (firstfit) {
+ lgenval &= ~PTH_RWL_EBIT; // reset E bit so another can acquire meanwhile
+ newtid = 0;
+ } else {
+ newtid = PTHREAD_MTX_TID_SWITCHING;
+ }
+ // need to signal others waiting for mutex
+ flags |= _PTHREAD_MTX_OPT_NOTIFY;
+ }
+
+ if (newtid != oldtid) {
+ // We're giving up the mutex one way or the other, so go ahead and update the owner to SWITCHING
+ // or 0 so that once the CAS below succeeds, there is no stale ownership information.
+ // If the CAS of the seqaddr fails, we may loop, but it's still valid for the owner
+ // to be SWITCHING/0
+ if (!OSAtomicCompareAndSwap64(oldtid, newtid, (volatile int64_t *)tidaddr)) {
+ // we own this mutex, nobody should be updating it except us
+ __builtin_trap();
+ }
+ }
+ }
+
+ if (clearnotify || spurious) {
+ flags &= ~_PTHREAD_MTX_OPT_NOTIFY;
+ if (firstfit && ((lgenval & PTH_RWL_PBIT) != 0)) {
+ clearprepost = true;
+ lgenval &= ~PTH_RWL_PBIT;
+ }
+ }
+
+ newval64 = (((uint64_t)ugenval) << 32);
+ newval64 |= lgenval;
+
+ } while (OSAtomicCompareAndSwap64Barrier(oldval64, newval64, (volatile int64_t *)seqaddr) != TRUE);
+
+ if (clearprepost) {
+ __psynch_cvclrprepost(mutex, lgenval, ugenval, 0, 0, lgenval, (flags | _PTHREAD_MTX_OPT_MUTEX));
+ }
+
+ if (mgenp != NULL) {
+ *mgenp = lgenval;
+ }
+ if (ugenp != NULL) {
+ *ugenp = ugenval;
+ }
+ if (pmtxp != NULL) {
+ *pmtxp = (uint32_t *)mutex;
+ }
+ if (flagsp != NULL) {
+ *flagsp = flags;
+ }
+
+ return 0;
+}
+
+static int
+__mtx_updatebits(_pthread_mutex *mutex, uint64_t selfid)
+{
+ int res = 0;
+ int firstfit = (mutex->mtxopts.options.policy == _PTHREAD_MUTEX_POLICY_FIRSTFIT);
+ int isebit = 0;
+
+ uint32_t lgenval, ugenval;
+ uint64_t oldval64, newval64;
+ volatile uint64_t *seqaddr;
+ MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
+ uint64_t oldtid;
+ volatile uint64_t *tidaddr;
+ MUTEX_GETTID_ADDR(mutex, &tidaddr);
+
+ do {
+ do {
+ oldval64 = *seqaddr;
+ oldtid = *tidaddr;
+ lgenval = (uint32_t)oldval64;
+ ugenval = (uint32_t)(oldval64 >> 32);
+
+ // E bit was set on first pass through the loop but is no longer
+ // set. Apparently we spin until it arrives.
+ // XXX: verify this is desired behavior.
+ } while (isebit && (lgenval & PTH_RWL_EBIT) == 0);
+
+ if (isebit) {
+ // first fit mutex now has the E bit set. Return 1.
+ res = 1;
+ break;
+ }
+
+ if (firstfit) {
+ isebit = (lgenval & PTH_RWL_EBIT) != 0;
+ } else if ((lgenval & (PTH_RWL_KBIT|PTH_RWL_EBIT)) == (PTH_RWL_KBIT|PTH_RWL_EBIT)) {
+ // fairshare mutex and the bits are already set, just update tid
+ break;
+ }
+
+ // either first fit or no E bit set
+ // update the bits
+ lgenval |= PTH_RWL_KBIT | PTH_RWL_EBIT;
+
+ newval64 = (((uint64_t)ugenval) << 32);
+ newval64 |= lgenval;
+
+ // set s and b bit
+ // Retry if CAS fails, or if it succeeds with firstfit and E bit already set
+ } while (OSAtomicCompareAndSwap64Barrier(oldval64, newval64, (volatile int64_t *)seqaddr) != TRUE ||
+ (firstfit && isebit));
+
+ if (res == 0) {
+ if (!OSAtomicCompareAndSwap64Barrier(oldtid, selfid, (volatile int64_t *)tidaddr)) {
+ // we own this mutex, nobody should be updating it except us
+ __builtin_trap();
+ }
+ }
+
+ return res;
+}
+
+int
+__mtx_markprepost(_pthread_mutex *mutex, uint32_t updateval, int firstfit)
+{
+ uint32_t flags;
+ uint32_t lgenval, ugenval;
+ uint64_t oldval64, newval64;
+
+ volatile uint64_t *seqaddr;
+ MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
+
+ if (firstfit != 0 && (updateval & PTH_RWL_PBIT) != 0) {
+ int clearprepost;
+ do {
+ clearprepost = 0;
+
+ flags = mutex->mtxopts.value;
+
+ oldval64 = *seqaddr;
+ lgenval = (uint32_t)oldval64;
+ ugenval = (uint32_t)(oldval64 >> 32);
+
+ /* update the bits */
+ if ((lgenval & PTHRW_COUNT_MASK) == (ugenval & PTHRW_COUNT_MASK)) {
+ clearprepost = 1;
+ lgenval &= ~PTH_RWL_PBIT;
+ } else {
+ lgenval |= PTH_RWL_PBIT;
+ }
+ newval64 = (((uint64_t)ugenval) << 32);
+ newval64 |= lgenval;
+ } while (OSAtomicCompareAndSwap64Barrier(oldval64, newval64, (volatile int64_t *)seqaddr) != TRUE);
+
+ if (clearprepost != 0) {
+ __psynch_cvclrprepost(mutex, lgenval, ugenval, 0, 0, lgenval, (flags | _PTHREAD_MTX_OPT_MUTEX));
+ }
+ }
+ return 0;
+}
+
+static inline bool
+_pthread_mutex_check_init_fast(_pthread_mutex *mutex)
+{
+ return (mutex->sig == _PTHREAD_MUTEX_SIG);
+}
+
+static int __attribute__((noinline))
+_pthread_mutex_check_init(pthread_mutex_t *omutex)
+{
+ int res = 0;
+ _pthread_mutex *mutex = (_pthread_mutex *)omutex;
+
+ if (mutex->sig != _PTHREAD_MUTEX_SIG) {
+ res = EINVAL;
+ if ((mutex->sig & _PTHREAD_MUTEX_SIG_init_MASK) == _PTHREAD_MUTEX_SIG_CMP) {
+ LOCK(mutex->lock);
+ if ((mutex->sig & _PTHREAD_MUTEX_SIG_init_MASK) == _PTHREAD_MUTEX_SIG_CMP) {
+ // initialize a statically initialized mutex to provide
+ // compatibility for misbehaving applications.
+ // (unlock should not be the first operation on a mutex)
+ res = _pthread_mutex_init(mutex, NULL, (mutex->sig & 0xf));
+ } else if (mutex->sig == _PTHREAD_MUTEX_SIG) {
+ res = 0;
+ }
+ UNLOCK(mutex->lock);
+ }
+ if (res != 0) {
+ PLOCKSTAT_MUTEX_ERROR(omutex, res);
+ }
+ }
+ return res;
+}
+
+static int
+_pthread_mutex_lock(pthread_mutex_t *omutex, bool trylock)
+{
+ int res;
+ _pthread_mutex *mutex = (_pthread_mutex *)omutex;
+
+ if (os_slowpath(!_pthread_mutex_check_init_fast(mutex))) {
+ res = _pthread_mutex_check_init(omutex);
+ if (res != 0) {
+ return res;
+ }
+ }
+
+ uint64_t oldtid;
+ volatile uint64_t *tidaddr;
+ MUTEX_GETTID_ADDR(mutex, &tidaddr);
+ uint64_t selfid = _pthread_selfid_direct();
+
+ if (mutex->mtxopts.options.type != PTHREAD_MUTEX_NORMAL) {
+ if (*tidaddr == selfid) {
+ if (mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE) {
+ if (mutex->mtxopts.options.lock_count < USHRT_MAX) {
+ mutex->mtxopts.options.lock_count++;
+ PLOCKSTAT_MUTEX_ACQUIRE(omutex, 1, 0);
+ res = 0;
+ } else {
+ res = EAGAIN;
+ PLOCKSTAT_MUTEX_ERROR(omutex, res);
+ }
+ } else if (trylock) { /* PTHREAD_MUTEX_ERRORCHECK */
+ // <rdar://problem/16261552> as per OpenGroup, trylock cannot
+ // return EDEADLK on a deadlock, it should return EBUSY.
+ res = EBUSY;
+ PLOCKSTAT_MUTEX_ERROR(omutex, res);
+ } else { /* PTHREAD_MUTEX_ERRORCHECK */
+ res = EDEADLK;
+ PLOCKSTAT_MUTEX_ERROR(omutex, res);
+ }
+ return res;
+ }
+ }
+
+ uint64_t oldval64, newval64;
+ volatile uint64_t *seqaddr;
+ MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
+
+ uint32_t lgenval, ugenval;
+ bool gotlock = false;
+
+ do {
+ oldval64 = *seqaddr;
+ oldtid = *tidaddr;
+ lgenval = (uint32_t)oldval64;
+ ugenval = (uint32_t)(oldval64 >> 32);
+
+ gotlock = ((lgenval & PTH_RWL_EBIT) == 0);
+
+ if (trylock && !gotlock) {
+ // A trylock on a held lock will fail immediately. But since
+ // we did not load the sequence words atomically, perform a
+ // no-op CAS64 to ensure that nobody has unlocked concurrently.
+ } else {
+ // Increment the lock sequence number and force the lock into E+K
+ // mode, whether "gotlock" is true or not.
+ lgenval += PTHRW_INC;
+ lgenval |= PTH_RWL_EBIT | PTH_RWL_KBIT;
+ }
+
+ newval64 = (((uint64_t)ugenval) << 32);
+ newval64 |= lgenval;
+
+ // Set S and B bit
+ } while (OSAtomicCompareAndSwap64Barrier(oldval64, newval64, (volatile int64_t *)seqaddr) == FALSE);
+
+ if (gotlock) {
+ if (!OSAtomicCompareAndSwap64Barrier(oldtid, selfid, (volatile int64_t *)tidaddr)) {
+ while (!OSAtomicCompareAndSwap64Barrier(*tidaddr, selfid, (volatile int64_t *)tidaddr));
+ }
+ res = 0;
+ DEBUG_TRACE(psynch_mutex_ulock, omutex, lgenval, ugenval, selfid);
+ PLOCKSTAT_MUTEX_ACQUIRE(omutex, 0, 0);
+ } else if (trylock) {
+ res = EBUSY;
+ DEBUG_TRACE(psynch_mutex_utrylock_failed, omutex, lgenval, ugenval, oldtid);
+ PLOCKSTAT_MUTEX_ERROR(omutex, res);
+ } else {
+ PLOCKSTAT_MUTEX_BLOCK(omutex);
+ do {
+ uint32_t updateval;
+ do {
+ updateval = __psynch_mutexwait(omutex, lgenval, ugenval, oldtid, mutex->mtxopts.value);
+ oldtid = *tidaddr;
+ } while (updateval == (uint32_t)-1);
+
+ // returns 0 on succesful update; in firstfit it may fail with 1
+ } while (__mtx_updatebits(mutex, selfid) == 1);
+ res = 0;
+ PLOCKSTAT_MUTEX_BLOCKED(omutex, BLOCK_SUCCESS_PLOCKSTAT);
+ }
+
+ if (res == 0 && mutex->mtxopts.options.type == PTHREAD_MUTEX_RECURSIVE) {
+ mutex->mtxopts.options.lock_count = 1;
+ }
+
+ PLOCKSTAT_MUTEX_ACQUIRE(omutex, 0, 0);
+
+ return res;
+}
+
+int
+pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+ return _pthread_mutex_lock(mutex, false);
+}
+
+int
+pthread_mutex_trylock(pthread_mutex_t *mutex)
+{
+ return _pthread_mutex_lock(mutex, true);
+}
+
+/*
+ * Unlock a mutex.
+ * TODO: Priority inheritance stuff
+ */
+int
+pthread_mutex_unlock(pthread_mutex_t *omutex)
+{
+ int res;
+ _pthread_mutex *mutex = (_pthread_mutex *)omutex;
+ uint32_t mtxgen, mtxugen, flags;
+
+ // Initialize static mutexes for compatibility with misbehaving
+ // applications (unlock should not be the first operation on a mutex).
+ if (os_slowpath(!_pthread_mutex_check_init_fast(mutex))) {
+ res = _pthread_mutex_check_init(omutex);
+ if (res != 0) {
+ return res;
+ }
+ }
+
+ res = __mtx_droplock(mutex, &flags, NULL, &mtxgen, &mtxugen);
+ if (res != 0) {
+ return res;
+ }
+
+ if ((flags & _PTHREAD_MTX_OPT_NOTIFY) != 0) {
+ uint32_t updateval;
+ int firstfit = (mutex->mtxopts.options.policy == _PTHREAD_MUTEX_POLICY_FIRSTFIT);
+ volatile uint64_t *tidaddr;
+ MUTEX_GETTID_ADDR(mutex, &tidaddr);
+
+ updateval = __psynch_mutexdrop(omutex, mtxgen, mtxugen, *tidaddr, flags);
+
+ if (updateval == (uint32_t)-1) {
+ res = errno;
+
+ if (res == EINTR) {
+ res = 0;
+ }
+ if (res != 0) {
+ PTHREAD_ABORT("__p_mutexdrop failed with error %d\n", res);
+ }
+ return res;
+ } else if (firstfit == 1) {
+ if ((updateval & PTH_RWL_PBIT) != 0) {
+ __mtx_markprepost(mutex, updateval, firstfit);
+ }
+ }
+ } else {
+ volatile uint64_t *tidaddr;
+ MUTEX_GETTID_ADDR(mutex, &tidaddr);
+ DEBUG_TRACE(psynch_mutex_uunlock, omutex, mtxgen, mtxugen, *tidaddr);
+ }
+
+ return 0;
+}
+
+int
+_pthread_mutex_init(_pthread_mutex *mutex, const pthread_mutexattr_t *attr, uint32_t static_type)
+{
+ if (attr) {
+ if (attr->sig != _PTHREAD_MUTEX_ATTR_SIG) {
+ return EINVAL;
+ }
+ mutex->prioceiling = attr->prioceiling;
+ mutex->mtxopts.options.protocol = attr->protocol;
+ mutex->mtxopts.options.policy = attr->policy;
+ mutex->mtxopts.options.type = attr->type;
+ mutex->mtxopts.options.pshared = attr->pshared;
+ } else {
+ switch (static_type) {
+ case 1:
+ mutex->mtxopts.options.type = PTHREAD_MUTEX_ERRORCHECK;
+ break;
+ case 2:
+ mutex->mtxopts.options.type = PTHREAD_MUTEX_RECURSIVE;
+ break;
+ case 3:
+ /* firstfit fall thru */
+ case 7:
+ mutex->mtxopts.options.type = PTHREAD_MUTEX_DEFAULT;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ mutex->prioceiling = _PTHREAD_DEFAULT_PRIOCEILING;
+ mutex->mtxopts.options.protocol = _PTHREAD_DEFAULT_PROTOCOL;
+ if (static_type != 3) {
+ mutex->mtxopts.options.policy = _PTHREAD_MUTEX_POLICY_FAIRSHARE;
+ } else {
+ mutex->mtxopts.options.policy = _PTHREAD_MUTEX_POLICY_FIRSTFIT;
+ }
+ mutex->mtxopts.options.pshared = _PTHREAD_DEFAULT_PSHARED;
+ }
+
+ mutex->mtxopts.options.notify = 0;
+ mutex->mtxopts.options.unused = 0;
+ mutex->mtxopts.options.hold = 0;
+ mutex->mtxopts.options.mutex = 1;
+ mutex->mtxopts.options.lock_count = 0;
+
+ mutex->m_tid[0] = 0;
+ mutex->m_tid[1] = 0;
+ mutex->m_seq[0] = 0;
+ mutex->m_seq[1] = 0;
+ mutex->m_seq[2] = 0;
+ mutex->prioceiling = 0;
+ mutex->priority = 0;
+
+ mutex->mtxopts.options.misalign = (((uintptr_t)&mutex->m_seq[0]) & 0x7) != 0;
+
+ // Ensure all contents are properly set before setting signature.
+ OSMemoryBarrier();
+
+ mutex->sig = _PTHREAD_MUTEX_SIG;
+
+ return 0;
+}
+
+int
+pthread_mutex_destroy(pthread_mutex_t *omutex)
+{
+ _pthread_mutex *mutex = (_pthread_mutex *)omutex;
+
+ int res = EINVAL;
+
+ LOCK(mutex->lock);
+ if (mutex->sig == _PTHREAD_MUTEX_SIG) {
+ uint32_t lgenval, ugenval;
+ uint64_t oldval64;
+ volatile uint64_t *seqaddr;
+ MUTEX_GETSEQ_ADDR(mutex, &seqaddr);
+ volatile uint64_t *tidaddr;
+ MUTEX_GETTID_ADDR(mutex, &tidaddr);
+
+ oldval64 = *seqaddr;
+ lgenval = (uint32_t)oldval64;
+ ugenval = (uint32_t)(oldval64 >> 32);
+ if ((*tidaddr == (uint64_t)0) &&
+ ((lgenval & PTHRW_COUNT_MASK) == (ugenval & PTHRW_COUNT_MASK))) {
+ mutex->sig = _PTHREAD_NO_SIG;
+ res = 0;
+ } else {
+ res = EBUSY;
+ }
+ } else if ((mutex->sig & _PTHREAD_MUTEX_SIG_init_MASK ) == _PTHREAD_MUTEX_SIG_CMP) {
+ mutex->sig = _PTHREAD_NO_SIG;
+ res = 0;
+ }
+ UNLOCK(mutex->lock);
+
+ return res;
+}
+
+#endif /* !BUILDING_VARIANT ] */
+
+/*
+ * Destroy a mutex attribute structure.
+ */
+int
+pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
+{
+#if __DARWIN_UNIX03
+ if (__unix_conforming == 0) {
+ __unix_conforming = 1;
+ }
+ if (attr->sig != _PTHREAD_MUTEX_ATTR_SIG) {
+ return EINVAL;
+ }
+#endif /* __DARWIN_UNIX03 */
+
+ attr->sig = _PTHREAD_NO_SIG;
+ return 0;
+}
+
+
--- /dev/null
+/*
+ * Copyright (c) 2000-2003, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*-
+ * Copyright (c) 1998 Alex Nash
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/lib/libc_r/uthread/uthread_rwlock.c,v 1.6 2001/04/10 04:19:20 deischen Exp $
+ */
+
+/*
+ * POSIX Pthread Library
+ * -- Read Write Lock support
+ * 4/24/02: A. Ramesh
+ * Ported from FreeBSD
+ */
+
+#include "internal.h"
+#include <stdio.h> /* For printf(). */
+
+extern int __unix_conforming;
+
+#ifdef PLOCKSTAT
+#include "plockstat.h"
+#else /* !PLOCKSTAT */
+#define PLOCKSTAT_RW_ERROR(x, y, z)
+#define PLOCKSTAT_RW_BLOCK(x, y)
+#define PLOCKSTAT_RW_BLOCKED(x, y, z)
+#define PLOCKSTAT_RW_ACQUIRE(x, y)
+#define PLOCKSTAT_RW_RELEASE(x, y)
+#endif /* PLOCKSTAT */
+
+#define READ_LOCK_PLOCKSTAT 0
+#define WRITE_LOCK_PLOCKSTAT 1
+
+#define BLOCK_FAIL_PLOCKSTAT 0
+#define BLOCK_SUCCESS_PLOCKSTAT 1
+
+/* maximum number of times a read lock may be obtained */
+#define MAX_READ_LOCKS (INT_MAX - 1)
+
+#include <platform/string.h>
+#include <platform/compat.h>
+
+__private_extern__ int __pthread_rwlock_init(_pthread_rwlock *rwlock, const pthread_rwlockattr_t *attr);
+__private_extern__ void _pthread_rwlock_updateval(_pthread_rwlock *rwlock, uint32_t updateval);
+
+static void
+RWLOCK_GETSEQ_ADDR(_pthread_rwlock *rwlock,
+ volatile uint32_t **lcntaddr,
+ volatile uint32_t **ucntaddr,
+ volatile uint32_t **seqaddr)
+{
+ if (rwlock->pshared == PTHREAD_PROCESS_SHARED) {
+ if (rwlock->misalign) {
+ *lcntaddr = &rwlock->rw_seq[1];
+ *seqaddr = &rwlock->rw_seq[2];
+ *ucntaddr = &rwlock->rw_seq[3];
+ } else {
+ *lcntaddr = &rwlock->rw_seq[0];
+ *seqaddr = &rwlock->rw_seq[1];
+ *ucntaddr = &rwlock->rw_seq[2];
+ }
+ } else {
+ *lcntaddr = rwlock->rw_lcntaddr;
+ *seqaddr = rwlock->rw_seqaddr;
+ *ucntaddr = rwlock->rw_ucntaddr;
+ }
+}
+
+#ifndef BUILDING_VARIANT /* [ */
+static uint32_t modbits(uint32_t lgenval, uint32_t updateval, uint32_t savebits);
+
+int
+pthread_rwlockattr_init(pthread_rwlockattr_t *attr)
+{
+ attr->sig = _PTHREAD_RWLOCK_ATTR_SIG;
+ attr->pshared = _PTHREAD_DEFAULT_PSHARED;
+ return 0;
+}
+
+int
+pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr)
+{
+ attr->sig = _PTHREAD_NO_SIG;
+ attr->pshared = 0;
+ return 0;
+}
+
+int
+pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *attr, int *pshared)
+{
+ int res = EINVAL;
+ if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG) {
+ *pshared = (int)attr->pshared;
+ res = 0;
+ }
+ return res;
+}
+
+int
+pthread_rwlockattr_setpshared(pthread_rwlockattr_t * attr, int pshared)
+{
+ int res = EINVAL;
+ if (attr->sig == _PTHREAD_RWLOCK_ATTR_SIG) {
+#if __DARWIN_UNIX03
+ if (( pshared == PTHREAD_PROCESS_PRIVATE) || (pshared == PTHREAD_PROCESS_SHARED))
+#else /* __DARWIN_UNIX03 */
+ if ( pshared == PTHREAD_PROCESS_PRIVATE)
+#endif /* __DARWIN_UNIX03 */
+ {
+ attr->pshared = pshared ;
+ res = 0;
+ }
+ }
+ return res;
+}
+
+__private_extern__ int
+__pthread_rwlock_init(_pthread_rwlock *rwlock, const pthread_rwlockattr_t *attr)
+{
+ // Force RWLOCK_GETSEQ_ADDR to calculate addresses by setting pshared.
+ rwlock->pshared = PTHREAD_PROCESS_SHARED;
+ rwlock->misalign = (((uintptr_t)&rwlock->rw_seq[0]) & 0x7) != 0;
+ RWLOCK_GETSEQ_ADDR(rwlock, &rwlock->rw_lcntaddr, &rwlock->rw_ucntaddr, &rwlock->rw_seqaddr);
+ *rwlock->rw_lcntaddr = PTHRW_RWLOCK_INIT;
+ *rwlock->rw_seqaddr = PTHRW_RWS_INIT;
+ *rwlock->rw_ucntaddr = 0;
+
+ if (attr != NULL && attr->pshared == PTHREAD_PROCESS_SHARED) {
+ rwlock->pshared = PTHREAD_PROCESS_SHARED;
+ rwlock->rw_flags = PTHRW_KERN_PROCESS_SHARED;
+ } else {
+ rwlock->pshared = _PTHREAD_DEFAULT_PSHARED;
+ rwlock->rw_flags = PTHRW_KERN_PROCESS_PRIVATE;
+ }
+
+ rwlock->rw_owner = NULL;
+ bzero(rwlock->_reserved, sizeof(rwlock->_reserved));
+
+ // Ensure all contents are properly set before setting signature.
+ OSMemoryBarrier();
+ rwlock->sig = _PTHREAD_RWLOCK_SIG;
+
+ return 0;
+}
+
+static uint32_t
+modbits(uint32_t lgenval, uint32_t updateval, uint32_t savebits)
+{
+ uint32_t lval = lgenval & PTHRW_BIT_MASK;
+ uint32_t uval = updateval & PTHRW_BIT_MASK;
+ uint32_t rval, nlval;
+
+ nlval = (lval | uval) & ~(PTH_RWL_MBIT);
+
+ /* reconcile bits on the lock with what kernel needs to set */
+ if ((uval & PTH_RWL_KBIT) == 0 && (lval & PTH_RWL_WBIT) == 0) {
+ nlval &= ~PTH_RWL_KBIT;
+ }
+
+ if (savebits != 0) {
+ if ((savebits & PTH_RWS_WSVBIT) != 0 && (nlval & PTH_RWL_WBIT) == 0 && (nlval & PTH_RWL_EBIT) == 0) {
+ nlval |= (PTH_RWL_WBIT | PTH_RWL_KBIT);
+ }
+ }
+ rval = (lgenval & PTHRW_COUNT_MASK) | nlval;
+ return(rval);
+}
+
+__private_extern__ void
+_pthread_rwlock_updateval(_pthread_rwlock *rwlock, uint32_t updateval)
+{
+ bool isoverlap = (updateval & PTH_RWL_MBIT) != 0;
+
+ uint64_t oldval64, newval64;
+ volatile uint32_t *lcntaddr, *ucntaddr, *seqaddr;
+
+ /* TBD: restore U bit */
+ RWLOCK_GETSEQ_ADDR(rwlock, &lcntaddr, &ucntaddr, &seqaddr);
+
+ do {
+ uint32_t lcntval = *lcntaddr;
+ uint32_t rw_seq = *seqaddr;
+
+ uint32_t newval, newsval;
+ if (isoverlap || is_rws_setunlockinit(rw_seq) != 0) {
+ // Set S word to the specified value
+ uint32_t savebits = (rw_seq & PTHRW_RWS_SAVEMASK);
+ newval = modbits(lcntval, updateval, savebits);
+ newsval = rw_seq + (updateval & PTHRW_COUNT_MASK);
+ if (!isoverlap) {
+ newsval &= PTHRW_COUNT_MASK;
+ }
+ newsval &= ~PTHRW_RWS_SAVEMASK;
+ } else {
+ newval = lcntval;
+ newsval = rw_seq;
+ }
+
+ oldval64 = (((uint64_t)rw_seq) << 32);
+ oldval64 |= lcntval;
+ newval64 = (((uint64_t)newsval) << 32);
+ newval64 |= newval;
+ } while (OSAtomicCompareAndSwap64Barrier(oldval64, newval64, (volatile int64_t *)lcntaddr) != TRUE);
+}
+
+#endif /* !BUILDING_VARIANT ] */
+
+static int
+_pthread_rwlock_check_busy(_pthread_rwlock *rwlock)
+{
+ int res = 0;
+
+ volatile uint32_t *lcntaddr, *ucntaddr, *seqaddr;
+
+ RWLOCK_GETSEQ_ADDR(rwlock, &lcntaddr, &ucntaddr, &seqaddr);
+
+ uint32_t rw_lcnt = *lcntaddr;
+ uint32_t rw_ucnt = *ucntaddr;
+
+ if ((rw_lcnt & PTHRW_COUNT_MASK) != rw_ucnt) {
+ res = EBUSY;
+ }
+
+ return res;
+}
+
+int
+pthread_rwlock_destroy(pthread_rwlock_t *orwlock)
+{
+ int res = 0;
+ _pthread_rwlock *rwlock = (_pthread_rwlock *)orwlock;
+
+ if (rwlock->sig == _PTHREAD_RWLOCK_SIG) {
+#if __DARWIN_UNIX03
+ res = _pthread_rwlock_check_busy(rwlock);
+#endif /* __DARWIN_UNIX03 */
+ } else if (rwlock->sig != _PTHREAD_RWLOCK_SIG_init) {
+ res = EINVAL;
+ }
+ if (res == 0) {
+ rwlock->sig = _PTHREAD_NO_SIG;
+ }
+ return res;
+}
+
+
+int
+pthread_rwlock_init(pthread_rwlock_t *orwlock, const pthread_rwlockattr_t *attr)
+{
+ int res = 0;
+ _pthread_rwlock *rwlock = (_pthread_rwlock *)orwlock;
+
+#if __DARWIN_UNIX03
+ if (attr && attr->sig != _PTHREAD_RWLOCK_ATTR_SIG) {
+ res = EINVAL;
+ }
+
+ if (res == 0 && rwlock->sig == _PTHREAD_RWLOCK_SIG) {
+ res = _pthread_rwlock_check_busy(rwlock);
+ }
+#endif
+ if (res == 0) {
+ LOCK_INIT(rwlock->lock);
+ res = __pthread_rwlock_init(rwlock, attr);
+ }
+ return res;
+}
+
+static int
+_pthread_rwlock_check_init(pthread_rwlock_t *orwlock)
+{
+ int res = 0;
+ _pthread_rwlock *rwlock = (_pthread_rwlock *)orwlock;
+ if (rwlock->sig != _PTHREAD_RWLOCK_SIG) {
+ res = EINVAL;
+ if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
+ LOCK(rwlock->lock);
+ if (rwlock->sig == _PTHREAD_RWLOCK_SIG_init) {
+ res = __pthread_rwlock_init(rwlock, NULL);
+ } else if (rwlock->sig == _PTHREAD_RWLOCK_SIG){
+ res = 0;
+ }
+ UNLOCK(rwlock->lock);
+ }
+ if (res != 0) {
+ PLOCKSTAT_RW_ERROR(orwlock, READ_LOCK_PLOCKSTAT, res);
+ }
+ }
+ return res;
+}
+
+static int
+_pthread_rwlock_lock(pthread_rwlock_t *orwlock, bool readlock, bool trylock)
+{
+ int res;
+ _pthread_rwlock *rwlock = (_pthread_rwlock *)orwlock;
+
+ res = _pthread_rwlock_check_init(orwlock);
+ if (res != 0) {
+ return res;
+ }
+
+ uint64_t oldval64, newval64;
+ volatile uint32_t *lcntaddr, *ucntaddr, *seqaddr;
+ RWLOCK_GETSEQ_ADDR(rwlock, &lcntaddr, &ucntaddr, &seqaddr);
+
+ uint32_t newval, newsval;
+ uint32_t lcntval, ucntval, rw_seq;
+
+ bool gotlock;
+ bool retry;
+ int retry_count = 0;
+
+ do {
+ res = 0;
+ retry = false;
+
+ lcntval = *lcntaddr;
+ ucntval = *ucntaddr;
+ rw_seq = *seqaddr;
+
+#if __DARWIN_UNIX03
+ if (is_rwl_ebit_set(lcntval)) {
+ if (rwlock->rw_owner == pthread_self()) {
+ res = EDEADLK;
+ break;
+ }
+ }
+#endif /* __DARWIN_UNIX03 */
+
+ oldval64 = (((uint64_t)rw_seq) << 32);
+ oldval64 |= lcntval;
+
+ /* if l bit is on or u and k bit is clear, acquire lock in userland */
+ if (readlock) {
+ gotlock = can_rwl_readinuser(lcntval);
+ } else {
+ gotlock = (lcntval & PTH_RWL_RBIT) != 0;
+ }
+
+ uint32_t bits = 0;
+ uint32_t mask = ~0ul;
+
+ newval = lcntval + PTHRW_INC;
+
+ if (gotlock) {
+ if (readlock) {
+ if (diff_genseq(lcntval, ucntval) >= PTHRW_MAX_READERS) {
+ /* since ucntval may be newer, just redo */
+ retry_count++;
+ if (retry_count > 1024) {
+ res = EAGAIN;
+ break;
+ } else {
+ sched_yield();
+ retry = true;
+ continue;
+ }
+ }
+
+ // Need to update L (remove R bit) and S word
+ mask = PTH_RWLOCK_RESET_RBIT;
+ } else {
+ mask = PTHRW_COUNT_MASK;
+ bits = PTH_RWL_IBIT | PTH_RWL_KBIT | PTH_RWL_EBIT;
+ }
+ newsval = rw_seq + PTHRW_INC;
+ } else if (trylock) {
+ res = EBUSY;
+ break;
+ } else {
+ if (readlock) {
+ // Need to block in kernel. Remove R bit.
+ mask = PTH_RWLOCK_RESET_RBIT;
+ } else {
+ bits = PTH_RWL_KBIT | PTH_RWL_WBIT;
+ }
+ newsval = rw_seq;
+ if (is_rws_setseq(rw_seq)) {
+ newsval &= PTHRW_SW_Reset_BIT_MASK;
+ newsval |= (newval & PTHRW_COUNT_MASK);
+ }
+ }
+ newval = (newval & mask) | bits;
+ newval64 = (((uint64_t)newsval) << 32);
+ newval64 |= newval;
+
+ } while (retry || OSAtomicCompareAndSwap64Barrier(oldval64, newval64, (volatile int64_t *)lcntaddr) != TRUE);
+
+#ifdef PLOCKSTAT
+ int plockstat = readlock ? READ_LOCK_PLOCKSTAT : WRITE_LOCK_PLOCKSTAT;
+#endif
+
+ // Unable to acquire in userland, transition to kernel.
+ if (res == 0 && !gotlock) {
+ uint32_t updateval;
+
+ PLOCKSTAT_RW_BLOCK(orwlock, plockstat);
+
+ do {
+ if (readlock) {
+ updateval = __psynch_rw_rdlock(orwlock, newval, ucntval, newsval, rwlock->rw_flags);
+ } else {
+ updateval = __psynch_rw_wrlock(orwlock, newval, ucntval, newsval, rwlock->rw_flags);
+ }
+ if (updateval == (uint32_t)-1) {
+ res = errno;
+ } else {
+ res = 0;
+ }
+ } while (res == EINTR);
+
+ if (res == 0) {
+ _pthread_rwlock_updateval(rwlock, updateval);
+ PLOCKSTAT_RW_BLOCKED(orwlock, plockstat, BLOCK_SUCCESS_PLOCKSTAT);
+ } else {
+ PLOCKSTAT_RW_BLOCKED(orwlock, plockstat, BLOCK_FAIL_PLOCKSTAT);
+ uint64_t myid;
+ (void)pthread_threadid_np(pthread_self(), &myid);
+ PTHREAD_ABORT("kernel lock returned unknown error %x with tid %x\n", updateval, (uint32_t)myid);
+ }
+ }
+
+ if (res == 0) {
+#if __DARWIN_UNIX03
+ if (!readlock) {
+ rwlock->rw_owner = pthread_self();
+ }
+#endif /* __DARWIN_UNIX03 */
+ PLOCKSTAT_RW_ACQUIRE(orwlock, plockstat);
+ } else {
+ PLOCKSTAT_RW_ERROR(orwlock, plockstat, res);
+ }
+
+ return res;
+}
+
+int
+pthread_rwlock_rdlock(pthread_rwlock_t *orwlock)
+{
+ // read lock, no try
+ return _pthread_rwlock_lock(orwlock, true, false);
+}
+
+int
+pthread_rwlock_tryrdlock(pthread_rwlock_t *orwlock)
+{
+ // read lock, try lock
+ return _pthread_rwlock_lock(orwlock, true, true);
+}
+
+int
+pthread_rwlock_wrlock(pthread_rwlock_t *orwlock)
+{
+ // write lock, no try
+ return _pthread_rwlock_lock(orwlock, false, false);
+}
+
+int
+pthread_rwlock_trywrlock(pthread_rwlock_t *orwlock)
+{
+ // write lock, try lock
+ return _pthread_rwlock_lock(orwlock, false, true);
+}
+
+int
+pthread_rwlock_unlock(pthread_rwlock_t *orwlock)
+{
+ int res;
+ _pthread_rwlock *rwlock = (_pthread_rwlock *)orwlock;
+#ifdef PLOCKSTAT
+ int wrlock = 0;
+#endif
+
+ res = _pthread_rwlock_check_init(orwlock);
+ if (res != 0) {
+ return res;
+ }
+
+ uint64_t oldval64 = 0, newval64 = 0;
+ volatile uint32_t *lcntaddr, *ucntaddr, *seqaddr;
+ RWLOCK_GETSEQ_ADDR(rwlock, &lcntaddr, &ucntaddr, &seqaddr);
+
+ bool droplock;
+ bool reload;
+ bool incr_ucnt = true;
+ bool check_spurious = true;
+ uint32_t lcntval, ucntval, rw_seq, ulval = 0, newval, newsval;
+
+ do {
+ reload = false;
+ droplock = true;
+
+ lcntval = *lcntaddr;
+ ucntval = *ucntaddr;
+ rw_seq = *seqaddr;
+
+ oldval64 = (((uint64_t)rw_seq) << 32);
+ oldval64 |= lcntval;
+
+ // check for spurious unlocks
+ if (check_spurious) {
+ if ((lcntval & PTH_RWL_RBIT) != 0) {
+ droplock = false;
+
+ newval64 = oldval64;
+ continue;
+ }
+ check_spurious = false;
+ }
+
+ if (is_rwl_ebit_set(lcntval)) {
+#ifdef PLOCKSTAT
+ wrlock = 1;
+#endif
+#if __DARWIN_UNIX03
+ rwlock->rw_owner = NULL;
+#endif /* __DARWIN_UNIX03 */
+ }
+
+ // update U
+ if (incr_ucnt) {
+ ulval = (ucntval + PTHRW_INC);
+ incr_ucnt = (OSAtomicCompareAndSwap32Barrier(ucntval, ulval, (volatile int32_t *)ucntaddr) != TRUE);
+ newval64 = oldval64;
+ reload = true;
+ continue;
+ }
+
+ // last unlock, note U is already updated ?
+ if ((lcntval & PTHRW_COUNT_MASK) == (ulval & PTHRW_COUNT_MASK)) {
+ /* Set L with R and init bits and set S to L */
+ newval = (lcntval & PTHRW_COUNT_MASK)| PTHRW_RWLOCK_INIT;
+ newsval = (lcntval & PTHRW_COUNT_MASK)| PTHRW_RWS_INIT;
+
+ droplock = false;
+ } else {
+ /* if it is not exclusive or no Writer/yield pending, skip */
+ if ((lcntval & (PTH_RWL_EBIT | PTH_RWL_WBIT | PTH_RWL_KBIT)) == 0) {
+ droplock = false;
+ break;
+ }
+
+ /* kernel transition needed? */
+ /* U+1 == S? */
+ if ((ulval + PTHRW_INC) != (rw_seq & PTHRW_COUNT_MASK)) {
+ droplock = false;
+ break;
+ }
+
+ /* reset all bits and set k */
+ newval = (lcntval & PTHRW_COUNT_MASK) | PTH_RWL_KBIT;
+ /* set I bit on S word */
+ newsval = rw_seq | PTH_RWS_IBIT;
+ if ((lcntval & PTH_RWL_WBIT) != 0) {
+ newsval |= PTH_RWS_WSVBIT;
+ }
+ }
+
+ newval64 = (((uint64_t)newsval) << 32);
+ newval64 |= newval;
+
+ } while (OSAtomicCompareAndSwap64Barrier(oldval64, newval64, (volatile int64_t *)lcntaddr) != TRUE || reload);
+
+ if (droplock) {
+ uint32_t updateval;
+ do {
+ updateval = __psynch_rw_unlock(orwlock, lcntval, ulval, newsval, rwlock->rw_flags);
+ if (updateval == (uint32_t)-1) {
+ res = errno;
+ } else {
+ res = 0;
+ }
+ } while (res == EINTR);
+
+ if (res != 0) {
+ uint64_t myid = 0;
+ (void)pthread_threadid_np(pthread_self(), &myid);
+ PTHREAD_ABORT("rwunlock from kernel with unknown error %x: tid %x\n", res, (uint32_t)myid);
+ }
+ }
+
+ PLOCKSTAT_RW_RELEASE(orwlock, wrlock);
+
+ return res;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#include "internal.h"
+#include <dlfcn.h>
+#include <_simple.h>
+#include <CrashReporterClient.h>
+
+#define __SIGABRT 6
+
+/* We should move abort() into Libsyscall, if possible. */
+int __getpid(void);
+
+PTHREAD_NORETURN int
+__kill(int pid, int signum, int posix);
+
+void
+__pthread_abort(void)
+{
+ PTHREAD_NORETURN void (*_libc_abort)(void);
+ _libc_abort = dlsym(RTLD_DEFAULT, "abort");
+
+ if (_libc_abort) {
+ _libc_abort();
+ } else {
+ __kill(__getpid(), __SIGABRT, 0);
+ }
+}
+
+void
+__pthread_abort_reason(const char *fmt, ...)
+{
+#if !TARGET_OS_EMBEDDED
+ va_list ap;
+ const char *str = fmt;
+ _SIMPLE_STRING s = _simple_salloc();
+ va_start(ap, fmt);
+ if (_simple_vsprintf(s, fmt, ap) == 0) {
+ str = _simple_string(s);
+ }
+ CRSetCrashLogMessage(str);
+ va_end(ap);
+#endif
+ __pthread_abort();
+}
--- /dev/null
+/*
+ * Copyright (c) 2000-2003, 2007, 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * MkLinux
+ */
+
+/*
+ * POSIX Pthread Library
+ * Thread Specific Data support
+ * NB: pthread_getspecific() is in a separate assembly file
+ */
+
+#include "internal.h"
+#include <TargetConditionals.h>
+
+#if !VARIANT_DYLD
+// __pthread_tsd_first is first static key managed by libpthread.
+// __pthread_tsd_max is the (observed) end of static key destructors.
+// __pthread_tsd_start is the start of dynamic keys.
+// __pthread_tsd_end is the end of dynamic keys.
+
+static const int __pthread_tsd_first = __TSD_RESERVED_MAX + 1;
+static int __pthread_tsd_max = __pthread_tsd_first;
+static const int __pthread_tsd_start = _INTERNAL_POSIX_THREAD_KEYS_MAX;
+static const int __pthread_tsd_end = _INTERNAL_POSIX_THREAD_KEYS_END;
+
+// Omit support for pthread key destructors in the static archive for dyld.
+// dyld does not create and destroy threads so these are not necessary.
+//
+// We store the bit-wise negation of the destructor so that a quick non-zero
+// test can be used to determine if the destructor has been set, even if it is
+// NULL. This means that a destructor of value ~0x0ull cannot be used. That
+// shouldn't be a problem in practice since it isn't a valid function address.
+
+static struct {
+ uintptr_t destructor;
+} _pthread_keys[_INTERNAL_POSIX_THREAD_KEYS_END];
+
+static pthread_lock_t tsd_lock = LOCK_INITIALIZER;
+
+// Returns true if successful, false if destructor was already set.
+static bool
+_pthread_key_set_destructor(pthread_key_t key, void (*destructor)(void *))
+{
+ uintptr_t *ptr = &_pthread_keys[key].destructor;
+ uintptr_t value = ~(uintptr_t)destructor;
+ if (*ptr == 0) {
+ *ptr = value;
+ return true;
+ }
+ return false;
+}
+
+// Returns true if successful, false if the destructor was not set.
+static bool
+_pthread_key_unset_destructor(pthread_key_t key)
+{
+ uintptr_t *ptr = &_pthread_keys[key].destructor;
+ if (*ptr != 0) {
+ *ptr = 0;
+ return true;
+ }
+ return false;
+}
+
+// Returns true if successful, false if the destructor was not set.
+static bool
+_pthread_key_get_destructor(pthread_key_t key, void (**destructor)(void *))
+{
+ uintptr_t value = _pthread_keys[key].destructor;
+ if (destructor) {
+ *destructor = (void (*)(void *))(~value);
+ }
+ return (value != 0);
+}
+
+int
+pthread_key_create(pthread_key_t *key, void (*destructor)(void *))
+{
+ int res = EAGAIN; // Returns EAGAIN if key cannot be allocated.
+ pthread_key_t k;
+
+ LOCK(tsd_lock);
+ for (k = __pthread_tsd_start; k < __pthread_tsd_end; k++) {
+ if (_pthread_key_set_destructor(k, destructor)) {
+ *key = k;
+ res = 0;
+ break;
+ }
+ }
+ UNLOCK(tsd_lock);
+
+ return res;
+}
+
+int
+pthread_key_delete(pthread_key_t key)
+{
+ int res = EINVAL; // Returns EINVAL if key is not allocated.
+
+ LOCK(tsd_lock);
+ if (key >= __pthread_tsd_start && key < __pthread_tsd_end) {
+ if (_pthread_key_unset_destructor(key)) {
+ struct _pthread *p;
+ LOCK(_pthread_list_lock);
+ TAILQ_FOREACH(p, &__pthread_head, plist) {
+ // No lock for word-sized write.
+ p->tsd[key] = 0;
+ }
+ UNLOCK(_pthread_list_lock);
+ res = 0;
+ }
+ }
+ UNLOCK(tsd_lock);
+
+ return res;
+}
+#endif // !VARIANT_DYLD
+
+int
+pthread_setspecific(pthread_key_t key, const void *value)
+{
+ int res = EINVAL;
+
+#if !VARIANT_DYLD
+ if (key >= __pthread_tsd_first && key < __pthread_tsd_end) {
+ bool created = _pthread_key_get_destructor(key, NULL);
+ if (key < __pthread_tsd_start || created) {
+ struct _pthread *self = pthread_self();
+ self->tsd[key] = (void *)value;
+ res = 0;
+
+ if (key < __pthread_tsd_start) {
+ // XXX: is this really necessary?
+ _pthread_key_set_destructor(key, NULL);
+ }
+ if (key > self->max_tsd_key) {
+ self->max_tsd_key = (int)key;
+ }
+ }
+ }
+#endif // !VARIANT_DYLD
+
+ return res;
+}
+
+void*
+pthread_getspecific(pthread_key_t key)
+{
+ return _pthread_getspecific_direct(key);
+}
+
+#if !VARIANT_DYLD
+static void
+_pthread_tsd_cleanup_key(pthread_t self, pthread_key_t key)
+{
+ void (*destructor)(void *);
+ if (_pthread_key_get_destructor(key, &destructor)) {
+ void **ptr = &self->tsd[key];
+ void *value = *ptr;
+ if (value) {
+ *ptr = NULL;
+ if (destructor) {
+ destructor(value);
+ }
+ }
+ }
+}
+#endif // !VARIANT_DYLD
+
+void
+_pthread_tsd_cleanup(pthread_t self)
+{
+#if !VARIANT_DYLD
+ int j;
+
+ // clean up dynamic keys first
+ for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) {
+ pthread_key_t k;
+ for (k = __pthread_tsd_start; k <= self->max_tsd_key; k++) {
+ _pthread_tsd_cleanup_key(self, k);
+ }
+ }
+
+ self->max_tsd_key = 0;
+
+ // clean up static keys
+ for (j = 0; j < PTHREAD_DESTRUCTOR_ITERATIONS; j++) {
+ pthread_key_t k;
+ for (k = __pthread_tsd_first; k <= __pthread_tsd_max; k++) {
+ _pthread_tsd_cleanup_key(self, k);
+ }
+ }
+#endif // !VARIANT_DYLD
+}
+
+#if !VARIANT_DYLD
+// XXX: key should be pthread_key_t
+int
+pthread_key_init_np(int key, void (*destructor)(void *))
+{
+ int res = EINVAL; // Returns EINVAL if key is out of range.
+ if (key >= __pthread_tsd_first && key < __pthread_tsd_start) {
+ LOCK(tsd_lock);
+ _pthread_key_set_destructor(key, destructor);
+ if (key > __pthread_tsd_max) {
+ __pthread_tsd_max = key;
+ }
+ UNLOCK(tsd_lock);
+ res = 0;
+ }
+ return res;
+}
+#endif // !VARIANT_DYLD
+
+#undef pthread_self
+pthread_t
+pthread_self(void)
+{
+ return _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_SELF);
+}
--- /dev/null
+/*
+ * Copyright (c) 2013 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#include "internal.h"
+
+#include <_simple.h>
+#include <mach/mach_vm.h>
+#include <unistd.h>
+#include <spawn.h>
+#include <spawn_private.h>
+#include <sys/spawn_internal.h>
+
+// TODO: remove me when internal.h can include *_private.h itself
+#include "workqueue_private.h"
+#include "qos_private.h"
+
+static pthread_priority_t _main_qos = QOS_CLASS_UNSPECIFIED;
+
+#define PTHREAD_OVERRIDE_SIGNATURE (0x6f766572)
+#define PTHREAD_OVERRIDE_SIG_DEAD (0x7265766f)
+
+struct pthread_override_s
+{
+ uint32_t sig;
+ pthread_t pthread;
+ mach_port_t kthread;
+ pthread_priority_t priority;
+ bool malloced;
+};
+
+void
+_pthread_set_main_qos(pthread_priority_t qos)
+{
+ _main_qos = qos;
+}
+
+int
+pthread_attr_set_qos_class_np(pthread_attr_t *__attr,
+ qos_class_t __qos_class,
+ int __relative_priority)
+{
+ if (!(__pthread_supported_features & PTHREAD_FEATURE_BSDTHREADCTL)) {
+ return ENOTSUP;
+ }
+
+ if (__relative_priority > 0 || __relative_priority < QOS_MIN_RELATIVE_PRIORITY) {
+ return EINVAL;
+ }
+
+ int ret = EINVAL;
+ if (__attr->sig == _PTHREAD_ATTR_SIG) {
+ if (!__attr->schedset) {
+ __attr->qosclass = _pthread_priority_make_newest(__qos_class, __relative_priority, 0);
+ __attr->qosset = 1;
+ ret = 0;
+ }
+ }
+
+ return ret;
+}
+
+int
+pthread_attr_get_qos_class_np(pthread_attr_t * __restrict __attr,
+ qos_class_t * __restrict __qos_class,
+ int * __restrict __relative_priority)
+{
+ if (!(__pthread_supported_features & PTHREAD_FEATURE_BSDTHREADCTL)) {
+ return ENOTSUP;
+ }
+
+ int ret = EINVAL;
+ if (__attr->sig == _PTHREAD_ATTR_SIG) {
+ if (__attr->qosset) {
+ qos_class_t qos; int relpri;
+ _pthread_priority_split_newest(__attr->qosclass, qos, relpri);
+
+ if (__qos_class) { *__qos_class = qos; }
+ if (__relative_priority) { *__relative_priority = relpri; }
+ } else {
+ if (__qos_class) { *__qos_class = 0; }
+ if (__relative_priority) { *__relative_priority = 0; }
+ }
+ ret = 0;
+ }
+
+ return ret;
+}
+
+int
+pthread_set_qos_class_self_np(qos_class_t __qos_class,
+ int __relative_priority)
+{
+ if (!(__pthread_supported_features & PTHREAD_FEATURE_BSDTHREADCTL)) {
+ return ENOTSUP;
+ }
+
+ if (__relative_priority > 0 || __relative_priority < QOS_MIN_RELATIVE_PRIORITY) {
+ return EINVAL;
+ }
+
+ pthread_priority_t priority = _pthread_priority_make_newest(__qos_class, __relative_priority, 0);
+
+ if (__pthread_supported_features & PTHREAD_FEATURE_SETSELF) {
+ return _pthread_set_properties_self(_PTHREAD_SET_SELF_QOS_FLAG, priority, 0);
+ } else {
+ /* We set the thread QoS class in the TSD and then call into the kernel to
+ * read the value out of it and set the QoS class.
+ */
+ _pthread_setspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS, priority);
+
+ mach_port_t kport = pthread_mach_thread_np(pthread_self());
+ int res = __bsdthread_ctl(BSDTHREAD_CTL_SET_QOS, kport, &pthread_self()->tsd[_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS], 0);
+
+ if (res == -1) {
+ res = errno;
+ }
+
+ return res;
+ }
+}
+
+int
+pthread_set_qos_class_np(pthread_t __pthread,
+ qos_class_t __qos_class,
+ int __relative_priority)
+{
+ if (!(__pthread_supported_features & PTHREAD_FEATURE_BSDTHREADCTL)) {
+ return ENOTSUP;
+ }
+
+ if (__relative_priority > 0 || __relative_priority < QOS_MIN_RELATIVE_PRIORITY) {
+ return EINVAL;
+ }
+
+ if (__pthread != pthread_self()) {
+ /* The kext now enforces this anyway, if we check here too, it allows us to call
+ * _pthread_set_properties_self later if we can.
+ */
+ return EPERM;
+ }
+
+ pthread_priority_t priority = _pthread_priority_make_newest(__qos_class, __relative_priority, 0);
+
+ if (__pthread_supported_features & PTHREAD_FEATURE_SETSELF) {
+ /* If we have _pthread_set_properties_self, then we can easily set this using that. */
+ return _pthread_set_properties_self(_PTHREAD_SET_SELF_QOS_FLAG, priority, 0);
+ } else {
+ /* We set the thread QoS class in the TSD and then call into the kernel to
+ * read the value out of it and set the QoS class.
+ */
+ if (__pthread == pthread_self()) {
+ _pthread_setspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS, priority);
+ } else {
+ __pthread->tsd[_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS] = priority;
+ }
+
+ mach_port_t kport = pthread_mach_thread_np(__pthread);
+ int res = __bsdthread_ctl(BSDTHREAD_CTL_SET_QOS, kport, &__pthread->tsd[_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS], 0);
+
+ if (res == -1) {
+ res = errno;
+ }
+
+ return res;
+ }
+}
+
+int
+pthread_get_qos_class_np(pthread_t __pthread,
+ qos_class_t * __restrict __qos_class,
+ int * __restrict __relative_priority)
+{
+ if (!(__pthread_supported_features & PTHREAD_FEATURE_BSDTHREADCTL)) {
+ return ENOTSUP;
+ }
+
+ pthread_priority_t priority;
+
+ if (__pthread == pthread_self()) {
+ priority = _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS);
+ } else {
+ priority = __pthread->tsd[_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS];
+ }
+
+ qos_class_t qos; int relpri;
+ _pthread_priority_split_newest(priority, qos, relpri);
+
+ if (__qos_class) { *__qos_class = qos; }
+ if (__relative_priority) { *__relative_priority = relpri; }
+
+ return 0;
+}
+
+qos_class_t
+qos_class_self(void)
+{
+ if (!(__pthread_supported_features & PTHREAD_FEATURE_BSDTHREADCTL)) {
+ return QOS_CLASS_UNSPECIFIED;
+ }
+
+ pthread_priority_t p = _pthread_getspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS);
+ qos_class_t c = _pthread_priority_get_qos_newest(p);
+
+ return c;
+}
+
+qos_class_t
+qos_class_main(void)
+{
+ return _pthread_priority_get_qos_newest(_main_qos);
+}
+
+pthread_priority_t
+_pthread_qos_class_encode(qos_class_t qos_class, int relative_priority, unsigned long flags)
+{
+ if ((__pthread_supported_features & PTHREAD_FEATURE_QOS_MAINTENANCE) == 0) {
+ return _pthread_priority_make_version2(qos_class, relative_priority, flags);
+ } else {
+ return _pthread_priority_make_newest(qos_class, relative_priority, flags);
+ }
+}
+
+qos_class_t
+_pthread_qos_class_decode(pthread_priority_t priority, int *relative_priority, unsigned long *flags)
+{
+ qos_class_t qos; int relpri;
+
+ if ((__pthread_supported_features & PTHREAD_FEATURE_QOS_MAINTENANCE) == 0) {
+ _pthread_priority_split_version2(priority, qos, relpri);
+ } else {
+ _pthread_priority_split_newest(priority, qos, relpri);
+ }
+
+ if (relative_priority) { *relative_priority = relpri; }
+ if (flags) { *flags = _pthread_priority_get_flags(priority); }
+ return qos;
+}
+
+pthread_priority_t
+_pthread_qos_class_encode_workqueue(int queue_priority, unsigned long flags)
+{
+ if ((__pthread_supported_features & PTHREAD_FEATURE_QOS_DEFAULT) == 0) {
+ switch (queue_priority) {
+ case WORKQ_HIGH_PRIOQUEUE:
+ return _pthread_priority_make_version1(QOS_CLASS_USER_INTERACTIVE, 0, flags);
+ case WORKQ_DEFAULT_PRIOQUEUE:
+ return _pthread_priority_make_version1(QOS_CLASS_USER_INITIATED, 0, flags);
+ case WORKQ_LOW_PRIOQUEUE:
+ case WORKQ_NON_INTERACTIVE_PRIOQUEUE:
+ return _pthread_priority_make_version1(QOS_CLASS_UTILITY, 0, flags);
+ case WORKQ_BG_PRIOQUEUE:
+ return _pthread_priority_make_version1(QOS_CLASS_BACKGROUND, 0, flags);
+ default:
+ __pthread_abort();
+ }
+ }
+
+ if ((__pthread_supported_features & PTHREAD_FEATURE_QOS_MAINTENANCE) == 0) {
+ switch (queue_priority) {
+ case WORKQ_HIGH_PRIOQUEUE:
+ return _pthread_priority_make_version2(QOS_CLASS_USER_INITIATED, 0, flags);
+ case WORKQ_DEFAULT_PRIOQUEUE:
+ return _pthread_priority_make_version2(QOS_CLASS_DEFAULT, 0, flags);
+ case WORKQ_LOW_PRIOQUEUE:
+ case WORKQ_NON_INTERACTIVE_PRIOQUEUE:
+ return _pthread_priority_make_version2(QOS_CLASS_UTILITY, 0, flags);
+ case WORKQ_BG_PRIOQUEUE:
+ return _pthread_priority_make_version2(QOS_CLASS_BACKGROUND, 0, flags);
+ /* Legacy dispatch does not use QOS_CLASS_MAINTENANCE, so no need to handle it here */
+ default:
+ __pthread_abort();
+ }
+ }
+
+ switch (queue_priority) {
+ case WORKQ_HIGH_PRIOQUEUE:
+ return _pthread_priority_make_newest(QOS_CLASS_USER_INITIATED, 0, flags);
+ case WORKQ_DEFAULT_PRIOQUEUE:
+ return _pthread_priority_make_newest(QOS_CLASS_DEFAULT, 0, flags);
+ case WORKQ_LOW_PRIOQUEUE:
+ case WORKQ_NON_INTERACTIVE_PRIOQUEUE:
+ return _pthread_priority_make_newest(QOS_CLASS_UTILITY, 0, flags);
+ case WORKQ_BG_PRIOQUEUE:
+ return _pthread_priority_make_newest(QOS_CLASS_BACKGROUND, 0, flags);
+ /* Legacy dispatch does not use QOS_CLASS_MAINTENANCE, so no need to handle it here */
+ default:
+ __pthread_abort();
+ }
+}
+
+int
+_pthread_set_properties_self(_pthread_set_flags_t flags, pthread_priority_t priority, mach_port_t voucher)
+{
+ if (!(__pthread_supported_features & PTHREAD_FEATURE_SETSELF)) {
+ return ENOTSUP;
+ }
+
+ int rv = __bsdthread_ctl(BSDTHREAD_CTL_SET_SELF, priority, voucher, flags);
+
+ /* Set QoS TSD if we succeeded or only failed the voucher half. */
+ if ((flags & _PTHREAD_SET_SELF_QOS_FLAG) != 0) {
+ if (rv == 0 || errno == ENOENT) {
+ _pthread_setspecific_direct(_PTHREAD_TSD_SLOT_PTHREAD_QOS_CLASS, priority);
+ }
+ }
+
+ if (rv) {
+ rv = errno;
+ }
+ return rv;
+}
+
+int
+pthread_set_fixedpriority_self(void)
+{
+ if (!(__pthread_supported_features & PTHREAD_FEATURE_BSDTHREADCTL)) {
+ return ENOTSUP;
+ }
+
+ if (__pthread_supported_features & PTHREAD_FEATURE_SETSELF) {
+ return _pthread_set_properties_self(_PTHREAD_SET_SELF_FIXEDPRIORITY_FLAG, 0, 0);
+ } else {
+ return ENOTSUP;
+ }
+}
+
+
+pthread_override_t
+pthread_override_qos_class_start_np(pthread_t __pthread, qos_class_t __qos_class, int __relative_priority)
+{
+ pthread_override_t rv;
+ kern_return_t kr;
+ int res = 0;
+
+ /* For now, we don't have access to malloc. So we'll have to vm_allocate this, which means the tiny struct is going
+ * to use an entire page.
+ */
+ bool did_malloc = true;
+
+ mach_vm_address_t vm_addr = malloc(sizeof(struct pthread_override_s));
+ if (!vm_addr) {
+ vm_addr = vm_page_size;
+ did_malloc = false;
+
+ kr = mach_vm_allocate(mach_task_self(), &vm_addr, round_page(sizeof(struct pthread_override_s)), VM_MAKE_TAG(VM_MEMORY_LIBDISPATCH) | VM_FLAGS_ANYWHERE);
+ if (kr != KERN_SUCCESS) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+
+ rv = (pthread_override_t)vm_addr;
+ rv->sig = PTHREAD_OVERRIDE_SIGNATURE;
+ rv->pthread = __pthread;
+ rv->kthread = pthread_mach_thread_np(__pthread);
+ rv->priority = _pthread_priority_make_newest(__qos_class, __relative_priority, 0);
+ rv->malloced = did_malloc;
+
+ /* To ensure that the kernel port that we keep stays valid, we retain it here. */
+ kr = mach_port_mod_refs(mach_task_self(), rv->kthread, MACH_PORT_RIGHT_SEND, 1);
+ if (kr != KERN_SUCCESS) {
+ res = EINVAL;
+ }
+
+ if (res == 0) {
+ res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_START, rv->kthread, rv->priority, 0);
+
+ if (res != 0) {
+ mach_port_mod_refs(mach_task_self(), rv->kthread, MACH_PORT_RIGHT_SEND, -1);
+ }
+ }
+
+ if (res != 0) {
+ if (did_malloc) {
+ free(rv);
+ } else {
+ mach_vm_deallocate(mach_task_self(), vm_addr, round_page(sizeof(struct pthread_override_s)));
+ }
+ rv = NULL;
+ }
+ return rv;
+}
+
+int
+pthread_override_qos_class_end_np(pthread_override_t override)
+{
+ kern_return_t kr;
+ int res = 0;
+
+ /* Double-free is a fault. Swap the signature and check the old one. */
+ if (__sync_swap(&override->sig, PTHREAD_OVERRIDE_SIG_DEAD) != PTHREAD_OVERRIDE_SIGNATURE) {
+ __builtin_trap();
+ }
+
+ override->sig = PTHREAD_OVERRIDE_SIG_DEAD;
+
+ /* Always consumes (and deallocates) the pthread_override_t object given. */
+ res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_END, override->kthread, 0, 0);
+ if (res == -1) { res = errno; }
+
+ /* EFAULT from the syscall means we underflowed. Crash here. */
+ if (res == EFAULT) {
+ // <rdar://problem/17645082> Disable the trap-on-underflow, it doesn't co-exist
+ // with dispatch resetting override counts on threads.
+ //__builtin_trap();
+ res = 0;
+ }
+
+ kr = mach_port_mod_refs(mach_task_self(), override->kthread, MACH_PORT_RIGHT_SEND, -1);
+ if (kr != KERN_SUCCESS) {
+ res = EINVAL;
+ }
+
+ if (override->malloced) {
+ free(override);
+ } else {
+ kr = mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)override, round_page(sizeof(struct pthread_override_s)));
+ if (kr != KERN_SUCCESS) {
+ res = EINVAL;
+ }
+ }
+
+ return res;
+}
+
+int
+_pthread_override_qos_class_start_direct(mach_port_t thread, pthread_priority_t priority)
+{
+ int res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_START, thread, priority, 0);
+ if (res == -1) { res = errno; }
+ return res;
+}
+
+int
+_pthread_override_qos_class_end_direct(mach_port_t thread)
+{
+ int res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_END, thread, 0, 0);
+ if (res == -1) { res = errno; }
+ return res;
+}
+
+int
+_pthread_workqueue_override_start_direct(mach_port_t thread, pthread_priority_t priority)
+{
+ int res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_DISPATCH, thread, priority, 0);
+ if (res == -1) { res = errno; }
+ return res;
+}
+
+int
+_pthread_workqueue_override_reset(void)
+{
+ int res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_RESET, 0, 0, 0);
+ if (res == -1) { res = errno; }
+ return res;
+}
+
+int
+posix_spawnattr_set_qos_class_np(posix_spawnattr_t * __restrict __attr, qos_class_t __qos_class)
+{
+ switch (__qos_class) {
+ case QOS_CLASS_UTILITY:
+ return posix_spawnattr_set_qos_clamp_np(__attr, POSIX_SPAWN_PROC_CLAMP_UTILITY);
+ case QOS_CLASS_BACKGROUND:
+ return posix_spawnattr_set_qos_clamp_np(__attr, POSIX_SPAWN_PROC_CLAMP_BACKGROUND);
+ case QOS_CLASS_MAINTENANCE:
+ return posix_spawnattr_set_qos_clamp_np(__attr, POSIX_SPAWN_PROC_CLAMP_MAINTENANCE);
+ default:
+ return EINVAL;
+ }
+}
+
+int
+posix_spawnattr_get_qos_class_np(const posix_spawnattr_t *__restrict __attr, qos_class_t * __restrict __qos_class)
+{
+ uint64_t clamp;
+
+ if (!__qos_class) {
+ return EINVAL;
+ }
+
+ int rv = posix_spawnattr_get_qos_clamp_np(__attr, &clamp);
+ if (rv != 0) {
+ return rv;
+ }
+
+ switch (clamp) {
+ case POSIX_SPAWN_PROC_CLAMP_UTILITY:
+ *__qos_class = QOS_CLASS_UTILITY;
+ break;
+ case POSIX_SPAWN_PROC_CLAMP_BACKGROUND:
+ *__qos_class = QOS_CLASS_BACKGROUND;
+ break;
+ case POSIX_SPAWN_PROC_CLAMP_MAINTENANCE:
+ *__qos_class = QOS_CLASS_MAINTENANCE;
+ break;
+ default:
+ *__qos_class = QOS_CLASS_UNSPECIFIED;
+ break;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000-2003, 2008, 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright 1996 1995 by Open Software Foundation, Inc. 1997 1996 1995 1994 1993 1992 1991
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appears in all copies and
+ * that both the copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE.
+ *
+ * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+/*
+ * MkLinux
+ */
+
+/*
+ * Machine specific support for thread initialization
+ */
+
+
+#include "internal.h"
+#include <platform/string.h>
+
+/*
+ * Set up the initial state of a MACH thread
+ */
+void
+_pthread_setup(pthread_t thread,
+ void (*routine)(pthread_t),
+ void *vsp,
+ int suspended,
+ int needresume)
+{
+#if defined(__i386__)
+ i386_thread_state_t state = {0};
+ thread_state_flavor_t flavor = x86_THREAD_STATE32;
+ mach_msg_type_number_t count = i386_THREAD_STATE_COUNT;
+#elif defined(__x86_64__)
+ x86_thread_state64_t state = {0};
+ thread_state_flavor_t flavor = x86_THREAD_STATE64;
+ mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
+#elif defined(__arm__)
+ arm_thread_state_t state = {0};
+ thread_state_flavor_t flavor = ARM_THREAD_STATE;
+ mach_msg_type_number_t count = ARM_THREAD_STATE_COUNT;
+#else
+#error _pthread_setup not defined for this architecture
+#endif
+
+ if (suspended) {
+ (void)thread_get_state(_pthread_kernel_thread(thread),
+ flavor,
+ (thread_state_t)&state,
+ &count);
+ }
+
+#if defined(__i386__)
+ uintptr_t *sp = vsp;
+
+ state.__eip = (uintptr_t)routine;
+
+ // We need to simulate a 16-byte aligned stack frame as if we had
+ // executed a call instruction. Since we're "pushing" one argument,
+ // we need to adjust the pointer by 12 bytes (3 * sizeof (int *))
+ sp -= 3; // make sure stack is aligned
+ *--sp = (uintptr_t)thread; // argument to function
+ *--sp = 0; // fake return address
+ state.__esp = (uintptr_t)sp; // set stack pointer
+#elif defined(__x86_64__)
+ uintptr_t *sp = vsp;
+
+ state.__rip = (uintptr_t)routine;
+
+ // We need to simulate a 16-byte aligned stack frame as if we had
+ // executed a call instruction. The stack should already be aligned
+ // before it comes to us and we don't need to push any arguments,
+ // so we shouldn't need to change it.
+ state.__rdi = (uintptr_t)thread; // argument to function
+ *--sp = 0; // fake return address
+ state.__rsp = (uintptr_t)sp; // set stack pointer
+#elif defined(__arm__)
+ state.__pc = (uintptr_t)routine;
+
+ // Detect switch to thumb mode.
+ if (state.__pc & 1) {
+ state.__pc &= ~1;
+ state.__cpsr |= 0x20; /* PSR_THUMB */
+ }
+
+ state.__sp = (uintptr_t)vsp - C_ARGSAVE_LEN - C_RED_ZONE;
+ state.__r[0] = (uintptr_t)thread;
+#else
+#error _pthread_setup not defined for this architecture
+#endif
+
+ if (suspended) {
+ (void)thread_set_state(_pthread_kernel_thread(thread), flavor, (thread_state_t)&state, count);
+ if (needresume) {
+ (void)thread_resume(_pthread_kernel_thread(thread));
+ }
+ } else {
+ mach_port_t kernel_thread;
+ (void)thread_create_running(mach_task_self(), flavor, (thread_state_t)&state, count, &kernel_thread);
+ _pthread_set_kernel_thread(thread, kernel_thread);
+ }
+}
+
+// pthread_setup initializes large structures to 0, which the compiler turns into a library call to memset. To avoid linking against
+// Libc, provide a simple wrapper that calls through to the libplatform primitives
+
+#undef memset
+__attribute__((visibility("hidden"))) void *
+memset(void *b, int c, size_t len)
+{
+ return _platform_memset(b, c, len);
+}
+
+#undef bzero
+__attribute__((visibility("hidden"))) void
+bzero(void *s, size_t n)
+{
+ _platform_bzero(s, n);
+}
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#define BUILDING_VARIANT 1
+#define VARIANT_CANCELABLE 1
+
+#undef __DARWIN_NON_CANCELABLE
+#define __DARWIN_NON_CANCELABLE 0
+
+#include "../pthread_cancelable.c"
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#include <TargetConditionals.h>
+#if defined(__i386__)
+
+#define BUILDING_VARIANT 1
+
+#undef __DARWIN_UNIX03
+#define __DARWIN_UNIX03 0
+
+#include "../pthread_cancelable.c"
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#include <TargetConditionals.h>
+#if defined(__i386__)
+
+#define BUILDING_VARIANT 1
+
+#undef __DARWIN_UNIX03
+#define __DARWIN_UNIX03 0
+
+#include "../pthread_cond.c"
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#include <TargetConditionals.h>
+#if defined(__i386__)
+
+#define BUILDING_VARIANT 1
+
+#undef __DARWIN_UNIX03
+#define __DARWIN_UNIX03 0
+
+#include "../pthread_mutex.c"
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2012 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#include <TargetConditionals.h>
+#if defined(__i386__)
+
+#define BUILDING_VARIANT 1
+
+#undef __DARWIN_UNIX03
+#define __DARWIN_UNIX03 0
+
+#include "../pthread_rwlock.c"
+
+#endif
--- /dev/null
+/*
+ * Copyright (c) 2003-2012 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 _PTHREAD_ATTR_T
+#define _PTHREAD_ATTR_T
+typedef __darwin_pthread_attr_t pthread_attr_t;
+#endif /* _PTHREAD_ATTR_T */
--- /dev/null
+/*
+ * Copyright (c) 2003-2012 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 _PTHREAD_COND_T
+#define _PTHREAD_COND_T
+typedef __darwin_pthread_cond_t pthread_cond_t;
+#endif /* _PTHREAD_COND_T */
--- /dev/null
+/*
+ * Copyright (c) 2003-2012 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 _PTHREAD_CONDATTR_T
+#define _PTHREAD_CONDATTR_T
+typedef __darwin_pthread_condattr_t pthread_condattr_t;
+#endif /* _PTHREAD_CONDATTR_T */
--- /dev/null
+/*
+ * Copyright (c) 2003-2012 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 _PTHREAD_KEY_T
+#define _PTHREAD_KEY_T
+typedef __darwin_pthread_key_t pthread_key_t;
+#endif /* _PTHREAD_KEY_T */
--- /dev/null
+/*
+ * Copyright (c) 2003-2012 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 _PTHREAD_MUTEX_T
+#define _PTHREAD_MUTEX_T
+typedef __darwin_pthread_mutex_t pthread_mutex_t;
+#endif /*_PTHREAD_MUTEX_T */
--- /dev/null
+/*
+ * Copyright (c) 2003-2012 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 _PTHREAD_MUTEXATTR_T
+#define _PTHREAD_MUTEXATTR_T
+typedef __darwin_pthread_mutexattr_t pthread_mutexattr_t;
+#endif /* _PTHREAD_MUTEXATTR_T */
--- /dev/null
+/*
+ * Copyright (c) 2003-2012 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 _PTHREAD_ONCE_T
+#define _PTHREAD_ONCE_T
+typedef __darwin_pthread_once_t pthread_once_t;
+#endif /* _PTHREAD_ONCE_T */
--- /dev/null
+/*
+ * Copyright (c) 2003-2012 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 _PTHREAD_RWLOCK_T
+#define _PTHREAD_RWLOCK_T
+typedef __darwin_pthread_rwlock_t pthread_rwlock_t;
+#endif /* _PTHREAD_RWLOCK_T */
--- /dev/null
+/*
+ * Copyright (c) 2003-2012 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 _PTHREAD_RWLOCKATTR_T
+#define _PTHREAD_RWLOCKATTR_T
+typedef __darwin_pthread_rwlockattr_t pthread_rwlockattr_t;
+#endif /* _PTHREAD_RWLOCKATTR_T */
--- /dev/null
+/*
+ * Copyright (c) 2003-2012 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 _PTHREAD_T
+#define _PTHREAD_T
+typedef __darwin_pthread_t pthread_t;
+#endif /* _PTHREAD_T */
--- /dev/null
+/*
+ * Copyright (c) 2003-2013 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 _SYS__PTHREAD_TYPES_H_
+#define _SYS__PTHREAD_TYPES_H_
+
+#include <sys/cdefs.h>
+
+// pthread opaque structures
+#if defined(__LP64__)
+#define __PTHREAD_SIZE__ 8176
+#define __PTHREAD_ATTR_SIZE__ 56
+#define __PTHREAD_MUTEXATTR_SIZE__ 8
+#define __PTHREAD_MUTEX_SIZE__ 56
+#define __PTHREAD_CONDATTR_SIZE__ 8
+#define __PTHREAD_COND_SIZE__ 40
+#define __PTHREAD_ONCE_SIZE__ 8
+#define __PTHREAD_RWLOCK_SIZE__ 192
+#define __PTHREAD_RWLOCKATTR_SIZE__ 16
+#else // !__LP64__
+#define __PTHREAD_SIZE__ 4088
+#define __PTHREAD_ATTR_SIZE__ 36
+#define __PTHREAD_MUTEXATTR_SIZE__ 8
+#define __PTHREAD_MUTEX_SIZE__ 40
+#define __PTHREAD_CONDATTR_SIZE__ 4
+#define __PTHREAD_COND_SIZE__ 24
+#define __PTHREAD_ONCE_SIZE__ 4
+#define __PTHREAD_RWLOCK_SIZE__ 124
+#define __PTHREAD_RWLOCKATTR_SIZE__ 12
+#endif // !__LP64__
+
+struct __darwin_pthread_handler_rec {
+ void (*__routine)(void *); // Routine to call
+ void *__arg; // Argument to pass
+ struct __darwin_pthread_handler_rec *__next;
+};
+
+struct _opaque_pthread_attr_t {
+ long __sig;
+ char __opaque[__PTHREAD_ATTR_SIZE__];
+};
+
+struct _opaque_pthread_cond_t {
+ long __sig;
+ char __opaque[__PTHREAD_COND_SIZE__];
+};
+
+struct _opaque_pthread_condattr_t {
+ long __sig;
+ char __opaque[__PTHREAD_CONDATTR_SIZE__];
+};
+
+struct _opaque_pthread_mutex_t {
+ long __sig;
+ char __opaque[__PTHREAD_MUTEX_SIZE__];
+};
+
+struct _opaque_pthread_mutexattr_t {
+ long __sig;
+ char __opaque[__PTHREAD_MUTEXATTR_SIZE__];
+};
+
+struct _opaque_pthread_once_t {
+ long __sig;
+ char __opaque[__PTHREAD_ONCE_SIZE__];
+};
+
+struct _opaque_pthread_rwlock_t {
+ long __sig;
+ char __opaque[__PTHREAD_RWLOCK_SIZE__];
+};
+
+struct _opaque_pthread_rwlockattr_t {
+ long __sig;
+ char __opaque[__PTHREAD_RWLOCKATTR_SIZE__];
+};
+
+struct _opaque_pthread_t {
+ long __sig;
+ struct __darwin_pthread_handler_rec *__cleanup_stack;
+ char __opaque[__PTHREAD_SIZE__];
+};
+
+typedef struct _opaque_pthread_attr_t __darwin_pthread_attr_t;
+typedef struct _opaque_pthread_cond_t __darwin_pthread_cond_t;
+typedef struct _opaque_pthread_condattr_t __darwin_pthread_condattr_t;
+typedef unsigned long __darwin_pthread_key_t;
+typedef struct _opaque_pthread_mutex_t __darwin_pthread_mutex_t;
+typedef struct _opaque_pthread_mutexattr_t __darwin_pthread_mutexattr_t;
+typedef struct _opaque_pthread_once_t __darwin_pthread_once_t;
+typedef struct _opaque_pthread_rwlock_t __darwin_pthread_rwlock_t;
+typedef struct _opaque_pthread_rwlockattr_t __darwin_pthread_rwlockattr_t;
+typedef struct _opaque_pthread_t *__darwin_pthread_t;
+
+#endif // _SYS__PTHREAD_TYPES_H_
--- /dev/null
+/*
+ * Copyright (c) 2013-2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#ifndef _SYS_QOS_H
+#define _SYS_QOS_H
+
+#include <sys/cdefs.h>
+#include <Availability.h>
+
+/*!
+ * @typedef qos_class_t
+ *
+ * @abstract
+ * An abstract thread quality of service (QOS) classification.
+ *
+ * @discussion
+ * Thread quality of service (QOS) classes are ordered abstract representations
+ * of the nature of work that is expected to be performed by a pthread, dispatch
+ * queue, or NSOperation. Each class specifies a maximum thread scheduling
+ * priority for that band (which may be used in combination with a relative
+ * priority offset within the band), as well as quality of service
+ * characteristics for timer latency, CPU throughput, I/O throughput, network
+ * socket traffic management behavior and more.
+ *
+ * A best effort is made to allocate available system resources to every QOS
+ * class. Quality of service degredation only occurs during system resource
+ * contention, proportionally to the QOS class. That said, QOS classes
+ * representing user-initiated work attempt to achieve peak throughput while
+ * QOS classes for other work attempt to achieve peak energy and thermal
+ * efficiency, even in the absence of contention. Finally, the use of QOS
+ * classes does not allow threads to supersede any limits that may be applied
+ * to the overall process.
+ */
+
+/*!
+ * @constant QOS_CLASS_USER_INTERACTIVE
+ * @abstract A QOS class which indicates work performed by this thread
+ * is interactive with the user.
+ * @discussion Such work is requested to run at high priority relative to other
+ * work on the system. Specifying this QOS class is a request to run with
+ * nearly all available system CPU and I/O bandwidth even under contention.
+ * This is not an energy-efficient QOS class to use for large tasks. The use of
+ * this QOS class should be limited to critical interaction with the user such
+ * as handling events on the main event loop, view drawing, animation, etc.
+ *
+ * @constant QOS_CLASS_USER_INITIATED
+ * @abstract A QOS class which indicates work performed by this thread
+ * was initiated by the user and that the user is likely waiting for the
+ * results.
+ * @discussion Such work is requested to run at a priority below critical user-
+ * interactive work, but relatively higher than other work on the system. This
+ * is not an energy-efficient QOS class to use for large tasks and the use of
+ * this QOS class should be limited to operations where the user is immediately
+ * waiting for the results.
+ *
+ * @constant QOS_CLASS_DEFAULT
+ * @abstract A default QOS class used by the system in cases where more specific
+ * QOS class information is not available.
+ * @discussion Such work is requested to run at a priority below critical user-
+ * interactive and user-initiated work, but relatively higher than utility and
+ * background tasks. Threads created by pthread_create() without an attribute
+ * specifying a QOS class will default to QOS_CLASS_DEFAULT. This QOS class
+ * value is not intended to be used as a work classification, it should only be
+ * set when propagating or restoring QOS class values provided by the system.
+ *
+ * @constant QOS_CLASS_UTILITY
+ * @abstract A QOS class which indicates work performed by this thread
+ * may or may not be initiated by the user and that the user is unlikely to be
+ * immediately waiting for the results.
+ * @discussion Such work is requested to run at a priority below critical user-
+ * interactive and user-initiated work, but relatively higher than low-level
+ * system maintenance tasks. The use of this QOS class indicates the work should
+ * be run in an energy and thermally-efficient manner.
+ *
+ * @constant QOS_CLASS_BACKGROUND
+ * @abstract A QOS class which indicates work performed by this thread was not
+ * initiated by the user and that the user may be unaware of the results.
+ * @discussion Such work is requested to run at a priority below other work.
+ * The use of this QOS class indicates the work should be run in the most energy
+ * and thermally-efficient manner.
+ *
+ * @constant QOS_CLASS_UNSPECIFIED
+ * @abstract A QOS class value which indicates the absence or removal of QOS
+ * class information.
+ * @discussion As an API return value, may indicate that threads or pthread
+ * attributes were configured with legacy API incompatible or in conflict with
+ * the QOS class system.
+ */
+
+#define __QOS_ENUM(name, type, ...) enum { __VA_ARGS__ }; typedef type name##_t
+#define __QOS_CLASS_AVAILABLE_STARTING(...)
+
+#if defined(__has_feature) && defined(__has_extension)
+#if __has_feature(objc_fixed_enum) || __has_extension(cxx_strong_enums)
+#undef __QOS_ENUM
+#define __QOS_ENUM(name, type, ...) typedef enum : type { __VA_ARGS__ } name##_t
+#endif
+#if __has_feature(enumerator_attributes)
+#undef __QOS_CLASS_AVAILABLE_STARTING
+#define __QOS_CLASS_AVAILABLE_STARTING __OSX_AVAILABLE_STARTING
+#endif
+#endif
+
+__QOS_ENUM(qos_class, unsigned int,
+ QOS_CLASS_USER_INTERACTIVE
+ __QOS_CLASS_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) = 0x21,
+ QOS_CLASS_USER_INITIATED
+ __QOS_CLASS_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) = 0x19,
+ QOS_CLASS_DEFAULT
+ __QOS_CLASS_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) = 0x15,
+ QOS_CLASS_UTILITY
+ __QOS_CLASS_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) = 0x11,
+ QOS_CLASS_BACKGROUND
+ __QOS_CLASS_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) = 0x09,
+ QOS_CLASS_UNSPECIFIED
+ __QOS_CLASS_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0) = 0x00,
+);
+
+#undef __QOS_ENUM
+
+/*!
+ * @constant QOS_MIN_RELATIVE_PRIORITY
+ * @abstract The minimum relative priority that may be specified within a
+ * QOS class. These priorities are relative only within a given QOS class
+ * and meaningful only for the current process.
+ */
+#define QOS_MIN_RELATIVE_PRIORITY (-15)
+
+/* Userspace (only) definitions */
+
+#ifndef KERNEL
+
+__BEGIN_DECLS
+
+/*!
+ * @function qos_class_self
+ *
+ * @abstract
+ * Returns the requested QOS class of the current thread.
+ *
+ * @return
+ * One of the QOS class values in qos_class_t.
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+qos_class_t
+qos_class_self(void);
+
+/*!
+ * @function qos_class_main
+ *
+ * @abstract
+ * Returns the initial requested QOS class of the main thread.
+ *
+ * @discussion
+ * The QOS class that the main thread of a process is created with depends on
+ * the type of process (e.g. application or daemon) and on how it has been
+ * launched.
+ *
+ * This function returns that initial requested QOS class value chosen by the
+ * system to enable propagation of that classification to matching work not
+ * executing on the main thread.
+ *
+ * @return
+ * One of the QOS class values in qos_class_t.
+ */
+__OSX_AVAILABLE_STARTING(__MAC_10_10, __IPHONE_8_0)
+qos_class_t
+qos_class_main(void);
+
+__END_DECLS
+
+#endif // KERNEL
+
+#endif // _SYS_QOS_H
--- /dev/null
+/*
+ * Copyright (c) 2014 Apple Inc. All rights reserved.
+ *
+ * @APPLE_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. 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_LICENSE_HEADER_END@
+ */
+
+#ifndef _QOS_SYS_PRIVATE_H
+#define _QOS_SYS_PRIVATE_H
+
+/*!
+ * @constant QOS_CLASS_MAINTENANCE
+ * @abstract A QOS class which indicates work performed by this thread was not
+ * initiated by the user and that the user may be unaware of the results.
+ * @discussion Such work is requested to run at a priority far below other work
+ * including significant I/O throttling. The use of this QOS class indicates
+ * the work should be run in the most energy and thermally-efficient manner
+ * possible, and may be deferred for a long time in order to preserve
+ * system responsiveness for the user.
+ * This is SPI for use by Spotlight and Time Machine only.
+ */
+#define QOS_CLASS_MAINTENANCE 0x05
+
+#endif //_QOS_SYS_PRIVATE_H
--- /dev/null
+#include "pthread.xcconfig"
+INSTALL_PATH = /usr/local/lib/eOS
+EXECUTABLE_PREFIX = lib
+PRODUCT_NAME = pthread_eOS
+GCC_PREPROCESSOR_DEFINITIONS = $(BASE_PREPROCESSOR_MACROS) PTHREAD_TARGET_EOS=1
+OTHER_LDFLAGS =
--- /dev/null
+#!/bin/bash -e
+# install kdebug trace files based on the input file
+INPUT=${SCRIPT_INPUT_FILE_0}
+OUTPUT=${SCRIPT_OUTPUT_FILE_0}
+
+# pre-process the source and pass through perl it
+xcrun cc -E -I${SDKROOT}/System/Library/Frameworks/System.framework/PrivateHeaders -D_PTHREAD_BUILDING_CODES_ "${INPUT}" | perl > "${OUTPUT}"
--- /dev/null
+#!/bin/bash -e
+# install the pthread lldbmacros into the module
+
+mkdir -p $DWARF_DSYM_FOLDER_PATH/$DWARF_DSYM_FILE_NAME/Contents/Resources/Python || true
+rsync -aq $SRCROOT/lldbmacros/* $DWARF_DSYM_FOLDER_PATH/$DWARF_DSYM_FILE_NAME/Contents/Resources/Python/
--- /dev/null
+#
+# Copyright (c) 2012-2013 Apple Inc. All rights reserved.
+#
+# @APPLE_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. 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_LICENSE_HEADER_END@
+#
+
+if [ "$ACTION" = installhdrs ]; then exit 0; fi
+if [ "${RC_ProjectName%_Sim}" != "${RC_ProjectName}" ]; then exit 0; fi
+
+mkdir -p "$DSTROOT"/usr/share/man/man2 || true
+mkdir -p "$DSTROOT"/usr/share/man/man3 || true
+mkdir -p "$DSTROOT"/usr/local/share/man/man2 || true
+mkdir -p "$DSTROOT"/usr/local/share/man/man3 || true
+
+# Copy man pages
+cd "$SRCROOT"/man
+
+BASE_PAGES="pthread_kill.2 \
+ pthread_sigmask.2"
+
+cp $BASE_PAGES "$DSTROOT"/usr/share/man/man2
+
+BASE_PAGES="pthread.3 \
+ pthread_atfork.3 \
+ pthread_attr.3 \
+ pthread_attr_init_destroy.3 \
+ pthread_attr_set_getdetachstate.3 \
+ pthread_attr_set_getinheritsched.3 \
+ pthread_attr_set_getschedparam.3 \
+ pthread_attr_set_getschedpolicy.3 \
+ pthread_attr_set_getscope.3 pthread_attr_set_getstackaddr.3 \
+ pthread_attr_set_getstacksize.3 \
+ pthread_cancel.3 \
+ pthread_cleanup_pop.3 \
+ pthread_cleanup_push.3 \
+ pthread_cond_broadcast.3 \
+ pthread_cond_destroy.3 \
+ pthread_cond_init.3 \
+ pthread_cond_signal.3 \
+ pthread_cond_timedwait.3 \
+ pthread_cond_wait.3 \
+ pthread_condattr.3 \
+ pthread_create.3 \
+ pthread_detach.3 \
+ pthread_equal.3 \
+ pthread_exit.3 \
+ pthread_getschedparam.3 \
+ pthread_getspecific.3 \
+ pthread_join.3 \
+ pthread_key_create.3 \
+ pthread_key_delete.3 \
+ pthread_mutex_destroy.3 \
+ pthread_mutex_init.3 \
+ pthread_mutex_lock.3 \
+ pthread_mutex_trylock.3 \
+ pthread_mutex_unlock.3 \
+ pthread_mutexattr.3 \
+ pthread_once.3 \
+ pthread_rwlock_destroy.3 \
+ pthread_rwlock_init.3 \
+ pthread_rwlock_rdlock.3 \
+ pthread_rwlock_unlock.3 \
+ pthread_rwlock_wrlock.3 \
+ pthread_rwlockattr_destroy.3 \
+ pthread_rwlockattr_getpshared.3 \
+ pthread_rwlockattr_init.3 \
+ pthread_rwlockattr_setpshared.3 \
+ pthread_self.3 \
+ pthread_setcancelstate.3 \
+ pthread_setspecific.3"
+
+cp $BASE_PAGES "$DSTROOT"/usr/share/man/man3
+
+# Make hard links
+
+cd "$DSTROOT"/usr/share/man/man3
+
+chown ${INSTALL_OWNER}:${INSTALL_GROUP} $BASE_PAGES
+chmod $INSTALL_MODE_FLAG $BASE_PAGES
+
+ln -fh pthread_getschedparam.3 pthread_setschedparam.3
+ln -fh pthread_rwlock_rdlock.3 pthread_rwlock_tryrdlock.3
+ln -fh pthread_rwlock_wrlock.3 pthread_rwlock_trywrlock.3
+
+for M in \
+ pthread_attr_destroy.3 \
+ pthread_attr_getdetachstate.3 \
+ pthread_attr_getinheritsched.3 \
+ pthread_attr_getschedparam.3 \
+ pthread_attr_getschedpolicy.3 \
+ pthread_attr_getscope.3 \
+ pthread_attr_getstackaddr.3 \
+ pthread_attr_getstacksize.3 \
+ pthread_attr_init.3 \
+ pthread_attr_setdetachstate.3 \
+ pthread_attr_setinheritsched.3 \
+ pthread_attr_setschedparam.3 \
+ pthread_attr_setschedpolicy.3 \
+ pthread_attr_setscope.3 \
+ pthread_attr_setstackaddr.3 \
+ pthread_attr_setstacksize.3 \
+ ; do
+ ln -fh pthread_attr.3 $M
+done
+
+for M in \
+ pthread_mutexattr_destroy.3 \
+ pthread_mutexattr_getprioceiling.3 \
+ pthread_mutexattr_getprotocol.3 \
+ pthread_mutexattr_gettype.3 \
+ pthread_mutexattr_init.3 \
+ pthread_mutexattr_setprioceiling.3 \
+ pthread_mutexattr_setprotocol.3 \
+ pthread_mutexattr_settype.3 \
+ ; do
+ ln -fh pthread_mutexattr.3 $M
+done
+
+for M in \
+ pthread_condattr_destroy.3 \
+ pthread_condattr_init.3 \
+ ; do
+ ln -fh pthread_condattr.3 $M
+done
+
+for M in \
+ pthread_setcanceltype.3 \
+ pthread_testcancel.3 \
+ ; do
+ ln -fh pthread_setcancelstate.3 $M
+done
--- /dev/null
+#
+# Copyright (c) 2012 Apple Inc. All rights reserved.
+#
+# @APPLE_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. 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_LICENSE_HEADER_END@
+#
+
+if [ "$ACTION" = build ]; then exit 0; fi
+DSTROOT="$DSTROOT$INSTALL_PATH_PREFIX"
+
+#
+# Symlink old header locations.
+#
+
+ln -sf "pthread/pthread.h" "$DSTROOT/usr/include/pthread.h"
+ln -sf "pthread/pthread_impl.h" "$DSTROOT/usr/include/pthread_impl.h"
+ln -sf "pthread/pthread_spis.h" "$DSTROOT/usr/include/pthread_spis.h"
+ln -sf "pthread/sched.h" "$DSTROOT/usr/include/sched.h"
+
+ln -sf "pthread/posix_sched.h" "$DSTROOT/usr/local/include/posix_sched.h"
+ln -sf "pthread/spinlock_private.h" "$DSTROOT/usr/local/include/pthread_spinlock.h"
+ln -sf "pthread/workqueue_private.h" "$DSTROOT/usr/local/include/pthread_workqueue.h"
+mkdir -p "$DSTROOT/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders/"
+ln -sf "../../../../../../../usr/local/include/pthread/tsd_private.h" \
+ "$DSTROOT/System/Library/Frameworks/System.framework/Versions/B/PrivateHeaders/pthread_machdep.h"
--- /dev/null
+#
+# Copyright (c) 2013-2014 Apple Inc. All rights reserved.
+#
+# @APPLE_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. 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_LICENSE_HEADER_END@
+#
+
+set -e
+
+if [ "$ACTION" = build ]; then exit 0; fi
+DSTROOT="$DSTROOT$INSTALL_PATH_PREFIX"
+
+DESTDIR="$DSTROOT/usr/include/sys"
+mkdir -p "$DESTDIR"
+for X in \
+ qos.h \
+ ; do
+ cp "sys/$X" "$DESTDIR"
+done
+
+DESTDIR="$DSTROOT/usr/local/include/sys"
+mkdir -p "$DESTDIR"
+for X in \
+ qos_private.h \
+ ; do
+ cp "sys/$X" "$DESTDIR"
+done
+
+DESTDIR="$DSTROOT/usr/include/sys/_pthread"
+mkdir -p "$DESTDIR"
+for X in \
+ _pthread_attr_t.h \
+ _pthread_cond_t.h \
+ _pthread_condattr_t.h \
+ _pthread_key_t.h \
+ _pthread_mutex_t.h \
+ _pthread_mutexattr_t.h \
+ _pthread_once_t.h \
+ _pthread_rwlock_t.h \
+ _pthread_rwlockattr_t.h \
+ _pthread_t.h \
+ _pthread_types.h \
+ ; do
+ cp "sys/_pthread/$X" "$DESTDIR"
+done
+
--- /dev/null
+// pthread kext build options
+
+ARCHS = $(ARCHS_STANDARD_32_64_BIT)
+SUPPORTED_PLATFORMS = macosx iphoneos
+DYLIB_CURRENT_VERSION = $(RC_ProjectSourceVersion)
+INSTALL_PATH = $(SYSTEM_LIBRARY_DIR)/Extensions
+MODULE_NAME = com.apple.kec.pthread
+MODULE_START = pthread_start
+MODULE_STOP = pthread_stop
+MODULE_VERSION = 1.0.0d1
+DEAD_CODE_STRIPPING = NO
+INFOPLIST_FILE = kern/pthread-Info.plist
+PRODUCT_NAME = $(TARGET_NAME)
+WRAPPER_EXTENSION = kext
+ALWAYS_SEARCH_USER_PATHS = NO
+SRCROOT_SEARCH_PATHS = $(SRCROOT) $(SRCROOT)/pthread $(SRCROOT)/private
+HEADER_SEARCH_PATHS = $(SDKROOT)/System/Library/Frameworks/Kernel.framework/PrivateHeaders $(SDKROOT)/System/Library/Frameworks/Kernel.framework/Headers $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders $(SDKROOT)/System/Library/Frameworks/System.framework/Headers $(SRCROOT_SEARCH_PATHS)
+GCC_C_LANGUAGE_STANDARD = gnu99
+CLANG_CXX_LANGUAGE_STANDARD = gnu++0x
+CLANG_CXX_LIBRARY = libc++
+GCC_PRECOMPILE_PREFIX_HEADER = YES
+GCC_PREPROCESSOR_DEFINITIONS = XNU_KERNEL_PRIVATE MACH_KERNEL_PRIVATE ABSOLUTETIME_SCALAR_TYPE NEEDS_SCHED_CALL_T
+//GCC_OPTIMIZATION_LEVEL = 0
+
+GCC_TREAT_IMPLICIT_FUNCTION_DECLARATIONS_AS_ERRORS = YES
+GCC_TREAT_INCOMPATIBLE_POINTER_TYPE_WARNINGS_AS_ERRORS = YES
+
+// Warnings
+CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
+CLANG_WARN_EMPTY_BODY = YES
+GCC_WARN_64_TO_32_BIT_CONVERSION = YES
+GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES
+GCC_WARN_ABOUT_MISSING_NEWLINE = YES
+GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES
+GCC_WARN_ABOUT_RETURN_TYPE = YES
+GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES
+GCC_WARN_SHADOW = YES
+GCC_WARN_SIGN_COMPARE = YES
+GCC_WARN_UNINITIALIZED_AUTOS = YES
+GCC_WARN_UNUSED_FUNCTION = YES
+GCC_WARN_UNUSED_LABEL = YES
+GCC_WARN_UNUSED_PARAMETER = YES
+GCC_WARN_UNUSED_VARIABLE = YES
--- /dev/null
+# aliases file for pthread old-symbol aliases
+# <symbol> <alias>
--- /dev/null
+#include "<DEVELOPER_DIR>/Makefiles/CoreOS/Xcode/BSD.xcconfig"
+#include "<DEVELOPER_DIR>/AppleInternal/XcodeConfig/SimulatorSupport.xcconfig"
+
+// Set INSTALL_PATH[sdk=macosx*] when SimulatorSupport.xcconfig is unavailable
+INSTALL_PATH[sdk=macosx*] = $(INSTALL_PATH_ACTUAL)
+
+// Standard settings
+SUPPORTED_PLATFORMS = macosx iphoneos iphonesimulator
+SRCROOT_SEARCH_PATHS = $(SRCROOT) $(SRCROOT)/private
+SYSTEM_FRAMEWORK_HEADERS = $(SDKROOT)/System/Library/Frameworks/System.framework/PrivateHeaders
+HEADER_SEARCH_PATHS = $($(TARGET_NAME)_SEARCH_PATHS) $(SRCROOT_SEARCH_PATHS) $(SYSTEM_FRAMEWORK_HEADERS) $(SDKROOT)/usr/local/include $(inherited)
+ALWAYS_SEARCH_USER_PATHS = YES
+USE_HEADERMAP = NO
+BUILD_VARIANTS = normal
+
+GCC_OPTIMIZATION_LEVEL = s
+GCC_C_LANGUAGE_STANDARD = gnu99
+GCC_ENABLE_OBJC_EXCEPTIONS = YES
+GCC_SYMBOLS_PRIVATE_EXTERN = NO
+GCC_DYNAMIC_NO_PIC = NO
+GCC_THUMB_SUPPORT = YES
+
+// Warnings
+CLANG_WARN__DUPLICATE_METHOD_MATCH = YES
+CLANG_WARN_DOCUMENTATION_COMMENTS = YES
+GCC_WARN_64_TO_32_BIT_CONVERSION = YES
+GCC_WARN_ABOUT_RETURN_TYPE = YES
+GCC_WARN_UNINITIALIZED_AUTOS = YES
+GCC_WARN_UNUSED_VARIABLE = YES
+
+INSTALLHDRS_SCRIPT_PHASE = YES
+
+COPY_PHASE_STRIP = NO
+STRIP_INSTALLED_PRODUCT = YES
+STRIP_STYLE = debugging
+
+// Versioning
+DYLIB_CURRENT_VERSION = $(RC_ProjectSourceVersion)
+DYLIB_COMPATIBILITY_VERSION = 1
+
+// Installation paths
+INSTALL_PATH_ACTUAL = /usr/lib/system
+PUBLIC_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/include/pthread
+PRIVATE_HEADERS_FOLDER_PATH = $(INSTALL_PATH_PREFIX)/usr/local/include/pthread
+SKIP_INSTALL = NO
+
+// Base definitions
+// TODO: Remove -fstack-protector on _debug when it is moved to libplatform
+LINK_WITH_STANDARD_LIBRARIES = NO
+BASE_PREPROCESSOR_MACROS = __LIBC__ __DARWIN_UNIX03=1 __DARWIN_64_BIT_INO_T=1 __DARWIN_NON_CANCELABLE=1 __DARWIN_VERS_1050=1 _FORTIFY_SOURCE=0 __PTHREAD_BUILDING_PTHREAD__=1 $(SIM_PREPROCESSOR_MACROS)
+OTHER_CFLAGS = -fno-stack-protector -fdollars-in-identifiers -fno-common -fno-builtin -momit-leaf-frame-pointer $($(TARGET_NAME)_CFLAGS)
+OTHER_CFLAGS_debug = -fno-stack-protector -fno-inline -O0 -DDEBUG=1
+OTHER_LDFLAGS = -Wl,-alias_list,$(SRCROOT)/xcodescripts/pthread.aliases -Wl,-umbrella,System -L/usr/lib/system -lsystem_kernel -lsystem_platform -ldyld -lcompiler_rt $(UPLINK_LDFLAGS) $(CR_LDFLAGS)
+GCC_PREPROCESSOR_DEFINITIONS = $(BASE_PREPROCESSOR_MACROS)
+
+// CrashReporter
+CR_LDFLAGS = -lCrashReporterClient
+
+ORDER_FILE = $(SDKROOT)/$(APPLE_INTERNAL_DIR)/OrderFiles/libsystem_pthread.order
+ORDER_FILE[sdk=iphonesimulator*] =
+
+// Simulator build rules
+EXCLUDED_SOURCE_FILE_NAMES[sdk=iphonesimulator*] = *.c *.d *.s
+SKIP_INSTALL[sdk=iphonesimulator*] = YES
+OTHER_LDFLAGS[sdk=iphonesimulator*] =