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> 44de5b1952SAlexander Leidinger #include <sys/sysctl.h> 45de5b1952SAlexander Leidinger #include <sys/kernel.h> 463a187295SJohn Baldwin #include <sys/mutex.h> 47fb919e4dSMark Murray #include <sys/proc.h> 48bdd04ab1STom Rhodes #include <sys/posix4.h> 4938c76440SPeter Dufault #include <sys/resource.h> 50b43179fbSJeff Roberson #include <sys/sched.h> 51917e476dSPeter Dufault 52de5b1952SAlexander Leidinger FEATURE(kposix_priority_scheduling, "POSIX P1003.1B realtime extensions"); 53de5b1952SAlexander Leidinger 54917e476dSPeter Dufault /* ksched: Real-time extension to support POSIX priority scheduling. 55917e476dSPeter Dufault */ 56917e476dSPeter Dufault 578a6472b7SPeter Dufault struct ksched { 588a6472b7SPeter Dufault struct timespec rr_interval; 598a6472b7SPeter Dufault }; 60917e476dSPeter Dufault 61f6c040a2SDavid Xu int 62f6c040a2SDavid Xu ksched_attach(struct ksched **p) 63917e476dSPeter Dufault { 648a6472b7SPeter Dufault struct ksched *ksched= p31b_malloc(sizeof(*ksched)); 65917e476dSPeter Dufault 668a6472b7SPeter Dufault ksched->rr_interval.tv_sec = 0; 67b43179fbSJeff Roberson ksched->rr_interval.tv_nsec = 1000000000L / sched_rr_interval(); 68917e476dSPeter Dufault 698a6472b7SPeter Dufault *p = ksched; 70917e476dSPeter Dufault return 0; 71917e476dSPeter Dufault } 72917e476dSPeter Dufault 73f6c040a2SDavid Xu int 74f6c040a2SDavid Xu ksched_detach(struct ksched *ks) 75917e476dSPeter Dufault { 76b40ce416SJulian Elischer p31b_free(ks); 778a6472b7SPeter Dufault 78917e476dSPeter Dufault return 0; 79917e476dSPeter Dufault } 80917e476dSPeter Dufault 81917e476dSPeter Dufault /* 82917e476dSPeter Dufault * XXX About priorities 83917e476dSPeter Dufault * 848a6472b7SPeter Dufault * POSIX 1003.1b requires that numerically higher priorities be of 85917e476dSPeter Dufault * higher priority. It also permits sched_setparam to be 86917e476dSPeter Dufault * implementation defined for SCHED_OTHER. I don't like 87917e476dSPeter Dufault * the notion of inverted priorites for normal processes when 88917e476dSPeter Dufault * you can use "setpriority" for that. 89917e476dSPeter Dufault * 90917e476dSPeter Dufault */ 91917e476dSPeter Dufault 92917e476dSPeter Dufault /* Macros to convert between the unix (lower numerically is higher priority) 938a6472b7SPeter Dufault * and POSIX 1003.1b (higher numerically is higher priority) 94917e476dSPeter Dufault */ 95917e476dSPeter Dufault 96917e476dSPeter Dufault #define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P)) 97917e476dSPeter Dufault #define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P)) 98917e476dSPeter Dufault 99bec67fd3SRandall Stewart #define p4prio_to_tsprio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P)) 100bec67fd3SRandall Stewart #define tsprio_to_p4prio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P)) 101bec67fd3SRandall Stewart 102aebde782SPeter Dufault /* These improve readability a bit for me: 103aebde782SPeter Dufault */ 104aebde782SPeter Dufault #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX) 105aebde782SPeter Dufault #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN) 106aebde782SPeter Dufault 107c1087c13SBruce Evans static __inline int 10865343c78SDavid Xu getscheduler(struct ksched *ksched, struct thread *td, int *policy) 109917e476dSPeter Dufault { 110d5a08a60SJake Burkholder struct rtprio rtp; 111917e476dSPeter Dufault int e = 0; 112917e476dSPeter Dufault 1138460a577SJohn Birrell pri_to_rtp(td, &rtp); 114d5a08a60SJake Burkholder switch (rtp.type) 115917e476dSPeter Dufault { 116917e476dSPeter Dufault case RTP_PRIO_FIFO: 11765343c78SDavid Xu *policy = SCHED_FIFO; 118917e476dSPeter Dufault break; 119917e476dSPeter Dufault 120917e476dSPeter Dufault case RTP_PRIO_REALTIME: 12165343c78SDavid Xu *policy = SCHED_RR; 122917e476dSPeter Dufault break; 123917e476dSPeter Dufault 124917e476dSPeter Dufault default: 12565343c78SDavid Xu *policy = SCHED_OTHER; 126917e476dSPeter Dufault break; 127917e476dSPeter Dufault } 128917e476dSPeter Dufault 129917e476dSPeter Dufault return e; 130917e476dSPeter Dufault } 131917e476dSPeter Dufault 132f6c040a2SDavid Xu int 13365343c78SDavid Xu ksched_setparam(struct ksched *ksched, 134b40ce416SJulian Elischer struct thread *td, const struct sched_param *param) 135917e476dSPeter Dufault { 13665343c78SDavid Xu int policy; 1379f79feecSBruce Evans int e; 138917e476dSPeter Dufault 13965343c78SDavid Xu e = getscheduler(ksched, td, &policy); 140917e476dSPeter Dufault 141917e476dSPeter Dufault if (e == 0) 142917e476dSPeter Dufault { 14365343c78SDavid Xu e = ksched_setscheduler(ksched, td, policy, param); 144917e476dSPeter Dufault } 145917e476dSPeter Dufault 146917e476dSPeter Dufault return e; 147917e476dSPeter Dufault } 148917e476dSPeter Dufault 149f6c040a2SDavid Xu int 15065343c78SDavid Xu ksched_getparam(struct ksched *ksched, 151b40ce416SJulian Elischer struct thread *td, struct sched_param *param) 152917e476dSPeter Dufault { 153d5a08a60SJake Burkholder struct rtprio rtp; 154d5a08a60SJake Burkholder 1558460a577SJohn Birrell pri_to_rtp(td, &rtp); 156d5a08a60SJake Burkholder if (RTP_PRIO_IS_REALTIME(rtp.type)) 157d5a08a60SJake Burkholder param->sched_priority = rtpprio_to_p4prio(rtp.prio); 158bec67fd3SRandall Stewart else { 159bec67fd3SRandall Stewart if (PRI_MIN_TIMESHARE < rtp.prio) 160bec67fd3SRandall Stewart /* 161bec67fd3SRandall Stewart * The interactive score has it to min realtime 162bec67fd3SRandall Stewart * so we must show max (64 most likely 163bec67fd3SRandall Stewart */ 164bec67fd3SRandall Stewart param->sched_priority = (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE); 165bec67fd3SRandall Stewart else 166bec67fd3SRandall Stewart param->sched_priority = tsprio_to_p4prio(rtp.prio); 167bec67fd3SRandall Stewart } 168917e476dSPeter Dufault return 0; 169917e476dSPeter Dufault } 170917e476dSPeter Dufault 171917e476dSPeter Dufault /* 172917e476dSPeter Dufault * XXX The priority and scheduler modifications should 173917e476dSPeter Dufault * be moved into published interfaces in kern/kern_sync. 174917e476dSPeter Dufault * 1758a6472b7SPeter Dufault * The permissions to modify process p were checked in "p31b_proc()". 176917e476dSPeter Dufault * 177917e476dSPeter Dufault */ 178f6c040a2SDavid Xu int 17965343c78SDavid Xu ksched_setscheduler(struct ksched *ksched, 180b40ce416SJulian Elischer struct thread *td, int policy, const struct sched_param *param) 181917e476dSPeter Dufault { 182917e476dSPeter Dufault int e = 0; 183917e476dSPeter Dufault struct rtprio rtp; 184917e476dSPeter Dufault 185917e476dSPeter Dufault switch(policy) 186917e476dSPeter Dufault { 187917e476dSPeter Dufault case SCHED_RR: 188917e476dSPeter Dufault case SCHED_FIFO: 189917e476dSPeter Dufault 190aebde782SPeter Dufault if (param->sched_priority >= P1B_PRIO_MIN && 191aebde782SPeter Dufault param->sched_priority <= P1B_PRIO_MAX) 192917e476dSPeter Dufault { 193aebde782SPeter Dufault rtp.prio = p4prio_to_rtpprio(param->sched_priority); 194917e476dSPeter Dufault rtp.type = (policy == SCHED_FIFO) 195917e476dSPeter Dufault ? RTP_PRIO_FIFO : RTP_PRIO_REALTIME; 196917e476dSPeter Dufault 1978460a577SJohn Birrell rtp_to_pri(&rtp, td); 198917e476dSPeter Dufault } 199917e476dSPeter Dufault else 200917e476dSPeter Dufault e = EPERM; 201917e476dSPeter Dufault 202917e476dSPeter Dufault 203917e476dSPeter Dufault break; 204917e476dSPeter Dufault 205917e476dSPeter Dufault case SCHED_OTHER: 206bec67fd3SRandall Stewart if (param->sched_priority >= 0 && 207bec67fd3SRandall Stewart param->sched_priority <= (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) { 208917e476dSPeter Dufault rtp.type = RTP_PRIO_NORMAL; 209a2311449SDavid Xu rtp.prio = p4prio_to_tsprio(param->sched_priority); 2108460a577SJohn Birrell rtp_to_pri(&rtp, td); 211bec67fd3SRandall Stewart } else 212bec67fd3SRandall Stewart e = EINVAL; 213bec67fd3SRandall Stewart 214917e476dSPeter Dufault break; 2155949ba21SJacques Vidrine 2165949ba21SJacques Vidrine default: 2175949ba21SJacques Vidrine e = EINVAL; 2185949ba21SJacques Vidrine break; 219917e476dSPeter Dufault } 220917e476dSPeter Dufault 221917e476dSPeter Dufault return e; 222917e476dSPeter Dufault } 223917e476dSPeter Dufault 224f6c040a2SDavid Xu int 22565343c78SDavid Xu ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy) 226917e476dSPeter Dufault { 22765343c78SDavid Xu return getscheduler(ksched, td, policy); 228917e476dSPeter Dufault } 229917e476dSPeter Dufault 230917e476dSPeter Dufault /* ksched_yield: Yield the CPU. 231917e476dSPeter Dufault */ 232f6c040a2SDavid Xu int 23365343c78SDavid Xu ksched_yield(struct ksched *ksched) 234917e476dSPeter Dufault { 23536ec198bSDavid Xu sched_relinquish(curthread); 236917e476dSPeter Dufault return 0; 237917e476dSPeter Dufault } 238917e476dSPeter Dufault 239f6c040a2SDavid Xu int 24065343c78SDavid Xu ksched_get_priority_max(struct ksched *ksched, int policy, int *prio) 241917e476dSPeter Dufault { 242917e476dSPeter Dufault int e = 0; 243917e476dSPeter Dufault 244917e476dSPeter Dufault switch (policy) 245917e476dSPeter Dufault { 246917e476dSPeter Dufault case SCHED_FIFO: 247917e476dSPeter Dufault case SCHED_RR: 24865343c78SDavid Xu *prio = RTP_PRIO_MAX; 249917e476dSPeter Dufault break; 250917e476dSPeter Dufault 251917e476dSPeter Dufault case SCHED_OTHER: 252c3ab507fSDavid Xu *prio = PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE; 253917e476dSPeter Dufault break; 254917e476dSPeter Dufault 255917e476dSPeter Dufault default: 256917e476dSPeter Dufault e = EINVAL; 257917e476dSPeter Dufault } 258917e476dSPeter Dufault 259917e476dSPeter Dufault return e; 260917e476dSPeter Dufault } 261917e476dSPeter Dufault 262f6c040a2SDavid Xu int 26365343c78SDavid Xu ksched_get_priority_min(struct ksched *ksched, int policy, int *prio) 264917e476dSPeter Dufault { 265917e476dSPeter Dufault int e = 0; 266917e476dSPeter Dufault 267917e476dSPeter Dufault switch (policy) 268917e476dSPeter Dufault { 269917e476dSPeter Dufault case SCHED_FIFO: 270917e476dSPeter Dufault case SCHED_RR: 27165343c78SDavid Xu *prio = P1B_PRIO_MIN; 272917e476dSPeter Dufault break; 273917e476dSPeter Dufault 274917e476dSPeter Dufault case SCHED_OTHER: 275c3ab507fSDavid Xu *prio = 0; 276917e476dSPeter Dufault break; 277917e476dSPeter Dufault 278917e476dSPeter Dufault default: 279917e476dSPeter Dufault e = EINVAL; 280917e476dSPeter Dufault } 281917e476dSPeter Dufault 282917e476dSPeter Dufault return e; 283917e476dSPeter Dufault } 284917e476dSPeter Dufault 285f6c040a2SDavid Xu int 28665343c78SDavid Xu ksched_rr_get_interval(struct ksched *ksched, 287b40ce416SJulian Elischer struct thread *td, struct timespec *timespec) 288917e476dSPeter Dufault { 2898a6472b7SPeter Dufault *timespec = ksched->rr_interval; 290917e476dSPeter Dufault 291917e476dSPeter Dufault return 0; 292917e476dSPeter Dufault } 293