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 33*44e629f1SKonstantin 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 53*44e629f1SKonstantin 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 { 62*44e629f1SKonstantin Belousov struct ksched *ksched; 63917e476dSPeter Dufault 64*44e629f1SKonstantin 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; 68*44e629f1SKonstantin Belousov return (0); 69917e476dSPeter Dufault } 70917e476dSPeter Dufault 71f6c040a2SDavid Xu int 72f6c040a2SDavid Xu ksched_detach(struct ksched *ks) 73917e476dSPeter Dufault { 748a6472b7SPeter Dufault 75*44e629f1SKonstantin Belousov free(ks, M_P31B); 76*44e629f1SKonstantin 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; 109*44e629f1SKonstantin Belousov int e; 110917e476dSPeter Dufault 111*44e629f1SKonstantin Belousov e = 0; 1128460a577SJohn Birrell pri_to_rtp(td, &rtp); 113*44e629f1SKonstantin 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 } 124*44e629f1SKonstantin 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 { 131*44e629f1SKonstantin 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); 136*44e629f1SKonstantin Belousov return (e); 137917e476dSPeter Dufault } 138917e476dSPeter Dufault 139f6c040a2SDavid Xu int 140*44e629f1SKonstantin Belousov ksched_getparam(struct ksched *ksched, struct thread *td, 141*44e629f1SKonstantin 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 152*44e629f1SKonstantin Belousov * so we must show max (64 most likely). 153bec67fd3SRandall Stewart */ 154*44e629f1SKonstantin Belousov param->sched_priority = PRI_MAX_TIMESHARE - 155*44e629f1SKonstantin Belousov PRI_MIN_TIMESHARE; 156bec67fd3SRandall Stewart else 157bec67fd3SRandall Stewart param->sched_priority = tsprio_to_p4prio(rtp.prio); 158bec67fd3SRandall Stewart } 159*44e629f1SKonstantin 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 170*44e629f1SKonstantin Belousov ksched_setscheduler(struct ksched *ksched, struct thread *td, int policy, 171*44e629f1SKonstantin Belousov const struct sched_param *param) 172917e476dSPeter Dufault { 173917e476dSPeter Dufault struct rtprio rtp; 174*44e629f1SKonstantin Belousov int e; 175917e476dSPeter Dufault 176*44e629f1SKonstantin Belousov e = 0; 177*44e629f1SKonstantin Belousov switch(policy) { 178917e476dSPeter Dufault case SCHED_RR: 179917e476dSPeter Dufault case SCHED_FIFO: 180aebde782SPeter Dufault if (param->sched_priority >= P1B_PRIO_MIN && 181*44e629f1SKonstantin Belousov param->sched_priority <= P1B_PRIO_MAX) { 182aebde782SPeter Dufault rtp.prio = p4prio_to_rtpprio(param->sched_priority); 183*44e629f1SKonstantin Belousov rtp.type = (policy == SCHED_FIFO) ? RTP_PRIO_FIFO : 184*44e629f1SKonstantin Belousov RTP_PRIO_REALTIME; 1858460a577SJohn Birrell rtp_to_pri(&rtp, td); 186*44e629f1SKonstantin Belousov } else { 187917e476dSPeter Dufault e = EPERM; 188*44e629f1SKonstantin Belousov } 189917e476dSPeter Dufault break; 190917e476dSPeter Dufault case SCHED_OTHER: 191*44e629f1SKonstantin Belousov if (param->sched_priority >= 0 && param->sched_priority <= 192*44e629f1SKonstantin 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); 196*44e629f1SKonstantin Belousov } else { 197bec67fd3SRandall Stewart e = EINVAL; 198*44e629f1SKonstantin Belousov } 199917e476dSPeter Dufault break; 2005949ba21SJacques Vidrine default: 2015949ba21SJacques Vidrine e = EINVAL; 2025949ba21SJacques Vidrine break; 203917e476dSPeter Dufault } 204*44e629f1SKonstantin Belousov return (e); 205917e476dSPeter Dufault } 206917e476dSPeter Dufault 207f6c040a2SDavid Xu int 20865343c78SDavid Xu ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy) 209917e476dSPeter Dufault { 210*44e629f1SKonstantin Belousov 211*44e629f1SKonstantin Belousov return (getscheduler(ksched, td, policy)); 212917e476dSPeter Dufault } 213917e476dSPeter Dufault 214*44e629f1SKonstantin Belousov /* ksched_yield: Yield the CPU. */ 215f6c040a2SDavid Xu int 21665343c78SDavid Xu ksched_yield(struct ksched *ksched) 217917e476dSPeter Dufault { 218*44e629f1SKonstantin Belousov 21936ec198bSDavid Xu sched_relinquish(curthread); 220*44e629f1SKonstantin 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 { 226*44e629f1SKonstantin Belousov int e; 227917e476dSPeter Dufault 228*44e629f1SKonstantin Belousov e = 0; 229*44e629f1SKonstantin Belousov switch (policy) { 230917e476dSPeter Dufault case SCHED_FIFO: 231917e476dSPeter Dufault case SCHED_RR: 23265343c78SDavid Xu *prio = RTP_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; 239*44e629f1SKonstantin Belousov break; 240917e476dSPeter Dufault } 241*44e629f1SKonstantin 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 { 247*44e629f1SKonstantin Belousov int e; 248917e476dSPeter Dufault 249*44e629f1SKonstantin Belousov e = 0; 250*44e629f1SKonstantin 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; 260*44e629f1SKonstantin Belousov break; 261917e476dSPeter Dufault } 262*44e629f1SKonstantin Belousov return (e); 263917e476dSPeter Dufault } 264917e476dSPeter Dufault 265f6c040a2SDavid Xu int 266*44e629f1SKonstantin Belousov ksched_rr_get_interval(struct ksched *ksched, struct thread *td, 267*44e629f1SKonstantin Belousov struct timespec *timespec) 268917e476dSPeter Dufault { 269917e476dSPeter Dufault 270*44e629f1SKonstantin Belousov *timespec = ksched->rr_interval; 271*44e629f1SKonstantin Belousov return (0); 272917e476dSPeter Dufault } 273