diff --git a/sys/kern/kern_thr.c b/sys/kern/kern_thr.c index 70d0e24b8ba5..a57e4a19efeb 100644 --- a/sys/kern/kern_thr.c +++ b/sys/kern/kern_thr.c @@ -27,6 +27,7 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_posix.h" #include #include #include @@ -44,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include @@ -89,8 +91,11 @@ thr_new(struct thread *td, struct thr_new_args *uap) if ((error = copyin(uap->param, ¶m, sizeof(param)))) return (error); sched = NULL; - if (param.sched != NULL) { - error = copyin(param.sched, &sched_param, + if (param.sched_param != NULL) { + if (param.sched_param_size != sizeof(struct thr_sched_param)) + return (EINVAL); + + error = copyin(param.sched_param, &sched_param, sizeof(sched_param)); if (error) return (error); @@ -431,3 +436,154 @@ thr_set_name(struct thread *td, struct thr_set_name_args *uap) PROC_UNLOCK(p); return (error); } + +int +thr_setscheduler(struct thread *td, struct thr_setscheduler_args *uap) +{ + struct proc *p; + struct thread *ttd; + struct rtprio rtp; + struct sched_param param; + int ret; + + if (uap->param_size != sizeof(struct sched_param)) + return (EINVAL); + + ret = copyin(uap->param, ¶m, sizeof(struct sched_param)); + if (ret) + return (ret); + + switch(uap->policy) { + case SCHED_FIFO: + if (suser(td) != 0) + return (EPERM); + rtp.type = PRI_FIFO; + break; + case SCHED_RR: + if (suser(td) != 0) + return (EPERM); + rtp.type = PRI_REALTIME; + break; + case SCHED_OTHER: + rtp.type = PRI_TIMESHARE; + break; + default: + return (EINVAL); + } + rtp.prio = param.sched_priority; + + p = td->td_proc; + PROC_LOCK(p); + ret = p_cansched(td, p); + if (ret != 0) { + PROC_UNLOCK(p); + return (ret); + } + + ttd = thread_find(p, uap->id); + if (ttd == NULL) { + PROC_UNLOCK(p); + return (ESRCH); + } + mtx_lock_spin(&sched_lock); + ret = rtp_to_pri(&rtp, ttd->td_ksegrp); + if (ret == 0) { + if (TD_IS_RUNNING(ttd)) + ttd->td_flags |= TDF_NEEDRESCHED; + else if (ttd->td_priority > ttd->td_ksegrp->kg_user_pri) + sched_prio(ttd, ttd->td_ksegrp->kg_user_pri); + } + mtx_unlock_spin(&sched_lock); + PROC_UNLOCK(p); + return (ret); +} + +int +thr_getscheduler(struct thread *td, struct thr_getscheduler_args *uap) +{ + struct proc *p; + struct thread *ttd; + struct rtprio rtp; + struct sched_param param; + int policy; + int ret; + + if (uap->param_size != sizeof(struct sched_param)) + return (EINVAL); + + p = td->td_proc; + PROC_LOCK(p); + ttd = thread_find(p, uap->id); + if (ttd == NULL) { + PROC_UNLOCK(p); + return (ESRCH); + } + mtx_lock_spin(&sched_lock); + switch(ttd->td_ksegrp->kg_pri_class) { + case PRI_TIMESHARE: + policy = SCHED_OTHER; + break; + case PRI_FIFO: + policy = SCHED_FIFO; + break; + case PRI_REALTIME: + policy = SCHED_RR; + break; + default: + policy = SCHED_OTHER; /* XXX SCHED_IDLE */ + } + pri_to_rtp(ttd->td_ksegrp, &rtp); + mtx_unlock_spin(&sched_lock); + PROC_UNLOCK(p); + + param.sched_priority = rtp.prio; + ret = copyout(&policy, uap->policy, sizeof(policy)); + if (ret == 0) + ret = copyout(¶m, uap->param, sizeof(param)); + return (ret); +} + +int +thr_setschedparam(struct thread *td, struct thr_setschedparam_args *uap) +{ + struct proc *p; + struct thread *ttd; + struct rtprio rtp; + struct sched_param param; + int ret; + + if (uap->param_size != sizeof(struct sched_param)) + return (EINVAL); + + ret = copyin(uap->param, ¶m, sizeof(struct sched_param)); + if (ret) + return (ret); + + p = td->td_proc; + PROC_LOCK(p); + ret = p_cansched(td, p); + if (ret != 0) { + PROC_UNLOCK(p); + return (ret); + } + + ttd = thread_find(p, uap->id); + if (ttd == NULL) { + PROC_UNLOCK(p); + return (ESRCH); + } + + mtx_lock_spin(&sched_lock); + pri_to_rtp(ttd->td_ksegrp, &rtp); + rtp.prio = param.sched_priority; + ret = rtp_to_pri(&rtp, ttd->td_ksegrp); + if (ret == 0) { + if (TD_IS_RUNNING(ttd)) + ttd->td_flags |= TDF_NEEDRESCHED; + else if (ttd->td_priority > ttd->td_ksegrp->kg_user_pri) + sched_prio(ttd, ttd->td_ksegrp->kg_user_pri); + } + mtx_unlock_spin(&sched_lock); + PROC_UNLOCK(p); + return (ret); +} diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index ecd8c8f7ff66..fd73f1c62269 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -822,5 +822,14 @@ 463 AUE_NULL MSTD { int abort2(const char *why, int nargs, void **args); } 464 AUE_NULL MSTD { int thr_set_name(long id, const char *name); } 465 AUE_NULL MNOSTD { int aio_fsync(int op, struct aiocb *aiocbp); } +466 AUE_NULL MSTD { int thr_setscheduler(long id, int policy,\ + const struct sched_param *param, \ + int param_size); } +467 AUE_NULL MSTD { int thr_getscheduler(long id, int *policy,\ + struct sched_param *param, \ + int param_size); } +468 AUE_NULL MSTD { int thr_setschedparam(long id, \ + const struct sched_param *param, \ + int param_size); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master diff --git a/sys/sys/thr.h b/sys/sys/thr.h index f58eab496a6a..c6153d0a31f1 100644 --- a/sys/sys/thr.h +++ b/sys/sys/thr.h @@ -52,8 +52,9 @@ struct thr_param { long *child_tid; /* address to store new TID. */ long *parent_tid; /* parent accesses the new TID here. */ int flags; /* thread flags. */ - struct thr_sched_param *sched; /* POSIX scheduler parameters .*/ - void *spare[3]; /* TODO: cpu affinity mask etc. */ + struct thr_sched_param *sched_param; /* POSIX scheduler parameters .*/ + long sched_param_size; /* scheduler parameter size */ + void *spare[2]; /* TODO: cpu affinity mask etc. */ }; /* @@ -69,6 +70,12 @@ int thr_kill(long id, int sig); int thr_suspend(const struct timespec *timeout); int thr_wake(long id); int thr_set_name(long id, const char *name); +int thr_setscheduler(long id, int policy, const struct sched_param *param, + int param_size); +int thr_getscheduler(long id, int *policy, struct sched_param *param, + int param_size); +int thr_setschedparam(long id, const struct sched_param *param, + int param_size); #endif /* !_KERNEL */ #endif /* ! _SYS_THR_H_ */