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/work_interval.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;
struct work_interval_notification notification;
struct work_interval_create_params create_params;
struct kern_work_interval_create_args create_args;
switch (operation) {
case WORK_INTERVAL_OPERATION_CREATE:
return ENOTSUP;
case WORK_INTERVAL_OPERATION_CREATE2:
if (uap->arg == USER_ADDR_NULL || uap->work_interval_id != 0)
return EINVAL;
if (uap->len < sizeof(create_params))
return EINVAL;
if ((error = priv_check_cred(kauth_cred_get(), PRIV_WORK_INTERVAL, 0)))
return error;
if ((error = copyin(uap->arg, &create_params, sizeof(create_params))))
return error;
create_args = (struct kern_work_interval_create_args) {
.wica_id = create_params.wicp_id,
.wica_port = create_params.wicp_port,
.wica_create_flags = create_params.wicp_create_flags,
};
kret = kern_work_interval_create(current_thread(), &create_args);
if (kret == KERN_FAILURE)
return EALREADY;
if (kret == KERN_RESOURCE_SHORTAGE)
return ENOMEM;
if (kret != KERN_SUCCESS)
return EINVAL;
create_params = (struct work_interval_create_params) {
.wicp_id = create_args.wica_id,
.wicp_port = create_args.wica_port,
.wicp_create_flags = create_args.wica_create_flags,
};
if ((error = copyout(&create_params, uap->arg, sizeof(create_params))))
return error;
break;
case WORK_INTERVAL_OPERATION_DESTROY:
if (uap->arg != USER_ADDR_NULL || uap->work_interval_id == 0) {
return EINVAL;
}
kret = kern_work_interval_destroy(current_thread(), uap->work_interval_id);
if (kret != KERN_SUCCESS)
return 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;
if ((error = copyin(uap->arg, ¬ification, sizeof(notification))))
return error;
struct kern_work_interval_args kwi_args = {
.work_interval_id = uap->work_interval_id,
.start = notification.start,
.finish = notification.finish,
.deadline = notification.deadline,
.next_start = notification.next_start,
.notify_flags = notification.notify_flags,
.create_flags = notification.create_flags,
};
kret = kern_work_interval_notify(current_thread(), &kwi_args);
if (kret != KERN_SUCCESS)
return EINVAL;
break;
case WORK_INTERVAL_OPERATION_JOIN:
if (uap->arg != USER_ADDR_NULL) {
return EINVAL;
}
kret = kern_work_interval_join(current_thread(),
(mach_port_name_t)uap->work_interval_id);
if (kret != KERN_SUCCESS)
return EINVAL;
break;
default:
return ENOTSUP;
}
return (error);
}