sys_work_interval.c [plain text]
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/kernel_types.h>
#include <sys/sysproto.h>
#include <sys/priv.h>
#include <sys/work_interval.h>
#include <kern/sched_prim.h>
#include <kern/thread.h>
#include <kern/policy_internal.h>
#include <libkern/libkern.h>
int
work_interval_ctl(__unused proc_t p, struct work_interval_ctl_args *uap, __unused int32_t *retval)
{
uint32_t operation = uap->operation;
int error = 0;
kern_return_t kret = KERN_SUCCESS;
uint64_t work_interval_id;
struct work_interval_notification notification;
switch (operation) {
case WORK_INTERVAL_OPERATION_CREATE:
if (uap->arg == USER_ADDR_NULL || uap->work_interval_id != 0) {
return EINVAL;
}
if (uap->len < sizeof(work_interval_id)) {
return ERANGE;
}
error = priv_check_cred(kauth_cred_get(), PRIV_WORK_INTERVAL, 0);
if (error) {
return (error);
}
kret = thread_policy_create_work_interval(current_thread(),
&work_interval_id);
if (kret == KERN_SUCCESS) {
error = copyout(&work_interval_id, uap->arg, sizeof(work_interval_id));
} else {
error = EINVAL;
}
break;
case WORK_INTERVAL_OPERATION_DESTROY:
if (uap->arg != USER_ADDR_NULL || uap->work_interval_id == 0) {
return EINVAL;
}
kret = thread_policy_destroy_work_interval(current_thread(),
uap->work_interval_id);
if (kret != KERN_SUCCESS) {
error = EINVAL;
}
break;
case WORK_INTERVAL_OPERATION_NOTIFY:
if (uap->arg == USER_ADDR_NULL || uap->work_interval_id == 0) {
return EINVAL;
}
if (uap->len < sizeof(notification)) {
return EINVAL;
}
error = copyin(uap->arg, ¬ification, sizeof(notification));
if (error) {
break;
}
kret = sched_work_interval_notify(current_thread(),
uap->work_interval_id,
notification.start,
notification.finish,
notification.deadline,
notification.next_start,
notification.flags);
if (kret != KERN_SUCCESS) {
error = EINVAL;
break;
}
break;
default:
error = ENOTSUP;
break;
}
return (error);
}