]> git.saurik.com Git - apple/libpthread.git/blobdiff - src/qos.c
libpthread-218.20.1.tar.gz
[apple/libpthread.git] / src / qos.c
index e9c999398efa9604518351259b0c7c46190b94dd..59747f3451368b442f0315db439e1417644510ab 100644 (file)
--- a/src/qos.c
+++ b/src/qos.c
@@ -29,6 +29,7 @@
 #include <spawn.h>
 #include <spawn_private.h>
 #include <sys/spawn_internal.h>
+#include <sys/ulock.h>
 
 // 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)
 {