160727d8bSWarner Losh /*- 2917e476dSPeter Dufault * Copyright (c) 1996, 1997 3917e476dSPeter Dufault * HD Associates, Inc. All rights reserved. 4917e476dSPeter Dufault * 5917e476dSPeter Dufault * Redistribution and use in source and binary forms, with or without 6917e476dSPeter Dufault * modification, are permitted provided that the following conditions 7917e476dSPeter Dufault * are met: 8917e476dSPeter Dufault * 1. Redistributions of source code must retain the above copyright 9917e476dSPeter Dufault * notice, this list of conditions and the following disclaimer. 10917e476dSPeter Dufault * 2. Redistributions in binary form must reproduce the above copyright 11917e476dSPeter Dufault * notice, this list of conditions and the following disclaimer in the 12917e476dSPeter Dufault * documentation and/or other materials provided with the distribution. 13917e476dSPeter Dufault * 3. All advertising materials mentioning features or use of this software 14917e476dSPeter Dufault * must display the following acknowledgement: 15917e476dSPeter Dufault * This product includes software developed by HD Associates, Inc 16917e476dSPeter Dufault * 4. Neither the name of the author nor the names of any co-contributors 17917e476dSPeter Dufault * may be used to endorse or promote products derived from this software 18917e476dSPeter Dufault * without specific prior written permission. 19917e476dSPeter Dufault * 20917e476dSPeter Dufault * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND 21917e476dSPeter Dufault * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22917e476dSPeter Dufault * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23917e476dSPeter Dufault * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE 24917e476dSPeter Dufault * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25917e476dSPeter Dufault * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26917e476dSPeter Dufault * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27917e476dSPeter Dufault * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28917e476dSPeter Dufault * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29917e476dSPeter Dufault * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30917e476dSPeter Dufault * SUCH DAMAGE. 31917e476dSPeter Dufault */ 32917e476dSPeter Dufault 3344e629f1SKonstantin Belousov /* ksched: Soft real time scheduling based on "rtprio". */ 34917e476dSPeter Dufault 35f4636c59SDavid E. O'Brien #include <sys/cdefs.h> 36f4636c59SDavid E. O'Brien __FBSDID("$FreeBSD$"); 37f4636c59SDavid E. O'Brien 38b565fb9eSAlfred Perlstein #include "opt_posix.h" 39b565fb9eSAlfred Perlstein 40917e476dSPeter Dufault #include <sys/param.h> 41917e476dSPeter Dufault #include <sys/systm.h> 42fb919e4dSMark Murray #include <sys/lock.h> 43de5b1952SAlexander Leidinger #include <sys/sysctl.h> 44de5b1952SAlexander Leidinger #include <sys/kernel.h> 453a187295SJohn Baldwin #include <sys/mutex.h> 46fb919e4dSMark Murray #include <sys/proc.h> 47bdd04ab1STom Rhodes #include <sys/posix4.h> 4838c76440SPeter Dufault #include <sys/resource.h> 49b43179fbSJeff Roberson #include <sys/sched.h> 50917e476dSPeter Dufault 51de5b1952SAlexander Leidinger FEATURE(kposix_priority_scheduling, "POSIX P1003.1B realtime extensions"); 52de5b1952SAlexander Leidinger 5344e629f1SKonstantin Belousov /* ksched: Real-time extension to support POSIX priority scheduling. */ 54917e476dSPeter Dufault 558a6472b7SPeter Dufault struct ksched { 568a6472b7SPeter Dufault struct timespec rr_interval; 578a6472b7SPeter Dufault }; 58917e476dSPeter Dufault 59f6c040a2SDavid Xu int 60f6c040a2SDavid Xu ksched_attach(struct ksched **p) 61917e476dSPeter Dufault { 6244e629f1SKonstantin Belousov struct ksched *ksched; 63917e476dSPeter Dufault 6444e629f1SKonstantin Belousov ksched = malloc(sizeof(*ksched), M_P31B, M_WAITOK); 658a6472b7SPeter Dufault ksched->rr_interval.tv_sec = 0; 669000aabfSAlexander Motin ksched->rr_interval.tv_nsec = 1000000000L / hz * sched_rr_interval(); 678a6472b7SPeter Dufault *p = ksched; 6844e629f1SKonstantin Belousov return (0); 69917e476dSPeter Dufault } 70917e476dSPeter Dufault 71f6c040a2SDavid Xu int 72f6c040a2SDavid Xu ksched_detach(struct ksched *ks) 73917e476dSPeter Dufault { 748a6472b7SPeter Dufault 7544e629f1SKonstantin Belousov free(ks, M_P31B); 7644e629f1SKonstantin Belousov return (0); 77917e476dSPeter Dufault } 78917e476dSPeter Dufault 79917e476dSPeter Dufault /* 80917e476dSPeter Dufault * XXX About priorities 81917e476dSPeter Dufault * 828a6472b7SPeter Dufault * POSIX 1003.1b requires that numerically higher priorities be of 83917e476dSPeter Dufault * higher priority. It also permits sched_setparam to be 84917e476dSPeter Dufault * implementation defined for SCHED_OTHER. I don't like 85917e476dSPeter Dufault * the notion of inverted priorites for normal processes when 86917e476dSPeter Dufault * you can use "setpriority" for that. 87917e476dSPeter Dufault * 88917e476dSPeter Dufault */ 89917e476dSPeter Dufault 90917e476dSPeter Dufault /* Macros to convert between the unix (lower numerically is higher priority) 918a6472b7SPeter Dufault * and POSIX 1003.1b (higher numerically is higher priority) 92917e476dSPeter Dufault */ 93917e476dSPeter Dufault 94917e476dSPeter Dufault #define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P)) 95917e476dSPeter Dufault #define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P)) 96917e476dSPeter Dufault 97bec67fd3SRandall Stewart #define p4prio_to_tsprio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P)) 98bec67fd3SRandall Stewart #define tsprio_to_p4prio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P)) 99bec67fd3SRandall Stewart 100aebde782SPeter Dufault /* These improve readability a bit for me: 101aebde782SPeter Dufault */ 102aebde782SPeter Dufault #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX) 103aebde782SPeter Dufault #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN) 104aebde782SPeter Dufault 105c1087c13SBruce Evans static __inline int 10665343c78SDavid Xu getscheduler(struct ksched *ksched, struct thread *td, int *policy) 107917e476dSPeter Dufault { 108d5a08a60SJake Burkholder struct rtprio rtp; 10944e629f1SKonstantin Belousov int e; 110917e476dSPeter Dufault 11144e629f1SKonstantin Belousov e = 0; 1128460a577SJohn Birrell pri_to_rtp(td, &rtp); 11344e629f1SKonstantin Belousov switch (rtp.type) { 114917e476dSPeter Dufault case RTP_PRIO_FIFO: 11565343c78SDavid Xu *policy = SCHED_FIFO; 116917e476dSPeter Dufault break; 117917e476dSPeter Dufault case RTP_PRIO_REALTIME: 11865343c78SDavid Xu *policy = SCHED_RR; 119917e476dSPeter Dufault break; 120917e476dSPeter Dufault default: 12165343c78SDavid Xu *policy = SCHED_OTHER; 122917e476dSPeter Dufault break; 123917e476dSPeter Dufault } 12444e629f1SKonstantin Belousov return (e); 125917e476dSPeter Dufault } 126917e476dSPeter Dufault 127f6c040a2SDavid Xu int 12865343c78SDavid Xu ksched_setparam(struct ksched *ksched, 129b40ce416SJulian Elischer struct thread *td, const struct sched_param *param) 130917e476dSPeter Dufault { 13144e629f1SKonstantin Belousov int e, policy; 132917e476dSPeter Dufault 13365343c78SDavid Xu e = getscheduler(ksched, td, &policy); 134917e476dSPeter Dufault if (e == 0) 13565343c78SDavid Xu e = ksched_setscheduler(ksched, td, policy, param); 13644e629f1SKonstantin Belousov return (e); 137917e476dSPeter Dufault } 138917e476dSPeter Dufault 139f6c040a2SDavid Xu int 14044e629f1SKonstantin Belousov ksched_getparam(struct ksched *ksched, struct thread *td, 14144e629f1SKonstantin Belousov struct sched_param *param) 142917e476dSPeter Dufault { 143d5a08a60SJake Burkholder struct rtprio rtp; 144d5a08a60SJake Burkholder 1458460a577SJohn Birrell pri_to_rtp(td, &rtp); 146d5a08a60SJake Burkholder if (RTP_PRIO_IS_REALTIME(rtp.type)) 147d5a08a60SJake Burkholder param->sched_priority = rtpprio_to_p4prio(rtp.prio); 148bec67fd3SRandall Stewart else { 149bec67fd3SRandall Stewart if (PRI_MIN_TIMESHARE < rtp.prio) 150bec67fd3SRandall Stewart /* 151bec67fd3SRandall Stewart * The interactive score has it to min realtime 15244e629f1SKonstantin Belousov * so we must show max (64 most likely). 153bec67fd3SRandall Stewart */ 15444e629f1SKonstantin Belousov param->sched_priority = PRI_MAX_TIMESHARE - 15544e629f1SKonstantin Belousov PRI_MIN_TIMESHARE; 156bec67fd3SRandall Stewart else 157bec67fd3SRandall Stewart param->sched_priority = tsprio_to_p4prio(rtp.prio); 158bec67fd3SRandall Stewart } 15944e629f1SKonstantin Belousov return (0); 160917e476dSPeter Dufault } 161917e476dSPeter Dufault 162917e476dSPeter Dufault /* 163917e476dSPeter Dufault * XXX The priority and scheduler modifications should 164917e476dSPeter Dufault * be moved into published interfaces in kern/kern_sync. 165917e476dSPeter Dufault * 1668a6472b7SPeter Dufault * The permissions to modify process p were checked in "p31b_proc()". 167917e476dSPeter Dufault * 168917e476dSPeter Dufault */ 169f6c040a2SDavid Xu int 17044e629f1SKonstantin Belousov ksched_setscheduler(struct ksched *ksched, struct thread *td, int policy, 17144e629f1SKonstantin Belousov const struct sched_param *param) 172917e476dSPeter Dufault { 173917e476dSPeter Dufault struct rtprio rtp; 17444e629f1SKonstantin Belousov int e; 175917e476dSPeter Dufault 17644e629f1SKonstantin Belousov e = 0; 17744e629f1SKonstantin Belousov switch(policy) { 178917e476dSPeter Dufault case SCHED_RR: 179917e476dSPeter Dufault case SCHED_FIFO: 180aebde782SPeter Dufault if (param->sched_priority >= P1B_PRIO_MIN && 18144e629f1SKonstantin Belousov param->sched_priority <= P1B_PRIO_MAX) { 182aebde782SPeter Dufault rtp.prio = p4prio_to_rtpprio(param->sched_priority); 18344e629f1SKonstantin Belousov rtp.type = (policy == SCHED_FIFO) ? RTP_PRIO_FIFO : 18444e629f1SKonstantin Belousov RTP_PRIO_REALTIME; 1858460a577SJohn Birrell rtp_to_pri(&rtp, td); 18644e629f1SKonstantin Belousov } else { 187917e476dSPeter Dufault e = EPERM; 18844e629f1SKonstantin Belousov } 189917e476dSPeter Dufault break; 190917e476dSPeter Dufault case SCHED_OTHER: 19144e629f1SKonstantin Belousov if (param->sched_priority >= 0 && param->sched_priority <= 19244e629f1SKonstantin Belousov (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) { 193917e476dSPeter Dufault rtp.type = RTP_PRIO_NORMAL; 194a2311449SDavid Xu rtp.prio = p4prio_to_tsprio(param->sched_priority); 1958460a577SJohn Birrell rtp_to_pri(&rtp, td); 19644e629f1SKonstantin Belousov } else { 197bec67fd3SRandall Stewart e = EINVAL; 19844e629f1SKonstantin Belousov } 199917e476dSPeter Dufault break; 2005949ba21SJacques Vidrine default: 2015949ba21SJacques Vidrine e = EINVAL; 2025949ba21SJacques Vidrine break; 203917e476dSPeter Dufault } 20444e629f1SKonstantin Belousov return (e); 205917e476dSPeter Dufault } 206917e476dSPeter Dufault 207f6c040a2SDavid Xu int 20865343c78SDavid Xu ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy) 209917e476dSPeter Dufault { 21044e629f1SKonstantin Belousov 21144e629f1SKonstantin Belousov return (getscheduler(ksched, td, policy)); 212917e476dSPeter Dufault } 213917e476dSPeter Dufault 21444e629f1SKonstantin Belousov /* ksched_yield: Yield the CPU. */ 215f6c040a2SDavid Xu int 21665343c78SDavid Xu ksched_yield(struct ksched *ksched) 217917e476dSPeter Dufault { 21844e629f1SKonstantin Belousov 21936ec198bSDavid Xu sched_relinquish(curthread); 22044e629f1SKonstantin Belousov return (0); 221917e476dSPeter Dufault } 222917e476dSPeter Dufault 223f6c040a2SDavid Xu int 22465343c78SDavid Xu ksched_get_priority_max(struct ksched *ksched, int policy, int *prio) 225917e476dSPeter Dufault { 22644e629f1SKonstantin Belousov int e; 227917e476dSPeter Dufault 22844e629f1SKonstantin Belousov e = 0; 22944e629f1SKonstantin Belousov switch (policy) { 230917e476dSPeter Dufault case SCHED_FIFO: 231917e476dSPeter Dufault case SCHED_RR: 232*8d830e02SKonstantin Belousov *prio = P1B_PRIO_MAX; 233917e476dSPeter Dufault break; 234917e476dSPeter Dufault case SCHED_OTHER: 235c3ab507fSDavid Xu *prio = PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE; 236917e476dSPeter Dufault break; 237917e476dSPeter Dufault default: 238917e476dSPeter Dufault e = EINVAL; 23944e629f1SKonstantin Belousov break; 240917e476dSPeter Dufault } 24144e629f1SKonstantin Belousov return (e); 242917e476dSPeter Dufault } 243917e476dSPeter Dufault 244f6c040a2SDavid Xu int 24565343c78SDavid Xu ksched_get_priority_min(struct ksched *ksched, int policy, int *prio) 246917e476dSPeter Dufault { 24744e629f1SKonstantin Belousov int e; 248917e476dSPeter Dufault 24944e629f1SKonstantin Belousov e = 0; 25044e629f1SKonstantin Belousov switch (policy) { 251917e476dSPeter Dufault case SCHED_FIFO: 252917e476dSPeter Dufault case SCHED_RR: 25365343c78SDavid Xu *prio = P1B_PRIO_MIN; 254917e476dSPeter Dufault break; 255917e476dSPeter Dufault case SCHED_OTHER: 256c3ab507fSDavid Xu *prio = 0; 257917e476dSPeter Dufault break; 258917e476dSPeter Dufault default: 259917e476dSPeter Dufault e = EINVAL; 26044e629f1SKonstantin Belousov break; 261917e476dSPeter Dufault } 26244e629f1SKonstantin Belousov return (e); 263917e476dSPeter Dufault } 264917e476dSPeter Dufault 265f6c040a2SDavid Xu int 26644e629f1SKonstantin Belousov ksched_rr_get_interval(struct ksched *ksched, struct thread *td, 26744e629f1SKonstantin Belousov struct timespec *timespec) 268917e476dSPeter Dufault { 269917e476dSPeter Dufault 27044e629f1SKonstantin Belousov *timespec = ksched->rr_interval; 27144e629f1SKonstantin Belousov return (0); 272917e476dSPeter Dufault } 273