/* version number of the in-kernel shims given to pthread.kext */
#define PTHREAD_SHIMS_VERSION 1
+/* on arm, the callbacks function has two #ifdef arm ponters */
+#define PTHREAD_CALLBACK_MEMBER ml_get_max_cpus
+
+/* compile time asserts to check the length of structures in pthread_shims.h */
+char pthread_functions_size_compile_assert[(sizeof(struct pthread_functions_s) - offsetof(struct pthread_functions_s, psynch_rw_yieldwrlock) - sizeof(void*)) == (sizeof(void*) * 100) ? 1 : -1];
+char pthread_callbacks_size_compile_assert[(sizeof(struct pthread_callbacks_s) - offsetof(struct pthread_callbacks_s, PTHREAD_CALLBACK_MEMBER) - sizeof(void*)) == (sizeof(void*) * 100) ? 1 : -1];
+
/* old pthread code had definitions for these as they don't exist in headers */
extern kern_return_t mach_port_deallocate(ipc_space_t, mach_port_name_t);
extern kern_return_t semaphore_signal_internal_trap(mach_port_name_t);
PTHREAD_STRUCT_ACCESSOR(proc_get_pthsize, proc_set_pthsize, int, struct proc*, p_pthsize);
PTHREAD_STRUCT_ACCESSOR(proc_get_wqthread, proc_set_wqthread, user_addr_t, struct proc*, p_wqthread);
PTHREAD_STRUCT_ACCESSOR(proc_get_targconc, proc_set_targconc, user_addr_t, struct proc*, p_targconc);
+PTHREAD_STRUCT_ACCESSOR(proc_get_stack_addr_hint, proc_set_stack_addr_hint, user_addr_t, struct proc *, p_stack_addr_hint);
PTHREAD_STRUCT_ACCESSOR(proc_get_dispatchqueue_offset, proc_set_dispatchqueue_offset, uint64_t, struct proc*, p_dispatchqueue_offset);
PTHREAD_STRUCT_ACCESSOR(proc_get_dispatchqueue_serialno_offset, proc_set_dispatchqueue_serialno_offset, uint64_t, struct proc*, p_dispatchqueue_serialno_offset);
+PTHREAD_STRUCT_ACCESSOR(proc_get_pthread_tsd_offset, proc_set_pthread_tsd_offset, uint32_t, struct proc *, p_pth_tsd_offset);
PTHREAD_STRUCT_ACCESSOR(proc_get_wqptr, proc_set_wqptr, void*, struct proc*, p_wqptr);
PTHREAD_STRUCT_ACCESSOR(proc_get_wqsize, proc_set_wqsize, int, struct proc*, p_wqsize);
PTHREAD_STRUCT_ACCESSOR(proc_get_pthhash, proc_set_pthhash, void*, struct proc*, p_pthhash);
return current_map();
}
+static boolean_t
+qos_main_thread_active(void)
+{
+ return TRUE;
+}
+
+
+static int proc_usynch_get_requested_thread_qos(struct uthread *uth)
+{
+ task_t task = current_task();
+ thread_t thread = uth ? uth->uu_thread : current_thread();
+ int requested_qos;
+
+ requested_qos = proc_get_task_policy(task, thread, TASK_POLICY_ATTRIBUTE, TASK_POLICY_QOS);
+
+ /*
+ * For the purposes of userspace synchronization, it doesn't make sense to place an override of UNSPECIFIED
+ * on another thread, if the current thread doesn't have any QoS set. In these cases, upgrade to
+ * THREAD_QOS_USER_INTERACTIVE.
+ */
+ if (requested_qos == THREAD_QOS_UNSPECIFIED) {
+ requested_qos = THREAD_QOS_USER_INTERACTIVE;
+ }
+
+ return requested_qos;
+}
+
+static boolean_t proc_usynch_thread_qos_add_override(struct uthread *uth, uint64_t tid, int override_qos, boolean_t first_override_for_resource)
+{
+ task_t task = current_task();
+ thread_t thread = uth ? uth->uu_thread : THREAD_NULL;
+
+ return proc_thread_qos_add_override(task, thread, tid, override_qos, first_override_for_resource, USER_ADDR_NULL, THREAD_QOS_OVERRIDE_TYPE_UNKNOWN);
+}
+
+static boolean_t proc_usynch_thread_qos_remove_override(struct uthread *uth, uint64_t tid)
+{
+ task_t task = current_task();
+ thread_t thread = uth ? uth->uu_thread : THREAD_NULL;
+
+ return proc_thread_qos_remove_override(task, thread, tid, USER_ADDR_NULL, THREAD_QOS_OVERRIDE_TYPE_UNKNOWN);
+}
+
+static boolean_t proc_usynch_thread_qos_add_override_for_resource(task_t task, struct uthread *uth, uint64_t tid, int override_qos, boolean_t first_override_for_resource, user_addr_t resource, int resource_type)
+{
+ thread_t thread = uth ? uth->uu_thread : THREAD_NULL;
+
+ return proc_thread_qos_add_override(task, thread, tid, override_qos, first_override_for_resource, resource, resource_type);
+}
+
+static boolean_t proc_usynch_thread_qos_remove_override_for_resource(task_t task, struct uthread *uth, uint64_t tid, user_addr_t resource, int resource_type)
+{
+ thread_t thread = uth ? uth->uu_thread : THREAD_NULL;
+
+ return proc_thread_qos_remove_override(task, thread, tid, resource, resource_type);
+}
+
+static boolean_t proc_usynch_thread_qos_reset_override_for_resource(task_t task, struct uthread *uth, uint64_t tid, user_addr_t resource, int resource_type)
+{
+ thread_t thread = uth ? uth->uu_thread : THREAD_NULL;
+
+ return proc_thread_qos_reset_override(task, thread, tid, resource, resource_type);
+}
/* kernel (core) to kext shims */
int
bsdthread_register(struct proc *p, struct bsdthread_register_args *uap, __unused int32_t *retval)
{
- return pthread_functions->bsdthread_register(p, uap->threadstart, uap->wqthread, uap->pthsize, uap->dummy_value,
- uap->targetconc_ptr, uap->dispatchqueue_offset, retval);
+ if (pthread_functions->version >= 1) {
+ return pthread_functions->bsdthread_register2(p, uap->threadstart, uap->wqthread,
+ uap->flags, uap->stack_addr_hint,
+ uap->targetconc_ptr, uap->dispatchqueue_offset,
+ uap->tsd_offset, retval);
+ } else {
+ return pthread_functions->bsdthread_register(p, uap->threadstart, uap->wqthread,
+ uap->flags, uap->stack_addr_hint,
+ uap->targetconc_ptr, uap->dispatchqueue_offset,
+ retval);
+ }
}
int
return pthread_functions->bsdthread_terminate(p, uap->stackaddr, uap->freesize, uap->port, uap->sem, retval);
}
+int
+bsdthread_ctl(struct proc *p, struct bsdthread_ctl_args *uap, int *retval)
+{
+ return pthread_functions->bsdthread_ctl(p, uap->cmd, uap->arg1, uap->arg2, uap->arg3, retval);
+}
+
+
int
thread_selfid(struct proc *p, __unused struct thread_selfid_args *uap, uint64_t *retval)
{
return 0;
}
-/* unimplemented guard */
-
-// static void
-// unhooked_panic(void)
-// {
-// panic("pthread system call not hooked up");
-// }
-
/*
* The callbacks structure (defined in pthread_shims.h) contains a collection
* of kernel functions that were not deemed sensible to expose as a KPI to all
.thread_static_param = thread_static_param,
.thread_create_workq = thread_create_workq,
.thread_policy_set_internal = thread_policy_set_internal,
+ .thread_policy_get = thread_policy_get,
+ .thread_set_voucher_name = thread_set_voucher_name,
.thread_affinity_set = thread_affinity_set,
.proc_get_dispatchqueue_serialno_offset = proc_get_dispatchqueue_serialno_offset,
.proc_set_dispatchqueue_serialno_offset = proc_set_dispatchqueue_serialno_offset,
+
+ .proc_get_stack_addr_hint = proc_get_stack_addr_hint,
+ .proc_set_stack_addr_hint = proc_set_stack_addr_hint,
+ .proc_get_pthread_tsd_offset = proc_get_pthread_tsd_offset,
+ .proc_set_pthread_tsd_offset = proc_set_pthread_tsd_offset,
+
+ .thread_set_tsd_base = thread_set_tsd_base,
+
+ .proc_usynch_get_requested_thread_qos = proc_usynch_get_requested_thread_qos,
+ .proc_usynch_thread_qos_add_override = proc_usynch_thread_qos_add_override,
+ .proc_usynch_thread_qos_remove_override = proc_usynch_thread_qos_remove_override,
+
+ .qos_main_thread_active = qos_main_thread_active,
+
+ .proc_usynch_thread_qos_add_override_for_resource = proc_usynch_thread_qos_add_override_for_resource,
+ .proc_usynch_thread_qos_remove_override_for_resource = proc_usynch_thread_qos_remove_override_for_resource,
+ .proc_usynch_thread_qos_reset_override_for_resource = proc_usynch_thread_qos_reset_override_for_resource,
};
pthread_callbacks_t pthread_kern = &pthread_callbacks;