X-Git-Url: https://git.saurik.com/apple/libpthread.git/blobdiff_plain/f1a1da6cf65a9d0e6858678f6c259025cf5d27fd..a03d92013c2a24ebc4e02e5d1f575787f8467f6b:/src/qos.c?ds=sidebyside diff --git a/src/qos.c b/src/qos.c index e9c9993..59747f3 100644 --- a/src/qos.c +++ b/src/qos.c @@ -29,6 +29,7 @@ #include #include #include +#include // TODO: remove me when internal.h can include *_private.h itself #include "workqueue_private.h" @@ -42,8 +43,8 @@ static pthread_priority_t _main_qos = QOS_CLASS_UNSPECIFIED; struct pthread_override_s { uint32_t sig; - pthread_t pthread; mach_port_t kthread; + pthread_t pthread; pthread_priority_t priority; bool malloced; }; @@ -344,6 +345,20 @@ pthread_set_fixedpriority_self(void) } } +int +pthread_set_timeshare_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_TIMESHARE_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) @@ -365,7 +380,7 @@ pthread_override_qos_class_start_np(pthread_t __pthread, qos_class_t __qos_clas 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; + return (_Nonnull pthread_override_t) NULL; } } @@ -383,7 +398,7 @@ pthread_override_qos_class_start_np(pthread_t __pthread, qos_class_t __qos_clas } if (res == 0) { - res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_START, rv->kthread, rv->priority, 0); + res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_START, rv->kthread, rv->priority, (uintptr_t)rv); if (res != 0) { mach_port_mod_refs(mach_task_self(), rv->kthread, MACH_PORT_RIGHT_SEND, -1); @@ -398,7 +413,7 @@ pthread_override_qos_class_start_np(pthread_t __pthread, qos_class_t __qos_clas } rv = NULL; } - return rv; + return (_Nonnull pthread_override_t) rv; } int @@ -415,7 +430,7 @@ pthread_override_qos_class_end_np(pthread_override_t override) 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); + res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_END, override->kthread, (uintptr_t)override, 0); if (res == -1) { res = errno; } /* EFAULT from the syscall means we underflowed. Crash here. */ @@ -444,21 +459,35 @@ pthread_override_qos_class_end_np(pthread_override_t override) } int -_pthread_override_qos_class_start_direct(mach_port_t thread, pthread_priority_t priority) +_pthread_qos_override_start_direct(mach_port_t thread, pthread_priority_t priority, void *resource) { - int res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_START, thread, priority, 0); + int res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_START, thread, priority, (uintptr_t)resource); if (res == -1) { res = errno; } return res; } int -_pthread_override_qos_class_end_direct(mach_port_t thread) +_pthread_qos_override_end_direct(mach_port_t thread, void *resource) { - int res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_END, thread, 0, 0); + int res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_END, thread, (uintptr_t)resource, 0); if (res == -1) { res = errno; } return res; } +int +_pthread_override_qos_class_start_direct(mach_port_t thread, pthread_priority_t priority) +{ + // use pthread_self as the default per-thread memory allocation to track the override in the kernel + return _pthread_qos_override_start_direct(thread, priority, pthread_self()); +} + +int +_pthread_override_qos_class_end_direct(mach_port_t thread) +{ + // use pthread_self as the default per-thread memory allocation to track the override in the kernel + return _pthread_qos_override_end_direct(thread, pthread_self()); +} + int _pthread_workqueue_override_start_direct(mach_port_t thread, pthread_priority_t priority) { @@ -467,6 +496,47 @@ _pthread_workqueue_override_start_direct(mach_port_t thread, pthread_priority_t return res; } +int +_pthread_workqueue_override_start_direct_check_owner(mach_port_t thread, pthread_priority_t priority, mach_port_t *ulock_addr) +{ +#if !TARGET_OS_IPHONE + static boolean_t kernel_supports_owner_check = TRUE; + if (!kernel_supports_owner_check) { + ulock_addr = NULL; + } +#endif + + for (;;) { + int res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_OVERRIDE_DISPATCH, thread, priority, ulock_addr); + if (res == -1) { res = errno; } +#if !TARGET_OS_IPHONE + if (ulock_addr && res == EINVAL) { + if ((uintptr_t)ulock_addr % _Alignof(_Atomic uint32_t)) { + // do not mute bad ulock addresses related errors + return EINVAL; + } + // backward compatibility for the XBS chroot + // BSDTHREAD_CTL_QOS_OVERRIDE_DISPATCH used to return EINVAL if + // arg3 was non NULL. + kernel_supports_owner_check = FALSE; + ulock_addr = NULL; + continue; + } +#endif + if (ulock_addr && res == EFAULT) { + // kernel wants us to redrive the call, so while we refault the + // memory, also revalidate the owner + uint32_t uval = os_atomic_load(ulock_addr, relaxed); + if (ulock_owner_value_to_port_name(uval) != thread) { + return ESTALE; + } + continue; + } + + return res; + } +} + int _pthread_workqueue_override_reset(void) { @@ -475,6 +545,36 @@ _pthread_workqueue_override_reset(void) return res; } +int +_pthread_workqueue_asynchronous_override_add(mach_port_t thread, pthread_priority_t priority, void *resource) +{ + int res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_DISPATCH_ASYNCHRONOUS_OVERRIDE_ADD, thread, priority, (uintptr_t)resource); + if (res == -1) { res = errno; } + return res; +} + +int +_pthread_workqueue_asynchronous_override_reset_self(void *resource) +{ + int res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_DISPATCH_ASYNCHRONOUS_OVERRIDE_RESET, + 0 /* !reset_all */, + (uintptr_t)resource, + 0); + if (res == -1) { res = errno; } + return res; +} + +int +_pthread_workqueue_asynchronous_override_reset_all_self(void) +{ + int res = __bsdthread_ctl(BSDTHREAD_CTL_QOS_DISPATCH_ASYNCHRONOUS_OVERRIDE_RESET, + 1 /* reset_all */, + 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) {