From f1a1da6cf65a9d0e6858678f6c259025cf5d27fd Mon Sep 17 00:00:00 2001 From: Apple Date: Thu, 30 Oct 2014 23:07:19 +0000 Subject: [PATCH] libpthread-105.1.4.tar.gz --- kern/kern_init.c | 66 + kern/kern_internal.h | 304 +++ kern/kern_policy.c | 98 + kern/kern_support.c | 2545 +++++++++++++++++++++ kern/kern_synch.c | 2592 ++++++++++++++++++++++ kern/kern_trace.h | 111 + kern/pthread-Info.plist | 49 + kern/synch_internal.h | 165 ++ kern/workqueue_internal.h | 161 ++ libpthread.xcodeproj/project.pbxproj | 1091 +++++++++ lldbmacros/pthread.py | 154 ++ man/pthread.3 | 481 ++++ man/pthread_atfork.3 | 62 + man/pthread_attr.3 | 277 +++ man/pthread_attr_init_destroy.3 | 64 + man/pthread_attr_set_getdetachstate.3 | 86 + man/pthread_attr_set_getinheritsched.3 | 85 + man/pthread_attr_set_getschedparam.3 | 81 + man/pthread_attr_set_getschedpolicy.3 | 73 + man/pthread_attr_set_getscope.3 | 75 + man/pthread_attr_set_getstackaddr.3 | 74 + man/pthread_attr_set_getstacksize.3 | 78 + man/pthread_cancel.3 | 77 + man/pthread_cleanup_pop.3 | 66 + man/pthread_cleanup_push.3 | 71 + man/pthread_cond_broadcast.3 | 69 + man/pthread_cond_destroy.3 | 73 + man/pthread_cond_init.3 | 81 + man/pthread_cond_signal.3 | 68 + man/pthread_cond_timedwait.3 | 109 + man/pthread_cond_wait.3 | 89 + man/pthread_condattr.3 | 87 + man/pthread_create.3 | 141 ++ man/pthread_detach.3 | 89 + man/pthread_equal.3 | 69 + man/pthread_exit.3 | 104 + man/pthread_getschedparam.3 | 96 + man/pthread_getspecific.3 | 83 + man/pthread_join.3 | 103 + man/pthread_key_create.3 | 106 + man/pthread_key_delete.3 | 98 + man/pthread_kill.2 | 81 + man/pthread_mutex_destroy.3 | 72 + man/pthread_mutex_init.3 | 78 + man/pthread_mutex_lock.3 | 74 + man/pthread_mutex_trylock.3 | 75 + man/pthread_mutex_unlock.3 | 81 + man/pthread_mutexattr.3 | 302 +++ man/pthread_once.3 | 102 + man/pthread_rwlock_destroy.3 | 82 + man/pthread_rwlock_init.3 | 102 + man/pthread_rwlock_rdlock.3 | 126 ++ man/pthread_rwlock_unlock.3 | 81 + man/pthread_rwlock_wrlock.3 | 106 + man/pthread_rwlockattr_destroy.3 | 70 + man/pthread_rwlockattr_getpshared.3 | 83 + man/pthread_rwlockattr_init.3 | 69 + man/pthread_rwlockattr_setpshared.3 | 91 + man/pthread_self.3 | 59 + man/pthread_setcancelstate.3 | 241 ++ man/pthread_setspecific.3 | 95 + man/pthread_sigmask.2 | 104 + private/introspection_private.h | 107 + private/posix_sched.h | 69 + private/private.h | 55 + private/qos.h | 42 + private/qos_private.h | 166 ++ private/spinlock_private.h | 79 + private/tsd_private.h | 269 +++ private/workqueue_private.h | 124 ++ pthread/pthread.h | 519 +++++ pthread/pthread_impl.h | 58 + pthread/pthread_spis.h | 78 + pthread/qos.h | 296 +++ pthread/sched.h | 44 + pthread/spawn.h | 92 + src/internal.h | 528 +++++ src/mk_pthread_impl.c | 110 + src/plockstat.d | 24 + src/pthread.c | 2169 ++++++++++++++++++ src/pthread_asm.s | 161 ++ src/pthread_atfork.c | 162 ++ src/pthread_cancelable.c | 377 ++++ src/pthread_cond.c | 694 ++++++ src/pthread_mutex.c | 912 ++++++++ src/pthread_rwlock.c | 629 ++++++ src/pthread_support.c | 65 + src/pthread_tsd.c | 262 +++ src/qos.c | 523 +++++ src/thread_setup.c | 155 ++ src/variants/pthread_cancelable_cancel.c | 30 + src/variants/pthread_cancelable_legacy.c | 34 + src/variants/pthread_cond_legacy.c | 34 + src/variants/pthread_mutex_legacy.c | 34 + src/variants/pthread_rwlock_legacy.c | 34 + sys/_pthread/_pthread_attr_t.h | 31 + sys/_pthread/_pthread_cond_t.h | 31 + sys/_pthread/_pthread_condattr_t.h | 31 + sys/_pthread/_pthread_key_t.h | 31 + sys/_pthread/_pthread_mutex_t.h | 31 + sys/_pthread/_pthread_mutexattr_t.h | 31 + sys/_pthread/_pthread_once_t.h | 31 + sys/_pthread/_pthread_rwlock_t.h | 31 + sys/_pthread/_pthread_rwlockattr_t.h | 31 + sys/_pthread/_pthread_t.h | 31 + sys/_pthread/_pthread_types.h | 120 + sys/qos.h | 194 ++ sys/qos_private.h | 40 + xcodescripts/eos.xcconfig | 6 + xcodescripts/install-codes.sh | 7 + xcodescripts/install-lldbmacros.sh | 5 + xcodescripts/install-manpages.sh | 148 ++ xcodescripts/install-symlinks.sh | 41 + xcodescripts/install-sys-headers.sh | 62 + xcodescripts/kext.xcconfig | 43 + xcodescripts/pthread.aliases | 2 + xcodescripts/pthread.xcconfig | 65 + 117 files changed, 22603 insertions(+) create mode 100644 kern/kern_init.c create mode 100644 kern/kern_internal.h create mode 100644 kern/kern_policy.c create mode 100644 kern/kern_support.c create mode 100644 kern/kern_synch.c create mode 100644 kern/kern_trace.h create mode 100644 kern/pthread-Info.plist create mode 100644 kern/synch_internal.h create mode 100644 kern/workqueue_internal.h create mode 100644 libpthread.xcodeproj/project.pbxproj create mode 100644 lldbmacros/pthread.py create mode 100644 man/pthread.3 create mode 100644 man/pthread_atfork.3 create mode 100644 man/pthread_attr.3 create mode 100644 man/pthread_attr_init_destroy.3 create mode 100644 man/pthread_attr_set_getdetachstate.3 create mode 100644 man/pthread_attr_set_getinheritsched.3 create mode 100644 man/pthread_attr_set_getschedparam.3 create mode 100644 man/pthread_attr_set_getschedpolicy.3 create mode 100644 man/pthread_attr_set_getscope.3 create mode 100644 man/pthread_attr_set_getstackaddr.3 create mode 100644 man/pthread_attr_set_getstacksize.3 create mode 100644 man/pthread_cancel.3 create mode 100644 man/pthread_cleanup_pop.3 create mode 100644 man/pthread_cleanup_push.3 create mode 100644 man/pthread_cond_broadcast.3 create mode 100644 man/pthread_cond_destroy.3 create mode 100644 man/pthread_cond_init.3 create mode 100644 man/pthread_cond_signal.3 create mode 100644 man/pthread_cond_timedwait.3 create mode 100644 man/pthread_cond_wait.3 create mode 100644 man/pthread_condattr.3 create mode 100644 man/pthread_create.3 create mode 100644 man/pthread_detach.3 create mode 100644 man/pthread_equal.3 create mode 100644 man/pthread_exit.3 create mode 100644 man/pthread_getschedparam.3 create mode 100644 man/pthread_getspecific.3 create mode 100644 man/pthread_join.3 create mode 100644 man/pthread_key_create.3 create mode 100644 man/pthread_key_delete.3 create mode 100644 man/pthread_kill.2 create mode 100644 man/pthread_mutex_destroy.3 create mode 100644 man/pthread_mutex_init.3 create mode 100644 man/pthread_mutex_lock.3 create mode 100644 man/pthread_mutex_trylock.3 create mode 100644 man/pthread_mutex_unlock.3 create mode 100644 man/pthread_mutexattr.3 create mode 100644 man/pthread_once.3 create mode 100644 man/pthread_rwlock_destroy.3 create mode 100644 man/pthread_rwlock_init.3 create mode 100644 man/pthread_rwlock_rdlock.3 create mode 100644 man/pthread_rwlock_unlock.3 create mode 100644 man/pthread_rwlock_wrlock.3 create mode 100644 man/pthread_rwlockattr_destroy.3 create mode 100644 man/pthread_rwlockattr_getpshared.3 create mode 100644 man/pthread_rwlockattr_init.3 create mode 100644 man/pthread_rwlockattr_setpshared.3 create mode 100644 man/pthread_self.3 create mode 100644 man/pthread_setcancelstate.3 create mode 100644 man/pthread_setspecific.3 create mode 100644 man/pthread_sigmask.2 create mode 100644 private/introspection_private.h create mode 100644 private/posix_sched.h create mode 100644 private/private.h create mode 100644 private/qos.h create mode 100644 private/qos_private.h create mode 100644 private/spinlock_private.h create mode 100644 private/tsd_private.h create mode 100644 private/workqueue_private.h create mode 100644 pthread/pthread.h create mode 100644 pthread/pthread_impl.h create mode 100644 pthread/pthread_spis.h create mode 100644 pthread/qos.h create mode 100644 pthread/sched.h create mode 100644 pthread/spawn.h create mode 100644 src/internal.h create mode 100644 src/mk_pthread_impl.c create mode 100644 src/plockstat.d create mode 100644 src/pthread.c create mode 100644 src/pthread_asm.s create mode 100644 src/pthread_atfork.c create mode 100644 src/pthread_cancelable.c create mode 100644 src/pthread_cond.c create mode 100644 src/pthread_mutex.c create mode 100644 src/pthread_rwlock.c create mode 100644 src/pthread_support.c create mode 100644 src/pthread_tsd.c create mode 100644 src/qos.c create mode 100644 src/thread_setup.c create mode 100644 src/variants/pthread_cancelable_cancel.c create mode 100644 src/variants/pthread_cancelable_legacy.c create mode 100644 src/variants/pthread_cond_legacy.c create mode 100644 src/variants/pthread_mutex_legacy.c create mode 100644 src/variants/pthread_rwlock_legacy.c create mode 100644 sys/_pthread/_pthread_attr_t.h create mode 100644 sys/_pthread/_pthread_cond_t.h create mode 100644 sys/_pthread/_pthread_condattr_t.h create mode 100644 sys/_pthread/_pthread_key_t.h create mode 100644 sys/_pthread/_pthread_mutex_t.h create mode 100644 sys/_pthread/_pthread_mutexattr_t.h create mode 100644 sys/_pthread/_pthread_once_t.h create mode 100644 sys/_pthread/_pthread_rwlock_t.h create mode 100644 sys/_pthread/_pthread_rwlockattr_t.h create mode 100644 sys/_pthread/_pthread_t.h create mode 100644 sys/_pthread/_pthread_types.h create mode 100644 sys/qos.h create mode 100644 sys/qos_private.h create mode 100644 xcodescripts/eos.xcconfig create mode 100644 xcodescripts/install-codes.sh create mode 100644 xcodescripts/install-lldbmacros.sh create mode 100644 xcodescripts/install-manpages.sh create mode 100644 xcodescripts/install-symlinks.sh create mode 100644 xcodescripts/install-sys-headers.sh create mode 100644 xcodescripts/kext.xcconfig create mode 100644 xcodescripts/pthread.aliases create mode 100644 xcodescripts/pthread.xcconfig diff --git a/kern/kern_init.c b/kern/kern_init.c new file mode 100644 index 0000000..8b4b60a --- /dev/null +++ b/kern/kern_init.c @@ -0,0 +1,66 @@ +// +// pthread.c +// pthread +// +// Created by Matt Wright on 9/13/12. +// Copyright (c) 2012 Matt Wright. All rights reserved. +// + +#include +#include +#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 index 0000000..3c30213 --- /dev/null +++ b/kern/kern_internal.h @@ -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 +#include +#include +#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 + 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 + 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); \ + }) + +/* 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 index 0000000..23fb0d0 --- /dev/null +++ b/kern/kern_policy.c @@ -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 + +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 index 0000000..4d1907e --- /dev/null +++ b/kern/kern_support.c @@ -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 +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include /* for coredump */ +#include /* for fill_procworkqueue */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* for thread_exception_return */ +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include /* for thread_resume */ +#include + +#include + +#include +#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; + } + + /* 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 , 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 index 0000000..1996f3f --- /dev/null +++ b/kern/kern_synch.c @@ -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 +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +//#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +//#include +#include +#include + +#include + +#include +#include + +#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 index 0000000..701fa70 --- /dev/null +++ b/kern/kern_trace.h @@ -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 + +#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_ 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 index 0000000..7b35509 --- /dev/null +++ b/kern/pthread-Info.plist @@ -0,0 +1,49 @@ + + + + + OSBundleRequired + Root + AppleKernelExternalComponent + + OSBundleAllowUserLoad + + OSBundleCompatibleVersion + 1.0 + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + ${MODULE_NAME} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + KEXT + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSHumanReadableCopyright + Copyright © 2012 Apple Inc. All rights reserved. + OSBundleLibraries + + com.apple.kpi.bsd + 12.0 + com.apple.kpi.libkern + 11.2 + com.apple.kpi.mach + 11.2 + com.apple.kpi.private + 11.2 + com.apple.kpi.unsupported + 11.2 + + + diff --git a/kern/synch_internal.h b/kern/synch_internal.h new file mode 100644 index 0000000..a3e5594 --- /dev/null +++ b/kern/synch_internal.h @@ -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 index 0000000..47f52a8 --- /dev/null +++ b/kern/workqueue_internal.h @@ -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 index 0000000..966894b --- /dev/null +++ b/libpthread.xcodeproj/project.pbxproj @@ -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 = ""; }; + 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 = ""; }; + C9153094167ACAB8006BB094 /* install-symlinks.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "install-symlinks.sh"; sourceTree = ""; }; + C9153095167ACC22006BB094 /* private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = private.h; sourceTree = ""; }; + C9169DDB1603DE84005A2F8C /* kern_synch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kern_synch.c; sourceTree = ""; }; + C9169DDC1603DE84005A2F8C /* kern_support.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kern_support.c; sourceTree = ""; }; + C9169DDF1603DF9B005A2F8C /* kern_init.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kern_init.c; sourceTree = ""; }; + C91D01BA162893CD0002E29A /* kext.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = kext.xcconfig; sourceTree = ""; }; + C9244C1A185FCFED00075748 /* qos.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = qos.h; sourceTree = ""; }; + C9244C1C1860D8EF00075748 /* qos.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = qos.c; sourceTree = ""; }; + C948FCC115D187FA00180BF5 /* pthread_atfork.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_atfork.3; sourceTree = ""; }; + C948FCC215D187FA00180BF5 /* pthread_attr_init_destroy.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_init_destroy.3; sourceTree = ""; }; + C948FCC315D187FA00180BF5 /* pthread_attr_set_getdetachstate.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getdetachstate.3; sourceTree = ""; }; + C948FCC415D187FA00180BF5 /* pthread_attr_set_getinheritsched.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getinheritsched.3; sourceTree = ""; }; + C948FCC515D187FA00180BF5 /* pthread_attr_set_getschedparam.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getschedparam.3; sourceTree = ""; }; + C948FCC615D187FA00180BF5 /* pthread_attr_set_getschedpolicy.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getschedpolicy.3; sourceTree = ""; }; + C948FCC715D187FA00180BF5 /* pthread_attr_set_getscope.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getscope.3; sourceTree = ""; }; + C948FCC815D187FA00180BF5 /* pthread_attr_set_getstackaddr.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getstackaddr.3; sourceTree = ""; }; + C948FCC915D187FA00180BF5 /* pthread_attr_set_getstacksize.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr_set_getstacksize.3; sourceTree = ""; }; + C948FCCA15D187FA00180BF5 /* pthread_attr.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_attr.3; sourceTree = ""; }; + C948FCCB15D187FA00180BF5 /* pthread_cancel.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cancel.3; sourceTree = ""; }; + C948FCCC15D187FA00180BF5 /* pthread_cleanup_pop.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cleanup_pop.3; sourceTree = ""; }; + C948FCCD15D187FA00180BF5 /* pthread_cleanup_push.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cleanup_push.3; sourceTree = ""; }; + C948FCCE15D187FA00180BF5 /* pthread_cond_broadcast.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cond_broadcast.3; sourceTree = ""; }; + C948FCCF15D187FA00180BF5 /* pthread_cond_destroy.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cond_destroy.3; sourceTree = ""; }; + C948FCD015D187FA00180BF5 /* pthread_cond_init.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cond_init.3; sourceTree = ""; }; + C948FCD115D187FA00180BF5 /* pthread_cond_signal.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cond_signal.3; sourceTree = ""; }; + C948FCD215D187FA00180BF5 /* pthread_cond_timedwait.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cond_timedwait.3; sourceTree = ""; }; + C948FCD315D187FA00180BF5 /* pthread_cond_wait.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_cond_wait.3; sourceTree = ""; }; + C948FCD415D187FA00180BF5 /* pthread_condattr.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_condattr.3; sourceTree = ""; }; + C948FCD515D187FA00180BF5 /* pthread_create.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_create.3; sourceTree = ""; }; + C948FCD615D187FA00180BF5 /* pthread_detach.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_detach.3; sourceTree = ""; }; + C948FCD715D187FA00180BF5 /* pthread_equal.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_equal.3; sourceTree = ""; }; + C948FCD815D187FA00180BF5 /* pthread_exit.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_exit.3; sourceTree = ""; }; + C948FCD915D187FA00180BF5 /* pthread_getschedparam.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_getschedparam.3; sourceTree = ""; }; + C948FCDA15D187FA00180BF5 /* pthread_getspecific.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_getspecific.3; sourceTree = ""; }; + C948FCDB15D187FA00180BF5 /* pthread_join.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_join.3; sourceTree = ""; }; + C948FCDC15D187FA00180BF5 /* pthread_key_create.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_key_create.3; sourceTree = ""; }; + C948FCDD15D187FA00180BF5 /* pthread_key_delete.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_key_delete.3; sourceTree = ""; }; + C948FCDE15D187FA00180BF5 /* pthread_mutex_destroy.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_mutex_destroy.3; sourceTree = ""; }; + C948FCDF15D187FA00180BF5 /* pthread_mutex_init.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_mutex_init.3; sourceTree = ""; }; + C948FCE015D187FA00180BF5 /* pthread_mutex_lock.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_mutex_lock.3; sourceTree = ""; }; + C948FCE115D187FA00180BF5 /* pthread_mutex_trylock.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_mutex_trylock.3; sourceTree = ""; }; + C948FCE215D187FA00180BF5 /* pthread_mutex_unlock.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_mutex_unlock.3; sourceTree = ""; }; + C948FCE315D187FA00180BF5 /* pthread_mutexattr.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_mutexattr.3; sourceTree = ""; }; + C948FCE415D187FA00180BF5 /* pthread_once.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_once.3; sourceTree = ""; }; + C948FCE515D187FA00180BF5 /* pthread_rwlock_destroy.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlock_destroy.3; sourceTree = ""; }; + C948FCE615D187FA00180BF5 /* pthread_rwlock_init.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlock_init.3; sourceTree = ""; }; + C948FCE715D187FA00180BF5 /* pthread_rwlock_rdlock.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlock_rdlock.3; sourceTree = ""; }; + C948FCE815D187FA00180BF5 /* pthread_rwlock_unlock.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlock_unlock.3; sourceTree = ""; }; + C948FCE915D187FA00180BF5 /* pthread_rwlock_wrlock.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlock_wrlock.3; sourceTree = ""; }; + C948FCEA15D187FA00180BF5 /* pthread_rwlockattr_destroy.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlockattr_destroy.3; sourceTree = ""; }; + C948FCEB15D187FA00180BF5 /* pthread_rwlockattr_getpshared.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlockattr_getpshared.3; sourceTree = ""; }; + C948FCEC15D187FA00180BF5 /* pthread_rwlockattr_init.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlockattr_init.3; sourceTree = ""; }; + C948FCED15D187FA00180BF5 /* pthread_rwlockattr_setpshared.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_rwlockattr_setpshared.3; sourceTree = ""; }; + C948FCEE15D187FA00180BF5 /* pthread_self.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_self.3; sourceTree = ""; }; + C948FCEF15D187FA00180BF5 /* pthread_setcancelstate.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_setcancelstate.3; sourceTree = ""; }; + C948FCF015D187FA00180BF5 /* pthread_setspecific.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread_setspecific.3; sourceTree = ""; }; + C948FCF115D187FA00180BF5 /* pthread.3 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = pthread.3; sourceTree = ""; }; + C975D5D615C9CECA0098ECD8 /* pthread_cond_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_cond_legacy.c; sourceTree = ""; }; + C975D5D815C9CEEA0098ECD8 /* pthread_mutex_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_mutex_legacy.c; sourceTree = ""; }; + C975D5DA15C9CEFA0098ECD8 /* pthread_rwlock_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_rwlock_legacy.c; sourceTree = ""; }; + C975D5DC15C9D16B0098ECD8 /* pthread_support.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_support.c; sourceTree = ""; }; + C979E9FB18A1BC2A000951E5 /* kern_trace.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = kern_trace.h; sourceTree = ""; }; + C979E9FC18A2BF2C000951E5 /* install-codes.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "install-codes.sh"; sourceTree = ""; }; + C98005141899BD2000368E4D /* workqueue_internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = workqueue_internal.h; sourceTree = ""; }; + C98C95D818FF1F4E005654FB /* spawn.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = spawn.h; sourceTree = ""; }; + C99AD87D15DF04D10009A6F8 /* pthread_asm.s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.asm; path = pthread_asm.s; sourceTree = ""; }; + C99B17DA189C2E1B00991D38 /* qos_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = qos_private.h; sourceTree = ""; }; + C99EA612161F8288003EBC56 /* eos.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = eos.xcconfig; sourceTree = ""; }; + C9A1BF5215C9A9F5006BB313 /* pthread_cancelable_cancel.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_cancelable_cancel.c; sourceTree = ""; }; + C9A1BF5415C9CB9D006BB313 /* pthread_cancelable_legacy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = pthread_cancelable_legacy.c; sourceTree = ""; }; + 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 = ""; }; + C9A325EF15B7513200270056 /* plockstat.d */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.dtrace; path = plockstat.d; sourceTree = ""; }; + C9A325F015B7513200270056 /* posix_sched.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = posix_sched.h; sourceTree = ""; }; + C9A325F115B7513200270056 /* pthread_cancelable.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread_cancelable.c; sourceTree = ""; }; + C9A325F215B7513200270056 /* pthread_cond.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread_cond.c; sourceTree = ""; }; + C9A325F315B7513200270056 /* internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = internal.h; sourceTree = ""; }; + C9A325F415B7513200270056 /* tsd_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = tsd_private.h; sourceTree = ""; }; + C9A325F515B7513200270056 /* pthread_mutex.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread_mutex.c; sourceTree = ""; }; + C9A325F615B7513200270056 /* pthread_rwlock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread_rwlock.c; sourceTree = ""; }; + C9A325F715B7513200270056 /* spinlock_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = spinlock_private.h; sourceTree = ""; }; + C9A325F815B7513200270056 /* pthread_tsd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread_tsd.c; sourceTree = ""; }; + C9A325F915B7513200270056 /* workqueue_private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = workqueue_private.h; sourceTree = ""; }; + C9A325FA15B7513200270056 /* pthread.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pthread.c; sourceTree = ""; }; + C9A325FC15B7513200270056 /* thread_setup.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = thread_setup.c; sourceTree = ""; }; + C9A325FE15B7513700270056 /* pthread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pthread.h; sourceTree = ""; }; + C9A325FF15B7513700270056 /* pthread_impl.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pthread_impl.h; sourceTree = ""; }; + C9A3260015B7513700270056 /* pthread_spis.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = pthread_spis.h; sourceTree = ""; }; + C9A3260115B7513700270056 /* sched.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sched.h; sourceTree = ""; }; + C9A3260C15B759B600270056 /* pthread.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = pthread.xcconfig; sourceTree = ""; }; + C9A960AF183EB42700AE10C8 /* kern_policy.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = kern_policy.c; sourceTree = ""; }; + C9A960B318452B2F00AE10C8 /* pthread.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = pthread.py; sourceTree = ""; }; + C9A960B618452CDD00AE10C8 /* install-lldbmacros.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "install-lldbmacros.sh"; sourceTree = ""; }; + C9C2212D15FA978D00447568 /* pthread.aliases */ = {isa = PBXFileReference; lastKnownFileType = text; path = pthread.aliases; sourceTree = ""; }; + C9C533841607C928009988FA /* kern_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = kern_internal.h; sourceTree = ""; }; + 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 = ""; }; + C9DCA2A115DC4F2000D057E2 /* install-manpages.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "install-manpages.sh"; sourceTree = ""; }; + E4063CF21906B4FB000202F9 /* qos.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = qos.h; sourceTree = ""; }; + E4657D4017284F7B007D1847 /* introspection_private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = introspection_private.h; sourceTree = ""; }; + E4D962F919086AD600E8A9F2 /* qos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = qos.h; sourceTree = ""; }; + E4D962FC19086C5700E8A9F2 /* install-sys-headers.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "install-sys-headers.sh"; sourceTree = ""; }; + FC30E28D16A747AD00A25B5F /* synch_internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = synch_internal.h; sourceTree = ""; }; + FC5A372417CEB3D6008C323E /* _pthread_attr_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_attr_t.h; sourceTree = ""; }; + FC5A372517CEB3D6008C323E /* _pthread_cond_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_cond_t.h; sourceTree = ""; }; + FC5A372617CEB3D6008C323E /* _pthread_condattr_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_condattr_t.h; sourceTree = ""; }; + FC5A372717CEB3D6008C323E /* _pthread_key_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_key_t.h; sourceTree = ""; }; + FC5A372817CEB3D6008C323E /* _pthread_mutex_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_mutex_t.h; sourceTree = ""; }; + FC5A372917CEB3D6008C323E /* _pthread_mutexattr_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_mutexattr_t.h; sourceTree = ""; }; + FC5A372A17CEB3D6008C323E /* _pthread_once_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_once_t.h; sourceTree = ""; }; + FC5A372B17CEB3D6008C323E /* _pthread_rwlock_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_rwlock_t.h; sourceTree = ""; }; + FC5A372C17CEB3D6008C323E /* _pthread_rwlockattr_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_rwlockattr_t.h; sourceTree = ""; }; + FC5A372D17CEB3D6008C323E /* _pthread_t.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_t.h; sourceTree = ""; }; + FC5A372E17CEB3D6008C323E /* _pthread_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = _pthread_types.h; sourceTree = ""; }; + FC618A76160E8155006810FE /* pthread_kill.2 */ = {isa = PBXFileReference; lastKnownFileType = text; path = pthread_kill.2; sourceTree = ""; }; + FC618A77160E8155006810FE /* pthread_sigmask.2 */ = {isa = PBXFileReference; lastKnownFileType = text; path = pthread_sigmask.2; sourceTree = ""; }; +/* 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + usesTabs = 1; + }; + C9A325E315B7347000270056 /* Products */ = { + isa = PBXGroup; + children = ( + C9A325E215B7347000270056 /* libsystem_pthread.dylib */, + C90E7A9F15DC3C3800A06D48 /* libpthread.a */, + 74E594A41613AAF4006C417B /* libpthread_eOS.a */, + C9CA27D91602813000259F78 /* pthread.kext */, + ); + name = Products; + sourceTree = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + 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 = ""; + }; + C9A960B218452B0700AE10C8 /* lldbmacros */ = { + isa = PBXGroup; + children = ( + C9A960B318452B2F00AE10C8 /* pthread.py */, + ); + path = lldbmacros; + sourceTree = ""; + }; + C9CA27DA1602813000259F78 /* Frameworks */ = { + isa = PBXGroup; + children = ( + C9CA27DB1602813000259F78 /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = ""; + }; + C9CA27DB1602813000259F78 /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + C9CA27DC1602813000259F78 /* Kernel.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 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 = ""; + }; + FC5A372217CEB3D6008C323E /* sys */ = { + isa = PBXGroup; + children = ( + E4D962F919086AD600E8A9F2 /* qos.h */, + FC5A372317CEB3D6008C323E /* _pthread */, + A98FE72D19479F7C007718DA /* qos_private.h */, + ); + path = sys; + sourceTree = ""; + }; + 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 = ""; + }; +/* 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 index 0000000..6b0c66a --- /dev/null +++ b/lldbmacros/pthread.py @@ -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 + """ + 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 + """ + 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 + """ + + 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 index 0000000..6f07565 --- /dev/null +++ b/man/pthread.3 @@ -0,0 +1,481 @@ +.\" Portions Copyright (c) 2001 Apple Computer, Inc. All Rights Reserved. +.\" Copyright (c) 1996 John Birrell . +.\" 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 +.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 index 0000000..d0b0b84 --- /dev/null +++ b/man/pthread_atfork.3 @@ -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 +.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 index 0000000..1019425 --- /dev/null +++ b/man/pthread_attr.3 @@ -0,0 +1,277 @@ +.\" Copyright (C) 2000 Jason Evans . +.\" 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 +.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 index 0000000..236a093 --- /dev/null +++ b/man/pthread_attr_init_destroy.3 @@ -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 +.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 index 0000000..ee30399 --- /dev/null +++ b/man/pthread_attr_set_getdetachstate.3 @@ -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 +.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 index 0000000..b5e52cc --- /dev/null +++ b/man/pthread_attr_set_getinheritsched.3 @@ -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 +.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 index 0000000..dff13e4 --- /dev/null +++ b/man/pthread_attr_set_getschedparam.3 @@ -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 +.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 index 0000000..d83e7a4 --- /dev/null +++ b/man/pthread_attr_set_getschedpolicy.3 @@ -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 +.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 index 0000000..2005297 --- /dev/null +++ b/man/pthread_attr_set_getscope.3 @@ -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 +.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 index 0000000..cf725ae --- /dev/null +++ b/man/pthread_attr_set_getstackaddr.3 @@ -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 +.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 index 0000000..3aadea6 --- /dev/null +++ b/man/pthread_attr_set_getstacksize.3 @@ -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 +.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 index 0000000..fae332e --- /dev/null +++ b/man/pthread_cancel.3 @@ -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 +.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 index 0000000..f6d0401 --- /dev/null +++ b/man/pthread_cleanup_pop.3 @@ -0,0 +1,66 @@ +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..91ec386 --- /dev/null +++ b/man/pthread_cleanup_push.3 @@ -0,0 +1,71 @@ +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..279636d --- /dev/null +++ b/man/pthread_cond_broadcast.3 @@ -0,0 +1,69 @@ +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..523bf8a --- /dev/null +++ b/man/pthread_cond_destroy.3 @@ -0,0 +1,73 @@ +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..a69fbac --- /dev/null +++ b/man/pthread_cond_init.3 @@ -0,0 +1,81 @@ +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..669b6fc --- /dev/null +++ b/man/pthread_cond_signal.3 @@ -0,0 +1,68 @@ +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..dbf48e4 --- /dev/null +++ b/man/pthread_cond_timedwait.3 @@ -0,0 +1,109 @@ +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..efe6ac2 --- /dev/null +++ b/man/pthread_cond_wait.3 @@ -0,0 +1,89 @@ +.\" Portions Copyright (c) 2001 Apple Computer, Inc. All Rights Reserved. +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..4db5027 --- /dev/null +++ b/man/pthread_condattr.3 @@ -0,0 +1,87 @@ +.\" Copyright (C) 2000 Jason Evans . +.\" 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 index 0000000..589b103 --- /dev/null +++ b/man/pthread_create.3 @@ -0,0 +1,141 @@ +.\" Copyright (c) 1996 John Birrell . +.\" 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 +.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 index 0000000..f354951 --- /dev/null +++ b/man/pthread_detach.3 @@ -0,0 +1,89 @@ +.\" Copyright (c) 1996-1998 John Birrell . +.\" 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 +.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 index 0000000..c865329 --- /dev/null +++ b/man/pthread_equal.3 @@ -0,0 +1,69 @@ +.\" Copyright (c) 1996 John Birrell . +.\" 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 +.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 index 0000000..52b8403 --- /dev/null +++ b/man/pthread_exit.3 @@ -0,0 +1,104 @@ +.\" Copyright (c) 1996 John Birrell . +.\" 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 +.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 index 0000000..854596c --- /dev/null +++ b/man/pthread_getschedparam.3 @@ -0,0 +1,96 @@ +.\" Copyright (C) 2000 Jason Evans . +.\" 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 +.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 index 0000000..642aed8 --- /dev/null +++ b/man/pthread_getspecific.3 @@ -0,0 +1,83 @@ +.\" Copyright (c) 1996 John Birrell . +.\" 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 +.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 index 0000000..6402393 --- /dev/null +++ b/man/pthread_join.3 @@ -0,0 +1,103 @@ +.\" Copyright (c) 1996-1998 John Birrell . +.\" 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 +.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 index 0000000..429f872 --- /dev/null +++ b/man/pthread_key_create.3 @@ -0,0 +1,106 @@ +.\" Copyright (c) 1996 John Birrell . +.\" 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 +.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 index 0000000..013ecd4 --- /dev/null +++ b/man/pthread_key_delete.3 @@ -0,0 +1,98 @@ +.\" Copyright (c) 1996 John Birrell . +.\" 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 +.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 index 0000000..8c83b99 --- /dev/null +++ b/man/pthread_kill.2 @@ -0,0 +1,81 @@ +.\" Darwin +.\" +.\" Copyright (C) 2000 Jason Evans . +.\" 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 +.Fd #include +.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 index 0000000..17207f3 --- /dev/null +++ b/man/pthread_mutex_destroy.3 @@ -0,0 +1,72 @@ +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..bebe8a2 --- /dev/null +++ b/man/pthread_mutex_init.3 @@ -0,0 +1,78 @@ +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..e0a4fad --- /dev/null +++ b/man/pthread_mutex_lock.3 @@ -0,0 +1,74 @@ +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..345a014 --- /dev/null +++ b/man/pthread_mutex_trylock.3 @@ -0,0 +1,75 @@ +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..ae29010 --- /dev/null +++ b/man/pthread_mutex_unlock.3 @@ -0,0 +1,81 @@ +.\" Copyright (c) 1997 Brian Cully +.\" 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 +.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 index 0000000..9f6ac0c --- /dev/null +++ b/man/pthread_mutexattr.3 @@ -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 . +.\" 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 +.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 index 0000000..1a84320 --- /dev/null +++ b/man/pthread_once.3 @@ -0,0 +1,102 @@ +.\" Copyright (c) 1996 John Birrell . +.\" 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 +.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 index 0000000..47beb62 --- /dev/null +++ b/man/pthread_rwlock_destroy.3 @@ -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 index 0000000..507317a --- /dev/null +++ b/man/pthread_rwlock_init.3 @@ -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 index 0000000..815da8c --- /dev/null +++ b/man/pthread_rwlock_rdlock.3 @@ -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 index 0000000..def7aaf --- /dev/null +++ b/man/pthread_rwlock_unlock.3 @@ -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 index 0000000..5906e4b --- /dev/null +++ b/man/pthread_rwlock_wrlock.3 @@ -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 index 0000000..3d45228 --- /dev/null +++ b/man/pthread_rwlockattr_destroy.3 @@ -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 index 0000000..61dcc73 --- /dev/null +++ b/man/pthread_rwlockattr_getpshared.3 @@ -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 index 0000000..1d75a3c --- /dev/null +++ b/man/pthread_rwlockattr_init.3 @@ -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 index 0000000..d8702b9 --- /dev/null +++ b/man/pthread_rwlockattr_setpshared.3 @@ -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 index 0000000..d7c2bcd --- /dev/null +++ b/man/pthread_self.3 @@ -0,0 +1,59 @@ +.\" Copyright (c) 1996 John Birrell . +.\" 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 +.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 index 0000000..0e451ab --- /dev/null +++ b/man/pthread_setcancelstate.3 @@ -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 +.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 index 0000000..96104b4 --- /dev/null +++ b/man/pthread_setspecific.3 @@ -0,0 +1,95 @@ +.\" Copyright (c) 1996 John Birrell . +.\" 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 +.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 index 0000000..5680dd2 --- /dev/null +++ b/man/pthread_sigmask.2 @@ -0,0 +1,104 @@ +.\" Copyright (C) 2000 Jason Evans . +.\" 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 +.Fd #include +.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 index 0000000..04c7c92 --- /dev/null +++ b/private/introspection_private.h @@ -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 +#include +#include + +/*! + * @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 index 0000000..8bbc4a5 --- /dev/null +++ b/private/posix_sched.h @@ -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 index 0000000..d59f161 --- /dev/null +++ b/private/private.h @@ -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 +#include +#include + +/* 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 index 0000000..b316a74 --- /dev/null +++ b/private/qos.h @@ -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 + +#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL + +// +#define QOS_CLASS_LEGACY QOS_CLASS_DEFAULT + +#ifdef __has_include +#if __has_include() +#include +#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 index 0000000..46763fa --- /dev/null +++ b/private/qos_private.h @@ -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 +#include + +#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL +// allow __DARWIN_C_LEVEL to turn off the use of mach_port_t +#include +#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 index 0000000..a09fb04 --- /dev/null +++ b/private/spinlock_private.h @@ -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 +#include +#include + +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 index 0000000..1737c97 --- /dev/null +++ b/private/tsd_private.h @@ -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 +#include +#include +#include +#include + +#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 index 0000000..aaaf402 --- /dev/null +++ b/private/workqueue_private.h @@ -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 +#include +#include +#include +#ifndef _PTHREAD_BUILDING_PTHREAD_ +#include +#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 index 0000000..4169176 --- /dev/null +++ b/pthread/pthread.h @@ -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 +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#if (!defined(_POSIX_C_SOURCE) && !defined(_XOPEN_SOURCE)) || defined(_DARWIN_C_SOURCE) + +#include +#include + +#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 + * #ifdef _POSIX_THREADS + * #include + * #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 + */ + +#include +#include + +__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}} + +/* */ +#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 index 0000000..887b56d --- /dev/null +++ b/pthread/pthread_impl.h @@ -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 index 0000000..b76c238 --- /dev/null +++ b/pthread/pthread_spis.h @@ -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 + +__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 index 0000000..fa0f832 --- /dev/null +++ b/pthread/qos.h @@ -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 +#include + +#if __DARWIN_C_LEVEL >= __DARWIN_C_FULL + +#include + +#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 index 0000000..df1fc51 --- /dev/null +++ b/pthread/sched.h @@ -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 +#include + +__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 index 0000000..11af0fe --- /dev/null +++ b/pthread/spawn.h @@ -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 +#include + +__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 index 0000000..057428f --- /dev/null +++ b/src/internal.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 + 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 +#include + +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 index 0000000..8654c45 --- /dev/null +++ b/src/mk_pthread_impl.c @@ -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 in a machine dependent fashion. + */ + +#include +#include + +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 index 0000000..0b6a5cc --- /dev/null +++ b/src/plockstat.d @@ -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 index 0000000..de2d6db --- /dev/null +++ b/src/pthread.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define __APPLE_API_PRIVATE +#include +#include + +#include <_simple.h> +#include +#include + +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 +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); + } +} + +// 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 index 0000000..df03a25 --- /dev/null +++ b/src/pthread_asm.s @@ -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 + + .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 + + .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 + + .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 index 0000000..724a7fb --- /dev/null +++ b/src/pthread_atfork.c @@ -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 +#include +#include +#include + +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 index 0000000..c875451 --- /dev/null +++ b/src/pthread_cancelable.c @@ -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 /* For printf(). */ +#include +#include /* For __mach_errno_addr() prototype. */ +#include +#include +#include +#include +#include +#include +#include + +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 index 0000000..a425fbe --- /dev/null +++ b/src/pthread_cond.c @@ -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 /* For struct timespec and getclock(). */ +#include + +#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); + + // 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 index 0000000..794b6ff --- /dev/null +++ b/src/pthread_mutex.c @@ -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 + +#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 + +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 */ + // 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 index 0000000..c7b5373 --- /dev/null +++ b/src/pthread_rwlock.c @@ -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 /* 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 +#include + +__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 index 0000000..5ae4239 --- /dev/null +++ b/src/pthread_support.c @@ -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 +#include <_simple.h> +#include + +#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 index 0000000..e3fffe7 --- /dev/null +++ b/src/pthread_tsd.c @@ -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 + +#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 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 +#include +#include +#include +#include + +// 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) { + // 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 index 0000000..3f7a8d0 --- /dev/null +++ b/src/thread_setup.c @@ -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 + +/* + * 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 index 0000000..17bf513 --- /dev/null +++ b/src/variants/pthread_cancelable_cancel.c @@ -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 index 0000000..31177a0 --- /dev/null +++ b/src/variants/pthread_cancelable_legacy.c @@ -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 +#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 index 0000000..75ee354 --- /dev/null +++ b/src/variants/pthread_cond_legacy.c @@ -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 +#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 index 0000000..ce00957 --- /dev/null +++ b/src/variants/pthread_mutex_legacy.c @@ -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 +#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 index 0000000..f0c9351 --- /dev/null +++ b/src/variants/pthread_rwlock_legacy.c @@ -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 +#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 index 0000000..943f2a9 --- /dev/null +++ b/sys/_pthread/_pthread_attr_t.h @@ -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 index 0000000..4e901b6 --- /dev/null +++ b/sys/_pthread/_pthread_cond_t.h @@ -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 index 0000000..51b5cdd --- /dev/null +++ b/sys/_pthread/_pthread_condattr_t.h @@ -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 index 0000000..19d1f31 --- /dev/null +++ b/sys/_pthread/_pthread_key_t.h @@ -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 index 0000000..75071c6 --- /dev/null +++ b/sys/_pthread/_pthread_mutex_t.h @@ -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 index 0000000..f68cdcd --- /dev/null +++ b/sys/_pthread/_pthread_mutexattr_t.h @@ -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 index 0000000..18d12ef --- /dev/null +++ b/sys/_pthread/_pthread_once_t.h @@ -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 index 0000000..c1e9555 --- /dev/null +++ b/sys/_pthread/_pthread_rwlock_t.h @@ -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 index 0000000..5392701 --- /dev/null +++ b/sys/_pthread/_pthread_rwlockattr_t.h @@ -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 index 0000000..bf82918 --- /dev/null +++ b/sys/_pthread/_pthread_t.h @@ -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 index 0000000..d9d51b8 --- /dev/null +++ b/sys/_pthread/_pthread_types.h @@ -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 + +// 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 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 +#include + +/*! + * @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 index 0000000..0a38926 --- /dev/null +++ b/sys/qos_private.h @@ -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 index 0000000..70f3caa --- /dev/null +++ b/xcodescripts/eos.xcconfig @@ -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 index 0000000..685b494 --- /dev/null +++ b/xcodescripts/install-codes.sh @@ -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 index 0000000..e50ee44 --- /dev/null +++ b/xcodescripts/install-lldbmacros.sh @@ -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 index 0000000..237872e --- /dev/null +++ b/xcodescripts/install-manpages.sh @@ -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 index 0000000..5c20007 --- /dev/null +++ b/xcodescripts/install-symlinks.sh @@ -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 index 0000000..0e3f6b3 --- /dev/null +++ b/xcodescripts/install-sys-headers.sh @@ -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 index 0000000..dd41529 --- /dev/null +++ b/xcodescripts/kext.xcconfig @@ -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 index 0000000..a71e089 --- /dev/null +++ b/xcodescripts/pthread.aliases @@ -0,0 +1,2 @@ +# aliases file for pthread old-symbol aliases +# diff --git a/xcodescripts/pthread.xcconfig b/xcodescripts/pthread.xcconfig new file mode 100644 index 0000000..7c2c274 --- /dev/null +++ b/xcodescripts/pthread.xcconfig @@ -0,0 +1,65 @@ +#include "/Makefiles/CoreOS/Xcode/BSD.xcconfig" +#include "/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*] = -- 2.45.2