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 33917e476dSPeter Dufault /* ksched: Soft real time scheduling based on "rtprio". 34917e476dSPeter Dufault */ 35917e476dSPeter Dufault 36f4636c59SDavid E. O'Brien #include <sys/cdefs.h> 37f4636c59SDavid E. O'Brien __FBSDID("$FreeBSD$"); 38f4636c59SDavid E. O'Brien 39b565fb9eSAlfred Perlstein #include "opt_posix.h" 40b565fb9eSAlfred Perlstein 41917e476dSPeter Dufault #include <sys/param.h> 42917e476dSPeter Dufault #include <sys/systm.h> 43fb919e4dSMark Murray #include <sys/lock.h> 443a187295SJohn Baldwin #include <sys/mutex.h> 45fb919e4dSMark Murray #include <sys/proc.h> 46bdd04ab1STom Rhodes #include <sys/posix4.h> 4738c76440SPeter Dufault #include <sys/resource.h> 48b43179fbSJeff Roberson #include <sys/sched.h> 49917e476dSPeter Dufault 50917e476dSPeter Dufault /* ksched: Real-time extension to support POSIX priority scheduling. 51917e476dSPeter Dufault */ 52917e476dSPeter Dufault 538a6472b7SPeter Dufault struct ksched { 548a6472b7SPeter Dufault struct timespec rr_interval; 558a6472b7SPeter Dufault }; 56917e476dSPeter Dufault 57f6c040a2SDavid Xu int 58f6c040a2SDavid Xu ksched_attach(struct ksched **p) 59917e476dSPeter Dufault { 608a6472b7SPeter Dufault struct ksched *ksched= p31b_malloc(sizeof(*ksched)); 61917e476dSPeter Dufault 628a6472b7SPeter Dufault ksched->rr_interval.tv_sec = 0; 63b43179fbSJeff Roberson ksched->rr_interval.tv_nsec = 1000000000L / sched_rr_interval(); 64917e476dSPeter Dufault 658a6472b7SPeter Dufault *p = ksched; 66917e476dSPeter Dufault return 0; 67917e476dSPeter Dufault } 68917e476dSPeter Dufault 69f6c040a2SDavid Xu int 70f6c040a2SDavid Xu ksched_detach(struct ksched *ks) 71917e476dSPeter Dufault { 72b40ce416SJulian Elischer p31b_free(ks); 738a6472b7SPeter Dufault 74917e476dSPeter Dufault return 0; 75917e476dSPeter Dufault } 76917e476dSPeter Dufault 77917e476dSPeter Dufault /* 78917e476dSPeter Dufault * XXX About priorities 79917e476dSPeter Dufault * 808a6472b7SPeter Dufault * POSIX 1003.1b requires that numerically higher priorities be of 81917e476dSPeter Dufault * higher priority. It also permits sched_setparam to be 82917e476dSPeter Dufault * implementation defined for SCHED_OTHER. I don't like 83917e476dSPeter Dufault * the notion of inverted priorites for normal processes when 84917e476dSPeter Dufault * you can use "setpriority" for that. 85917e476dSPeter Dufault * 86917e476dSPeter Dufault */ 87917e476dSPeter Dufault 88917e476dSPeter Dufault /* Macros to convert between the unix (lower numerically is higher priority) 898a6472b7SPeter Dufault * and POSIX 1003.1b (higher numerically is higher priority) 90917e476dSPeter Dufault */ 91917e476dSPeter Dufault 92917e476dSPeter Dufault #define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P)) 93917e476dSPeter Dufault #define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P)) 94917e476dSPeter Dufault 95bec67fd3SRandall Stewart #define p4prio_to_tsprio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P)) 96bec67fd3SRandall Stewart #define tsprio_to_p4prio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P)) 97bec67fd3SRandall Stewart 98aebde782SPeter Dufault /* These improve readability a bit for me: 99aebde782SPeter Dufault */ 100aebde782SPeter Dufault #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX) 101aebde782SPeter Dufault #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN) 102aebde782SPeter Dufault 103c1087c13SBruce Evans static __inline int 10465343c78SDavid Xu getscheduler(struct ksched *ksched, struct thread *td, int *policy) 105917e476dSPeter Dufault { 106d5a08a60SJake Burkholder struct rtprio rtp; 107917e476dSPeter Dufault int e = 0; 108917e476dSPeter Dufault 1098460a577SJohn Birrell pri_to_rtp(td, &rtp); 110d5a08a60SJake Burkholder switch (rtp.type) 111917e476dSPeter Dufault { 112917e476dSPeter Dufault case RTP_PRIO_FIFO: 11365343c78SDavid Xu *policy = SCHED_FIFO; 114917e476dSPeter Dufault break; 115917e476dSPeter Dufault 116917e476dSPeter Dufault case RTP_PRIO_REALTIME: 11765343c78SDavid Xu *policy = SCHED_RR; 118917e476dSPeter Dufault break; 119917e476dSPeter Dufault 120917e476dSPeter Dufault default: 12165343c78SDavid Xu *policy = SCHED_OTHER; 122917e476dSPeter Dufault break; 123917e476dSPeter Dufault } 124917e476dSPeter Dufault 125917e476dSPeter Dufault return e; 126917e476dSPeter Dufault } 127917e476dSPeter Dufault 128f6c040a2SDavid Xu int 12965343c78SDavid Xu ksched_setparam(struct ksched *ksched, 130b40ce416SJulian Elischer struct thread *td, const struct sched_param *param) 131917e476dSPeter Dufault { 13265343c78SDavid Xu int policy; 1339f79feecSBruce Evans int e; 134917e476dSPeter Dufault 13565343c78SDavid Xu e = getscheduler(ksched, td, &policy); 136917e476dSPeter Dufault 137917e476dSPeter Dufault if (e == 0) 138917e476dSPeter Dufault { 13965343c78SDavid Xu e = ksched_setscheduler(ksched, td, policy, param); 140917e476dSPeter Dufault } 141917e476dSPeter Dufault 142917e476dSPeter Dufault return e; 143917e476dSPeter Dufault } 144917e476dSPeter Dufault 145f6c040a2SDavid Xu int 14665343c78SDavid Xu ksched_getparam(struct ksched *ksched, 147b40ce416SJulian Elischer struct thread *td, struct sched_param *param) 148917e476dSPeter Dufault { 149d5a08a60SJake Burkholder struct rtprio rtp; 150d5a08a60SJake Burkholder 1518460a577SJohn Birrell pri_to_rtp(td, &rtp); 152d5a08a60SJake Burkholder if (RTP_PRIO_IS_REALTIME(rtp.type)) 153d5a08a60SJake Burkholder param->sched_priority = rtpprio_to_p4prio(rtp.prio); 154bec67fd3SRandall Stewart else { 155bec67fd3SRandall Stewart if (PRI_MIN_TIMESHARE < rtp.prio) 156bec67fd3SRandall Stewart /* 157bec67fd3SRandall Stewart * The interactive score has it to min realtime 158bec67fd3SRandall Stewart * so we must show max (64 most likely 159bec67fd3SRandall Stewart */ 160bec67fd3SRandall Stewart param->sched_priority = (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE); 161bec67fd3SRandall Stewart else 162bec67fd3SRandall Stewart param->sched_priority = tsprio_to_p4prio(rtp.prio); 163bec67fd3SRandall Stewart } 164917e476dSPeter Dufault return 0; 165917e476dSPeter Dufault } 166917e476dSPeter Dufault 167917e476dSPeter Dufault /* 168917e476dSPeter Dufault * XXX The priority and scheduler modifications should 169917e476dSPeter Dufault * be moved into published interfaces in kern/kern_sync. 170917e476dSPeter Dufault * 1718a6472b7SPeter Dufault * The permissions to modify process p were checked in "p31b_proc()". 172917e476dSPeter Dufault * 173917e476dSPeter Dufault */ 174f6c040a2SDavid Xu int 17565343c78SDavid Xu ksched_setscheduler(struct ksched *ksched, 176b40ce416SJulian Elischer struct thread *td, int policy, const struct sched_param *param) 177917e476dSPeter Dufault { 178917e476dSPeter Dufault int e = 0; 179917e476dSPeter Dufault struct rtprio rtp; 180917e476dSPeter Dufault 181917e476dSPeter Dufault switch(policy) 182917e476dSPeter Dufault { 183917e476dSPeter Dufault case SCHED_RR: 184917e476dSPeter Dufault case SCHED_FIFO: 185917e476dSPeter Dufault 186aebde782SPeter Dufault if (param->sched_priority >= P1B_PRIO_MIN && 187aebde782SPeter Dufault param->sched_priority <= P1B_PRIO_MAX) 188917e476dSPeter Dufault { 189aebde782SPeter Dufault rtp.prio = p4prio_to_rtpprio(param->sched_priority); 190917e476dSPeter Dufault rtp.type = (policy == SCHED_FIFO) 191917e476dSPeter Dufault ? RTP_PRIO_FIFO : RTP_PRIO_REALTIME; 192917e476dSPeter Dufault 1938460a577SJohn Birrell rtp_to_pri(&rtp, td); 194917e476dSPeter Dufault } 195917e476dSPeter Dufault else 196917e476dSPeter Dufault e = EPERM; 197917e476dSPeter Dufault 198917e476dSPeter Dufault 199917e476dSPeter Dufault break; 200917e476dSPeter Dufault 201917e476dSPeter Dufault case SCHED_OTHER: 202bec67fd3SRandall Stewart if (param->sched_priority >= 0 && 203bec67fd3SRandall Stewart param->sched_priority <= (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) { 204917e476dSPeter Dufault rtp.type = RTP_PRIO_NORMAL; 2052a61a110SPeter Dufault rtp.prio = p4prio_to_rtpprio(param->sched_priority); 2068460a577SJohn Birrell rtp_to_pri(&rtp, td); 207bec67fd3SRandall Stewart } else 208bec67fd3SRandall Stewart e = EINVAL; 209bec67fd3SRandall Stewart 210917e476dSPeter Dufault break; 2115949ba21SJacques Vidrine 2125949ba21SJacques Vidrine default: 2135949ba21SJacques Vidrine e = EINVAL; 2145949ba21SJacques Vidrine break; 215917e476dSPeter Dufault } 216917e476dSPeter Dufault 217917e476dSPeter Dufault return e; 218917e476dSPeter Dufault } 219917e476dSPeter Dufault 220f6c040a2SDavid Xu int 22165343c78SDavid Xu ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy) 222917e476dSPeter Dufault { 22365343c78SDavid Xu return getscheduler(ksched, td, policy); 224917e476dSPeter Dufault } 225917e476dSPeter Dufault 226917e476dSPeter Dufault /* ksched_yield: Yield the CPU. 227917e476dSPeter Dufault */ 228f6c040a2SDavid Xu int 22965343c78SDavid Xu ksched_yield(struct ksched *ksched) 230917e476dSPeter Dufault { 23136ec198bSDavid Xu sched_relinquish(curthread); 232917e476dSPeter Dufault return 0; 233917e476dSPeter Dufault } 234917e476dSPeter Dufault 235f6c040a2SDavid Xu int 23665343c78SDavid Xu ksched_get_priority_max(struct ksched *ksched, int policy, int *prio) 237917e476dSPeter Dufault { 238917e476dSPeter Dufault int e = 0; 239917e476dSPeter Dufault 240917e476dSPeter Dufault switch (policy) 241917e476dSPeter Dufault { 242917e476dSPeter Dufault case SCHED_FIFO: 243917e476dSPeter Dufault case SCHED_RR: 24465343c78SDavid Xu *prio = RTP_PRIO_MAX; 245917e476dSPeter Dufault break; 246917e476dSPeter Dufault 247917e476dSPeter Dufault case SCHED_OTHER: 248c3ab507fSDavid Xu *prio = PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE; 249917e476dSPeter Dufault break; 250917e476dSPeter Dufault 251917e476dSPeter Dufault default: 252917e476dSPeter Dufault e = EINVAL; 253917e476dSPeter Dufault } 254917e476dSPeter Dufault 255917e476dSPeter Dufault return e; 256917e476dSPeter Dufault } 257917e476dSPeter Dufault 258f6c040a2SDavid Xu int 25965343c78SDavid Xu ksched_get_priority_min(struct ksched *ksched, int policy, int *prio) 260917e476dSPeter Dufault { 261917e476dSPeter Dufault int e = 0; 262917e476dSPeter Dufault 263917e476dSPeter Dufault switch (policy) 264917e476dSPeter Dufault { 265917e476dSPeter Dufault case SCHED_FIFO: 266917e476dSPeter Dufault case SCHED_RR: 26765343c78SDavid Xu *prio = P1B_PRIO_MIN; 268917e476dSPeter Dufault break; 269917e476dSPeter Dufault 270917e476dSPeter Dufault case SCHED_OTHER: 271c3ab507fSDavid Xu *prio = 0; 272917e476dSPeter Dufault break; 273917e476dSPeter Dufault 274917e476dSPeter Dufault default: 275917e476dSPeter Dufault e = EINVAL; 276917e476dSPeter Dufault } 277917e476dSPeter Dufault 278917e476dSPeter Dufault return e; 279917e476dSPeter Dufault } 280917e476dSPeter Dufault 281f6c040a2SDavid Xu int 28265343c78SDavid Xu ksched_rr_get_interval(struct ksched *ksched, 283b40ce416SJulian Elischer struct thread *td, struct timespec *timespec) 284917e476dSPeter Dufault { 2858a6472b7SPeter Dufault *timespec = ksched->rr_interval; 286917e476dSPeter Dufault 287917e476dSPeter Dufault return 0; 288917e476dSPeter Dufault } 289