ipc_pthread_priority.c [plain text]
#include <voucher/ipc_pthread_priority_types.h>
#include <voucher/ipc_pthread_priority_internal.h>
#include <mach/mach_types.h>
#include <mach/kern_return.h>
#include <ipc/ipc_port.h>
#include <mach/mach_vm.h>
#include <mach/vm_map.h>
#include <vm/vm_map.h>
#include <mach/host_priv.h>
#include <mach/host_special_ports.h>
#include <kern/host.h>
#include <kern/kalloc.h>
#include <kern/ledger.h>
#include <sys/kdebug.h>
#include <IOKit/IOBSD.h>
#include <mach/mach_voucher_attr_control.h>
ipc_voucher_attr_control_t ipc_pthread_priority_voucher_attr_control;
#define IPC_PTHREAD_PRIORITY_VALUE_TO_HANDLE(x) ((mach_voucher_attr_value_handle_t)(x))
#define HANDLE_TO_IPC_PTHREAD_PRIORITY_VALUE(x) ((ipc_pthread_priority_value_t)(x))
extern unsigned long pthread_priority_canonicalize(unsigned long priority, boolean_t for_propagation);
kern_return_t
ipc_pthread_priority_release_value(
ipc_voucher_attr_manager_t __assert_only manager,
mach_voucher_attr_key_t __assert_only key,
mach_voucher_attr_value_handle_t value,
mach_voucher_attr_value_reference_t sync);
kern_return_t
ipc_pthread_priority_get_value(
ipc_voucher_attr_manager_t __assert_only manager,
mach_voucher_attr_key_t __assert_only key,
mach_voucher_attr_recipe_command_t command,
mach_voucher_attr_value_handle_array_t prev_values,
mach_msg_type_number_t __assert_only prev_value_count,
mach_voucher_attr_content_t recipe,
mach_voucher_attr_content_size_t recipe_size,
mach_voucher_attr_value_handle_t *out_value,
mach_voucher_attr_value_flags_t *out_flags,
ipc_voucher_t *out_value_voucher);
kern_return_t
ipc_pthread_priority_extract_content(
ipc_voucher_attr_manager_t __assert_only manager,
mach_voucher_attr_key_t __assert_only key,
mach_voucher_attr_value_handle_array_t values,
mach_msg_type_number_t value_count,
mach_voucher_attr_recipe_command_t *out_command,
mach_voucher_attr_content_t out_recipe,
mach_voucher_attr_content_size_t *in_out_recipe_size);
kern_return_t
ipc_pthread_priority_command(
ipc_voucher_attr_manager_t __assert_only manager,
mach_voucher_attr_key_t __assert_only key,
mach_voucher_attr_value_handle_array_t values,
mach_msg_type_number_t value_count,
mach_voucher_attr_command_t command,
mach_voucher_attr_content_t in_content,
mach_voucher_attr_content_size_t in_content_size,
mach_voucher_attr_content_t out_content,
mach_voucher_attr_content_size_t *in_out_content_size);
void
ipc_pthread_priority_release(ipc_voucher_attr_manager_t __assert_only manager);
struct ipc_voucher_attr_manager ipc_pthread_priority_manager = {
.ivam_release_value = ipc_pthread_priority_release_value,
.ivam_get_value = ipc_pthread_priority_get_value,
.ivam_extract_content = ipc_pthread_priority_extract_content,
.ivam_command = ipc_pthread_priority_command,
.ivam_release = ipc_pthread_priority_release,
.ivam_flags = IVAM_FLAGS_NONE,
};
void
ipc_pthread_priority_init()
{
kern_return_t kr = KERN_SUCCESS;
kr = ipc_register_well_known_mach_voucher_attr_manager(
&ipc_pthread_priority_manager,
0,
MACH_VOUCHER_ATTR_KEY_PTHPRIORITY,
&ipc_pthread_priority_voucher_attr_control);
if (kr != KERN_SUCCESS )
panic("IPC_PTHREAD_PRIORITY subsystem initialization failed");
kprintf("IPC_PTHREAD_PRIORITY subsystem is initialized\n");
return ;
}
kern_return_t
ipc_pthread_priority_release_value(
ipc_voucher_attr_manager_t __assert_only manager,
mach_voucher_attr_key_t __assert_only key,
mach_voucher_attr_value_handle_t value,
mach_voucher_attr_value_reference_t sync)
{
assert(MACH_VOUCHER_ATTR_KEY_PTHPRIORITY == key);
assert(manager == &ipc_pthread_priority_manager);
ipc_pthread_priority_value_t ipc_pthread_priority_value = HANDLE_TO_IPC_PTHREAD_PRIORITY_VALUE(value);
panic("ipc_pthread_priority_release_value called for a persistent PTHPRIORITY value %x with sync value %d\n", ipc_pthread_priority_value, sync);
return KERN_FAILURE;
}
kern_return_t
ipc_pthread_priority_get_value(
ipc_voucher_attr_manager_t __assert_only manager,
mach_voucher_attr_key_t __assert_only key,
mach_voucher_attr_recipe_command_t command,
mach_voucher_attr_value_handle_array_t __unused prev_values,
mach_msg_type_number_t __unused prev_value_count,
mach_voucher_attr_content_t recipe,
mach_voucher_attr_content_size_t recipe_size,
mach_voucher_attr_value_handle_t *out_value,
mach_voucher_attr_value_flags_t *out_flags,
ipc_voucher_t *out_value_voucher)
{
kern_return_t kr = KERN_SUCCESS;
ipc_pthread_priority_value_t ipc_pthread_priority_value;
ipc_pthread_priority_value_t canonicalize_priority_value;
assert(MACH_VOUCHER_ATTR_KEY_PTHPRIORITY == key);
assert(manager == &ipc_pthread_priority_manager);
*out_value_voucher = IPC_VOUCHER_NULL;
*out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE;
switch (command) {
case MACH_VOUCHER_ATTR_PTHPRIORITY_CREATE:
if (recipe_size != sizeof(ipc_pthread_priority_value_t)) {
return KERN_INVALID_ARGUMENT;
}
memcpy(&ipc_pthread_priority_value, recipe, recipe_size);
if (ipc_pthread_priority_value == PTHPRIORITY_ATTR_DEFAULT_VALUE) {
*out_value = IPC_PTHREAD_PRIORITY_VALUE_TO_HANDLE(PTHPRIORITY_ATTR_DEFAULT_VALUE);
return kr;
}
canonicalize_priority_value = (ipc_pthread_priority_value_t) pthread_priority_canonicalize(
(unsigned long)ipc_pthread_priority_value, true);
*out_value = IPC_PTHREAD_PRIORITY_VALUE_TO_HANDLE(canonicalize_priority_value);
*out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST;
return kr;
default:
kr = KERN_INVALID_ARGUMENT;
break;
}
return kr;
}
kern_return_t
ipc_pthread_priority_extract_content(
ipc_voucher_attr_manager_t __assert_only manager,
mach_voucher_attr_key_t __assert_only key,
mach_voucher_attr_value_handle_array_t values,
mach_msg_type_number_t value_count,
mach_voucher_attr_recipe_command_t *out_command,
mach_voucher_attr_content_t out_recipe,
mach_voucher_attr_content_size_t *in_out_recipe_size)
{
kern_return_t kr = KERN_SUCCESS;
mach_msg_type_number_t i;
ipc_pthread_priority_value_t ipc_pthread_priority_value;
assert(MACH_VOUCHER_ATTR_KEY_PTHPRIORITY == key);
assert(manager == &ipc_pthread_priority_manager);
for (i = 0; i < value_count; i++) {
ipc_pthread_priority_value = HANDLE_TO_IPC_PTHREAD_PRIORITY_VALUE(values[i]);
if (ipc_pthread_priority_value == PTHPRIORITY_ATTR_DEFAULT_VALUE) {
continue;
}
if (MACH_VOUCHER_PTHPRIORITY_CONTENT_SIZE > *in_out_recipe_size) {
*in_out_recipe_size = 0;
return KERN_NO_SPACE;
}
memcpy(&out_recipe[0], &ipc_pthread_priority_value, sizeof(ipc_pthread_priority_value));
*out_command = MACH_VOUCHER_ATTR_PTHPRIORITY_NULL;
*in_out_recipe_size = (mach_voucher_attr_content_size_t)sizeof(ipc_pthread_priority_value);
return kr;
}
*in_out_recipe_size = 0;
return KERN_INVALID_VALUE;
}
kern_return_t
ipc_pthread_priority_command(
ipc_voucher_attr_manager_t __assert_only manager,
mach_voucher_attr_key_t __assert_only key,
mach_voucher_attr_value_handle_array_t __unused values,
mach_msg_type_number_t __unused value_count,
mach_voucher_attr_command_t __unused command,
mach_voucher_attr_content_t __unused in_content,
mach_voucher_attr_content_size_t __unused in_content_size,
mach_voucher_attr_content_t __unused out_content,
mach_voucher_attr_content_size_t __unused *out_content_size)
{
assert(MACH_VOUCHER_ATTR_KEY_PTHPRIORITY == key);
assert(manager == &ipc_pthread_priority_manager);
return KERN_FAILURE;
}
void
ipc_pthread_priority_release(
ipc_voucher_attr_manager_t __assert_only manager)
{
assert(manager == &ipc_pthread_priority_manager);
}