]> git.saurik.com Git - apple/libpthread.git/commitdiff
libpthread-105.1.4.tar.gz os-x-1010 os-x-10101 v105.1.4
authorApple <opensource@apple.com>
Thu, 30 Oct 2014 23:07:19 +0000 (23:07 +0000)
committerApple <opensource@apple.com>
Thu, 30 Oct 2014 23:07:19 +0000 (23:07 +0000)
117 files changed:
kern/kern_init.c [new file with mode: 0644]
kern/kern_internal.h [new file with mode: 0644]
kern/kern_policy.c [new file with mode: 0644]
kern/kern_support.c [new file with mode: 0644]
kern/kern_synch.c [new file with mode: 0644]
kern/kern_trace.h [new file with mode: 0644]
kern/pthread-Info.plist [new file with mode: 0644]
kern/synch_internal.h [new file with mode: 0644]
kern/workqueue_internal.h [new file with mode: 0644]
libpthread.xcodeproj/project.pbxproj [new file with mode: 0644]
lldbmacros/pthread.py [new file with mode: 0644]
man/pthread.3 [new file with mode: 0644]
man/pthread_atfork.3 [new file with mode: 0644]
man/pthread_attr.3 [new file with mode: 0644]
man/pthread_attr_init_destroy.3 [new file with mode: 0644]
man/pthread_attr_set_getdetachstate.3 [new file with mode: 0644]
man/pthread_attr_set_getinheritsched.3 [new file with mode: 0644]
man/pthread_attr_set_getschedparam.3 [new file with mode: 0644]
man/pthread_attr_set_getschedpolicy.3 [new file with mode: 0644]
man/pthread_attr_set_getscope.3 [new file with mode: 0644]
man/pthread_attr_set_getstackaddr.3 [new file with mode: 0644]
man/pthread_attr_set_getstacksize.3 [new file with mode: 0644]
man/pthread_cancel.3 [new file with mode: 0644]
man/pthread_cleanup_pop.3 [new file with mode: 0644]
man/pthread_cleanup_push.3 [new file with mode: 0644]
man/pthread_cond_broadcast.3 [new file with mode: 0644]
man/pthread_cond_destroy.3 [new file with mode: 0644]
man/pthread_cond_init.3 [new file with mode: 0644]
man/pthread_cond_signal.3 [new file with mode: 0644]
man/pthread_cond_timedwait.3 [new file with mode: 0644]
man/pthread_cond_wait.3 [new file with mode: 0644]
man/pthread_condattr.3 [new file with mode: 0644]
man/pthread_create.3 [new file with mode: 0644]
man/pthread_detach.3 [new file with mode: 0644]
man/pthread_equal.3 [new file with mode: 0644]
man/pthread_exit.3 [new file with mode: 0644]
man/pthread_getschedparam.3 [new file with mode: 0644]
man/pthread_getspecific.3 [new file with mode: 0644]
man/pthread_join.3 [new file with mode: 0644]
man/pthread_key_create.3 [new file with mode: 0644]
man/pthread_key_delete.3 [new file with mode: 0644]
man/pthread_kill.2 [new file with mode: 0644]
man/pthread_mutex_destroy.3 [new file with mode: 0644]
man/pthread_mutex_init.3 [new file with mode: 0644]
man/pthread_mutex_lock.3 [new file with mode: 0644]
man/pthread_mutex_trylock.3 [new file with mode: 0644]
man/pthread_mutex_unlock.3 [new file with mode: 0644]
man/pthread_mutexattr.3 [new file with mode: 0644]
man/pthread_once.3 [new file with mode: 0644]
man/pthread_rwlock_destroy.3 [new file with mode: 0644]
man/pthread_rwlock_init.3 [new file with mode: 0644]
man/pthread_rwlock_rdlock.3 [new file with mode: 0644]
man/pthread_rwlock_unlock.3 [new file with mode: 0644]
man/pthread_rwlock_wrlock.3 [new file with mode: 0644]
man/pthread_rwlockattr_destroy.3 [new file with mode: 0644]
man/pthread_rwlockattr_getpshared.3 [new file with mode: 0644]
man/pthread_rwlockattr_init.3 [new file with mode: 0644]
man/pthread_rwlockattr_setpshared.3 [new file with mode: 0644]
man/pthread_self.3 [new file with mode: 0644]
man/pthread_setcancelstate.3 [new file with mode: 0644]
man/pthread_setspecific.3 [new file with mode: 0644]
man/pthread_sigmask.2 [new file with mode: 0644]
private/introspection_private.h [new file with mode: 0644]
private/posix_sched.h [new file with mode: 0644]
private/private.h [new file with mode: 0644]
private/qos.h [new file with mode: 0644]
private/qos_private.h [new file with mode: 0644]
private/spinlock_private.h [new file with mode: 0644]
private/tsd_private.h [new file with mode: 0644]
private/workqueue_private.h [new file with mode: 0644]
pthread/pthread.h [new file with mode: 0644]
pthread/pthread_impl.h [new file with mode: 0644]
pthread/pthread_spis.h [new file with mode: 0644]
pthread/qos.h [new file with mode: 0644]
pthread/sched.h [new file with mode: 0644]
pthread/spawn.h [new file with mode: 0644]
src/internal.h [new file with mode: 0644]
src/mk_pthread_impl.c [new file with mode: 0644]
src/plockstat.d [new file with mode: 0644]
src/pthread.c [new file with mode: 0644]
src/pthread_asm.s [new file with mode: 0644]
src/pthread_atfork.c [new file with mode: 0644]
src/pthread_cancelable.c [new file with mode: 0644]
src/pthread_cond.c [new file with mode: 0644]
src/pthread_mutex.c [new file with mode: 0644]
src/pthread_rwlock.c [new file with mode: 0644]
src/pthread_support.c [new file with mode: 0644]
src/pthread_tsd.c [new file with mode: 0644]
src/qos.c [new file with mode: 0644]
src/thread_setup.c [new file with mode: 0644]
src/variants/pthread_cancelable_cancel.c [new file with mode: 0644]
src/variants/pthread_cancelable_legacy.c [new file with mode: 0644]
src/variants/pthread_cond_legacy.c [new file with mode: 0644]
src/variants/pthread_mutex_legacy.c [new file with mode: 0644]
src/variants/pthread_rwlock_legacy.c [new file with mode: 0644]
sys/_pthread/_pthread_attr_t.h [new file with mode: 0644]
sys/_pthread/_pthread_cond_t.h [new file with mode: 0644]
sys/_pthread/_pthread_condattr_t.h [new file with mode: 0644]
sys/_pthread/_pthread_key_t.h [new file with mode: 0644]
sys/_pthread/_pthread_mutex_t.h [new file with mode: 0644]
sys/_pthread/_pthread_mutexattr_t.h [new file with mode: 0644]
sys/_pthread/_pthread_once_t.h [new file with mode: 0644]
sys/_pthread/_pthread_rwlock_t.h [new file with mode: 0644]
sys/_pthread/_pthread_rwlockattr_t.h [new file with mode: 0644]
sys/_pthread/_pthread_t.h [new file with mode: 0644]
sys/_pthread/_pthread_types.h [new file with mode: 0644]
sys/qos.h [new file with mode: 0644]
sys/qos_private.h [new file with mode: 0644]
xcodescripts/eos.xcconfig [new file with mode: 0644]
xcodescripts/install-codes.sh [new file with mode: 0644]
xcodescripts/install-lldbmacros.sh [new file with mode: 0644]
xcodescripts/install-manpages.sh [new file with mode: 0644]
xcodescripts/install-symlinks.sh [new file with mode: 0644]
xcodescripts/install-sys-headers.sh [new file with mode: 0644]
xcodescripts/kext.xcconfig [new file with mode: 0644]
xcodescripts/pthread.aliases [new file with mode: 0644]
xcodescripts/pthread.xcconfig [new file with mode: 0644]

diff --git a/kern/kern_init.c b/kern/kern_init.c
new file mode 100644 (file)
index 0000000..8b4b60a
--- /dev/null
@@ -0,0 +1,66 @@
+//
+//  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);
+}
diff --git a/kern/kern_internal.h b/kern/kern_internal.h
new file mode 100644 (file)
index 0000000..3c30213
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ * 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_ */
+
diff --git a/kern/kern_policy.c b/kern/kern_policy.c
new file mode 100644 (file)
index 0000000..23fb0d0
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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;
+       }
+}
diff --git a/kern/kern_support.c b/kern/kern_support.c
new file mode 100644 (file)
index 0000000..4d1907e
--- /dev/null
@@ -0,0 +1,2545 @@
+/*
+ * 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);
+}
diff --git a/kern/kern_synch.c b/kern/kern_synch.c
new file mode 100644 (file)
index 0000000..1996f3f
--- /dev/null
@@ -0,0 +1,2592 @@
+/*
+ * 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");
+}
diff --git a/kern/kern_trace.h b/kern/kern_trace.h
new file mode 100644 (file)
index 0000000..701fa70
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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_
diff --git a/kern/pthread-Info.plist b/kern/pthread-Info.plist
new file mode 100644 (file)
index 0000000..7b35509
--- /dev/null
@@ -0,0 +1,49 @@
+<?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>
diff --git a/kern/synch_internal.h b/kern/synch_internal.h
new file mode 100644 (file)
index 0000000..a3e5594
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * 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__ */
diff --git a/kern/workqueue_internal.h b/kern/workqueue_internal.h
new file mode 100644 (file)
index 0000000..47f52a8
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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_
diff --git a/libpthread.xcodeproj/project.pbxproj b/libpthread.xcodeproj/project.pbxproj
new file mode 100644 (file)
index 0000000..966894b
--- /dev/null
@@ -0,0 +1,1091 @@
+// !$*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 */;
+}
diff --git a/lldbmacros/pthread.py b/lldbmacros/pthread.py
new file mode 100644 (file)
index 0000000..6b0c66a
--- /dev/null
@@ -0,0 +1,154 @@
+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
diff --git a/man/pthread.3 b/man/pthread.3
new file mode 100644 (file)
index 0000000..6f07565
--- /dev/null
@@ -0,0 +1,481 @@
+.\" 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 .
diff --git a/man/pthread_atfork.3 b/man/pthread_atfork.3
new file mode 100644 (file)
index 0000000..d0b0b84
--- /dev/null
@@ -0,0 +1,62 @@
+.\" 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 .
diff --git a/man/pthread_attr.3 b/man/pthread_attr.3
new file mode 100644 (file)
index 0000000..1019425
--- /dev/null
@@ -0,0 +1,277 @@
+.\" 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
diff --git a/man/pthread_attr_init_destroy.3 b/man/pthread_attr_init_destroy.3
new file mode 100644 (file)
index 0000000..236a093
--- /dev/null
@@ -0,0 +1,64 @@
+.\" 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
diff --git a/man/pthread_attr_set_getdetachstate.3 b/man/pthread_attr_set_getdetachstate.3
new file mode 100644 (file)
index 0000000..ee30399
--- /dev/null
@@ -0,0 +1,86 @@
+.\" 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
diff --git a/man/pthread_attr_set_getinheritsched.3 b/man/pthread_attr_set_getinheritsched.3
new file mode 100644 (file)
index 0000000..b5e52cc
--- /dev/null
@@ -0,0 +1,85 @@
+.\" 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
diff --git a/man/pthread_attr_set_getschedparam.3 b/man/pthread_attr_set_getschedparam.3
new file mode 100644 (file)
index 0000000..dff13e4
--- /dev/null
@@ -0,0 +1,81 @@
+.\" 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
diff --git a/man/pthread_attr_set_getschedpolicy.3 b/man/pthread_attr_set_getschedpolicy.3
new file mode 100644 (file)
index 0000000..d83e7a4
--- /dev/null
@@ -0,0 +1,73 @@
+.\" 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
diff --git a/man/pthread_attr_set_getscope.3 b/man/pthread_attr_set_getscope.3
new file mode 100644 (file)
index 0000000..2005297
--- /dev/null
@@ -0,0 +1,75 @@
+.\" 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
diff --git a/man/pthread_attr_set_getstackaddr.3 b/man/pthread_attr_set_getstackaddr.3
new file mode 100644 (file)
index 0000000..cf725ae
--- /dev/null
@@ -0,0 +1,74 @@
+.\" 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
diff --git a/man/pthread_attr_set_getstacksize.3 b/man/pthread_attr_set_getstacksize.3
new file mode 100644 (file)
index 0000000..3aadea6
--- /dev/null
@@ -0,0 +1,78 @@
+.\" 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
diff --git a/man/pthread_cancel.3 b/man/pthread_cancel.3
new file mode 100644 (file)
index 0000000..fae332e
--- /dev/null
@@ -0,0 +1,77 @@
+.\" $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 .
diff --git a/man/pthread_cleanup_pop.3 b/man/pthread_cleanup_pop.3
new file mode 100644 (file)
index 0000000..f6d0401
--- /dev/null
@@ -0,0 +1,66 @@
+.\" 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 .
diff --git a/man/pthread_cleanup_push.3 b/man/pthread_cleanup_push.3
new file mode 100644 (file)
index 0000000..91ec386
--- /dev/null
@@ -0,0 +1,71 @@
+.\" 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 .
diff --git a/man/pthread_cond_broadcast.3 b/man/pthread_cond_broadcast.3
new file mode 100644 (file)
index 0000000..279636d
--- /dev/null
@@ -0,0 +1,69 @@
+.\" 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 .
diff --git a/man/pthread_cond_destroy.3 b/man/pthread_cond_destroy.3
new file mode 100644 (file)
index 0000000..523bf8a
--- /dev/null
@@ -0,0 +1,73 @@
+.\" 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 .
diff --git a/man/pthread_cond_init.3 b/man/pthread_cond_init.3
new file mode 100644 (file)
index 0000000..a69fbac
--- /dev/null
@@ -0,0 +1,81 @@
+.\" 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 .
diff --git a/man/pthread_cond_signal.3 b/man/pthread_cond_signal.3
new file mode 100644 (file)
index 0000000..669b6fc
--- /dev/null
@@ -0,0 +1,68 @@
+.\" 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 .
diff --git a/man/pthread_cond_timedwait.3 b/man/pthread_cond_timedwait.3
new file mode 100644 (file)
index 0000000..dbf48e4
--- /dev/null
@@ -0,0 +1,109 @@
+.\" 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 .
diff --git a/man/pthread_cond_wait.3 b/man/pthread_cond_wait.3
new file mode 100644 (file)
index 0000000..efe6ac2
--- /dev/null
@@ -0,0 +1,89 @@
+.\" 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 .
diff --git a/man/pthread_condattr.3 b/man/pthread_condattr.3
new file mode 100644 (file)
index 0000000..4db5027
--- /dev/null
@@ -0,0 +1,87 @@
+.\" 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
diff --git a/man/pthread_create.3 b/man/pthread_create.3
new file mode 100644 (file)
index 0000000..589b103
--- /dev/null
@@ -0,0 +1,141 @@
+.\" 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 .
diff --git a/man/pthread_detach.3 b/man/pthread_detach.3
new file mode 100644 (file)
index 0000000..f354951
--- /dev/null
@@ -0,0 +1,89 @@
+.\" 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 .
diff --git a/man/pthread_equal.3 b/man/pthread_equal.3
new file mode 100644 (file)
index 0000000..c865329
--- /dev/null
@@ -0,0 +1,69 @@
+.\" 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 .
diff --git a/man/pthread_exit.3 b/man/pthread_exit.3
new file mode 100644 (file)
index 0000000..52b8403
--- /dev/null
@@ -0,0 +1,104 @@
+.\" 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 .
diff --git a/man/pthread_getschedparam.3 b/man/pthread_getschedparam.3
new file mode 100644 (file)
index 0000000..854596c
--- /dev/null
@@ -0,0 +1,96 @@
+.\" 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
diff --git a/man/pthread_getspecific.3 b/man/pthread_getspecific.3
new file mode 100644 (file)
index 0000000..642aed8
--- /dev/null
@@ -0,0 +1,83 @@
+.\" 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 .
diff --git a/man/pthread_join.3 b/man/pthread_join.3
new file mode 100644 (file)
index 0000000..6402393
--- /dev/null
@@ -0,0 +1,103 @@
+.\" 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 .
diff --git a/man/pthread_key_create.3 b/man/pthread_key_create.3
new file mode 100644 (file)
index 0000000..429f872
--- /dev/null
@@ -0,0 +1,106 @@
+.\" 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 .
diff --git a/man/pthread_key_delete.3 b/man/pthread_key_delete.3
new file mode 100644 (file)
index 0000000..013ecd4
--- /dev/null
@@ -0,0 +1,98 @@
+.\" 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 .
diff --git a/man/pthread_kill.2 b/man/pthread_kill.2
new file mode 100644 (file)
index 0000000..8c83b99
--- /dev/null
@@ -0,0 +1,81 @@
+.\"    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'')
diff --git a/man/pthread_mutex_destroy.3 b/man/pthread_mutex_destroy.3
new file mode 100644 (file)
index 0000000..17207f3
--- /dev/null
@@ -0,0 +1,72 @@
+.\" 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 .
diff --git a/man/pthread_mutex_init.3 b/man/pthread_mutex_init.3
new file mode 100644 (file)
index 0000000..bebe8a2
--- /dev/null
@@ -0,0 +1,78 @@
+.\" 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 .
diff --git a/man/pthread_mutex_lock.3 b/man/pthread_mutex_lock.3
new file mode 100644 (file)
index 0000000..e0a4fad
--- /dev/null
@@ -0,0 +1,74 @@
+.\" 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 .
diff --git a/man/pthread_mutex_trylock.3 b/man/pthread_mutex_trylock.3
new file mode 100644 (file)
index 0000000..345a014
--- /dev/null
@@ -0,0 +1,75 @@
+.\" 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 .
diff --git a/man/pthread_mutex_unlock.3 b/man/pthread_mutex_unlock.3
new file mode 100644 (file)
index 0000000..ae29010
--- /dev/null
@@ -0,0 +1,81 @@
+.\" 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 .
diff --git a/man/pthread_mutexattr.3 b/man/pthread_mutexattr.3
new file mode 100644 (file)
index 0000000..9f6ac0c
--- /dev/null
@@ -0,0 +1,302 @@
+.\" $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
diff --git a/man/pthread_once.3 b/man/pthread_once.3
new file mode 100644 (file)
index 0000000..1a84320
--- /dev/null
@@ -0,0 +1,102 @@
+.\" 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 .
diff --git a/man/pthread_rwlock_destroy.3 b/man/pthread_rwlock_destroy.3
new file mode 100644 (file)
index 0000000..47beb62
--- /dev/null
@@ -0,0 +1,82 @@
+.\" 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 .
diff --git a/man/pthread_rwlock_init.3 b/man/pthread_rwlock_init.3
new file mode 100644 (file)
index 0000000..507317a
--- /dev/null
@@ -0,0 +1,102 @@
+.\" 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.
diff --git a/man/pthread_rwlock_rdlock.3 b/man/pthread_rwlock_rdlock.3
new file mode 100644 (file)
index 0000000..815da8c
--- /dev/null
@@ -0,0 +1,126 @@
+.\" 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 .
diff --git a/man/pthread_rwlock_unlock.3 b/man/pthread_rwlock_unlock.3
new file mode 100644 (file)
index 0000000..def7aaf
--- /dev/null
@@ -0,0 +1,81 @@
+.\" 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 .
diff --git a/man/pthread_rwlock_wrlock.3 b/man/pthread_rwlock_wrlock.3
new file mode 100644 (file)
index 0000000..5906e4b
--- /dev/null
@@ -0,0 +1,106 @@
+.\" 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 .
diff --git a/man/pthread_rwlockattr_destroy.3 b/man/pthread_rwlockattr_destroy.3
new file mode 100644 (file)
index 0000000..3d45228
--- /dev/null
@@ -0,0 +1,70 @@
+.\" 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 .
diff --git a/man/pthread_rwlockattr_getpshared.3 b/man/pthread_rwlockattr_getpshared.3
new file mode 100644 (file)
index 0000000..61dcc73
--- /dev/null
@@ -0,0 +1,83 @@
+.\" 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 .
diff --git a/man/pthread_rwlockattr_init.3 b/man/pthread_rwlockattr_init.3
new file mode 100644 (file)
index 0000000..1d75a3c
--- /dev/null
@@ -0,0 +1,69 @@
+.\" 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 .
diff --git a/man/pthread_rwlockattr_setpshared.3 b/man/pthread_rwlockattr_setpshared.3
new file mode 100644 (file)
index 0000000..d8702b9
--- /dev/null
@@ -0,0 +1,91 @@
+.\" 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.
diff --git a/man/pthread_self.3 b/man/pthread_self.3
new file mode 100644 (file)
index 0000000..d7c2bcd
--- /dev/null
@@ -0,0 +1,59 @@
+.\" 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 .
diff --git a/man/pthread_setcancelstate.3 b/man/pthread_setcancelstate.3
new file mode 100644 (file)
index 0000000..0e451ab
--- /dev/null
@@ -0,0 +1,241 @@
+.\" $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 .
diff --git a/man/pthread_setspecific.3 b/man/pthread_setspecific.3
new file mode 100644 (file)
index 0000000..96104b4
--- /dev/null
@@ -0,0 +1,95 @@
+.\" 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 .
diff --git a/man/pthread_sigmask.2 b/man/pthread_sigmask.2
new file mode 100644 (file)
index 0000000..5680dd2
--- /dev/null
@@ -0,0 +1,104 @@
+.\" 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'')
diff --git a/private/introspection_private.h b/private/introspection_private.h
new file mode 100644 (file)
index 0000000..04c7c92
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * 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
diff --git a/private/posix_sched.h b/private/posix_sched.h
new file mode 100644 (file)
index 0000000..8bbc4a5
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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 */
diff --git a/private/private.h b/private/private.h
new file mode 100644 (file)
index 0000000..d59f161
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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__
diff --git a/private/qos.h b/private/qos.h
new file mode 100644 (file)
index 0000000..b316a74
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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
diff --git a/private/qos_private.h b/private/qos_private.h
new file mode 100644 (file)
index 0000000..46763fa
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * 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
diff --git a/private/spinlock_private.h b/private/spinlock_private.h
new file mode 100644 (file)
index 0000000..a09fb04
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * 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 */
diff --git a/private/tsd_private.h b/private/tsd_private.h
new file mode 100644 (file)
index 0000000..1737c97
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * 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__ */
diff --git a/private/workqueue_private.h b/private/workqueue_private.h
new file mode 100644 (file)
index 0000000..aaaf402
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * 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__
diff --git a/pthread/pthread.h b/pthread/pthread.h
new file mode 100644 (file)
index 0000000..4169176
--- /dev/null
@@ -0,0 +1,519 @@
+/*
+ * 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 */
diff --git a/pthread/pthread_impl.h b/pthread/pthread_impl.h
new file mode 100644 (file)
index 0000000..887b56d
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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_ */
diff --git a/pthread/pthread_spis.h b/pthread/pthread_spis.h
new file mode 100644 (file)
index 0000000..b76c238
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * 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 */
diff --git a/pthread/qos.h b/pthread/qos.h
new file mode 100644 (file)
index 0000000..fa0f832
--- /dev/null
@@ -0,0 +1,296 @@
+/*
+ * 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
diff --git a/pthread/sched.h b/pthread/sched.h
new file mode 100644 (file)
index 0000000..df1fc51
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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_ */
+
diff --git a/pthread/spawn.h b/pthread/spawn.h
new file mode 100644 (file)
index 0000000..11af0fe
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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
diff --git a/src/internal.h b/src/internal.h
new file mode 100644 (file)
index 0000000..057428f
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+ * 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 */
diff --git a/src/mk_pthread_impl.c b/src/mk_pthread_impl.c
new file mode 100644 (file)
index 0000000..8654c45
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * 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);
+} 
diff --git a/src/plockstat.d b/src/plockstat.d
new file mode 100644 (file)
index 0000000..0b6a5cc
--- /dev/null
@@ -0,0 +1,24 @@
+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
diff --git a/src/pthread.c b/src/pthread.c
new file mode 100644 (file)
index 0000000..de2d6db
--- /dev/null
@@ -0,0 +1,2169 @@
+/*
+ * 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);
+}
+
diff --git a/src/pthread_asm.s b/src/pthread_asm.s
new file mode 100644 (file)
index 0000000..df03a25
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * 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
diff --git a/src/pthread_atfork.c b/src/pthread_atfork.c
new file mode 100644 (file)
index 0000000..724a7fb
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * 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;
+}
diff --git a/src/pthread_cancelable.c b/src/pthread_cancelable.c
new file mode 100644 (file)
index 0000000..c875451
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * 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 */
+}
diff --git a/src/pthread_cond.c b/src/pthread_cond.c
new file mode 100644 (file)
index 0000000..a425fbe
--- /dev/null
@@ -0,0 +1,694 @@
+/*
+ * 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);
+}
diff --git a/src/pthread_mutex.c b/src/pthread_mutex.c
new file mode 100644 (file)
index 0000000..794b6ff
--- /dev/null
@@ -0,0 +1,912 @@
+/*
+ * 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;
+}
+
+
diff --git a/src/pthread_rwlock.c b/src/pthread_rwlock.c
new file mode 100644 (file)
index 0000000..c7b5373
--- /dev/null
@@ -0,0 +1,629 @@
+/*
+ * 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;
+}
+
diff --git a/src/pthread_support.c b/src/pthread_support.c
new file mode 100644 (file)
index 0000000..5ae4239
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * 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();
+}
diff --git a/src/pthread_tsd.c b/src/pthread_tsd.c
new file mode 100644 (file)
index 0000000..e3fffe7
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * 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);
+}
diff --git a/src/qos.c b/src/qos.c
new file mode 100644 (file)
index 0000000..e9c9993
--- /dev/null
+++ b/src/qos.c
@@ -0,0 +1,523 @@
+/*
+ * 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;
+}
diff --git a/src/thread_setup.c b/src/thread_setup.c
new file mode 100644 (file)
index 0000000..3f7a8d0
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * 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);
+}
diff --git a/src/variants/pthread_cancelable_cancel.c b/src/variants/pthread_cancelable_cancel.c
new file mode 100644 (file)
index 0000000..17bf513
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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"
diff --git a/src/variants/pthread_cancelable_legacy.c b/src/variants/pthread_cancelable_legacy.c
new file mode 100644 (file)
index 0000000..31177a0
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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
diff --git a/src/variants/pthread_cond_legacy.c b/src/variants/pthread_cond_legacy.c
new file mode 100644 (file)
index 0000000..75ee354
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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
diff --git a/src/variants/pthread_mutex_legacy.c b/src/variants/pthread_mutex_legacy.c
new file mode 100644 (file)
index 0000000..ce00957
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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
diff --git a/src/variants/pthread_rwlock_legacy.c b/src/variants/pthread_rwlock_legacy.c
new file mode 100644 (file)
index 0000000..f0c9351
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * 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
diff --git a/sys/_pthread/_pthread_attr_t.h b/sys/_pthread/_pthread_attr_t.h
new file mode 100644 (file)
index 0000000..943f2a9
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 */
diff --git a/sys/_pthread/_pthread_cond_t.h b/sys/_pthread/_pthread_cond_t.h
new file mode 100644 (file)
index 0000000..4e901b6
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 */
diff --git a/sys/_pthread/_pthread_condattr_t.h b/sys/_pthread/_pthread_condattr_t.h
new file mode 100644 (file)
index 0000000..51b5cdd
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 */
diff --git a/sys/_pthread/_pthread_key_t.h b/sys/_pthread/_pthread_key_t.h
new file mode 100644 (file)
index 0000000..19d1f31
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 */
diff --git a/sys/_pthread/_pthread_mutex_t.h b/sys/_pthread/_pthread_mutex_t.h
new file mode 100644 (file)
index 0000000..75071c6
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 */
diff --git a/sys/_pthread/_pthread_mutexattr_t.h b/sys/_pthread/_pthread_mutexattr_t.h
new file mode 100644 (file)
index 0000000..f68cdcd
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 */
diff --git a/sys/_pthread/_pthread_once_t.h b/sys/_pthread/_pthread_once_t.h
new file mode 100644 (file)
index 0000000..18d12ef
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 */
diff --git a/sys/_pthread/_pthread_rwlock_t.h b/sys/_pthread/_pthread_rwlock_t.h
new file mode 100644 (file)
index 0000000..c1e9555
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 */
diff --git a/sys/_pthread/_pthread_rwlockattr_t.h b/sys/_pthread/_pthread_rwlockattr_t.h
new file mode 100644 (file)
index 0000000..5392701
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 */
diff --git a/sys/_pthread/_pthread_t.h b/sys/_pthread/_pthread_t.h
new file mode 100644 (file)
index 0000000..bf82918
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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 */
diff --git a/sys/_pthread/_pthread_types.h b/sys/_pthread/_pthread_types.h
new file mode 100644 (file)
index 0000000..d9d51b8
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * 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_
diff --git a/sys/qos.h b/sys/qos.h
new file mode 100644 (file)
index 0000000..9dec15d
--- /dev/null
+++ b/sys/qos.h
@@ -0,0 +1,194 @@
+/*
+ * 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
diff --git a/sys/qos_private.h b/sys/qos_private.h
new file mode 100644 (file)
index 0000000..0a38926
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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
diff --git a/xcodescripts/eos.xcconfig b/xcodescripts/eos.xcconfig
new file mode 100644 (file)
index 0000000..70f3caa
--- /dev/null
@@ -0,0 +1,6 @@
+#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 =
diff --git a/xcodescripts/install-codes.sh b/xcodescripts/install-codes.sh
new file mode 100644 (file)
index 0000000..685b494
--- /dev/null
@@ -0,0 +1,7 @@
+#!/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}"
diff --git a/xcodescripts/install-lldbmacros.sh b/xcodescripts/install-lldbmacros.sh
new file mode 100644 (file)
index 0000000..e50ee44
--- /dev/null
@@ -0,0 +1,5 @@
+#!/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/
diff --git a/xcodescripts/install-manpages.sh b/xcodescripts/install-manpages.sh
new file mode 100644 (file)
index 0000000..237872e
--- /dev/null
@@ -0,0 +1,148 @@
+#
+# 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
diff --git a/xcodescripts/install-symlinks.sh b/xcodescripts/install-symlinks.sh
new file mode 100644 (file)
index 0000000..5c20007
--- /dev/null
@@ -0,0 +1,41 @@
+#
+# 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"
diff --git a/xcodescripts/install-sys-headers.sh b/xcodescripts/install-sys-headers.sh
new file mode 100644 (file)
index 0000000..0e3f6b3
--- /dev/null
@@ -0,0 +1,62 @@
+#
+# 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
+
diff --git a/xcodescripts/kext.xcconfig b/xcodescripts/kext.xcconfig
new file mode 100644 (file)
index 0000000..dd41529
--- /dev/null
@@ -0,0 +1,43 @@
+// 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
diff --git a/xcodescripts/pthread.aliases b/xcodescripts/pthread.aliases
new file mode 100644 (file)
index 0000000..a71e089
--- /dev/null
@@ -0,0 +1,2 @@
+# aliases file for pthread old-symbol aliases
+# <symbol> <alias>
diff --git a/xcodescripts/pthread.xcconfig b/xcodescripts/pthread.xcconfig
new file mode 100644 (file)
index 0000000..7c2c274
--- /dev/null
@@ -0,0 +1,65 @@
+#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*] =