#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"
struct pthread_override_s
{
uint32_t sig;
- pthread_t pthread;
mach_port_t kthread;
+ pthread_t pthread;
pthread_priority_t priority;
bool malloced;
};
}
}
+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)
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;
}
}
}
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);
}
rv = NULL;
}
- return rv;
+ return (_Nonnull pthread_override_t) rv;
}
int
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. */
}
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)
{
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)
{
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)
{