1917e476dSPeter Dufault /* 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 * 329f79feecSBruce Evans * $FreeBSD$ 33917e476dSPeter Dufault */ 34917e476dSPeter Dufault 35917e476dSPeter Dufault /* ksched: Soft real time scheduling based on "rtprio". 36917e476dSPeter Dufault */ 37917e476dSPeter Dufault 38917e476dSPeter Dufault #include <sys/param.h> 39917e476dSPeter Dufault #include <sys/systm.h> 40fb919e4dSMark Murray #include <sys/lock.h> 413a187295SJohn Baldwin #include <sys/mutex.h> 42fb919e4dSMark Murray #include <sys/proc.h> 4338c76440SPeter Dufault #include <sys/resource.h> 44917e476dSPeter Dufault 458a6472b7SPeter Dufault #include <posix4/posix4.h> 46917e476dSPeter Dufault 47917e476dSPeter Dufault /* ksched: Real-time extension to support POSIX priority scheduling. 48917e476dSPeter Dufault */ 49917e476dSPeter Dufault 508a6472b7SPeter Dufault struct ksched { 518a6472b7SPeter Dufault struct timespec rr_interval; 528a6472b7SPeter Dufault }; 53917e476dSPeter Dufault 548a6472b7SPeter Dufault int ksched_attach(struct ksched **p) 55917e476dSPeter Dufault { 568a6472b7SPeter Dufault struct ksched *ksched= p31b_malloc(sizeof(*ksched)); 57917e476dSPeter Dufault 588a6472b7SPeter Dufault ksched->rr_interval.tv_sec = 0; 598a6472b7SPeter Dufault ksched->rr_interval.tv_nsec = 1000000000L / roundrobin_interval(); 60917e476dSPeter Dufault 618a6472b7SPeter Dufault *p = ksched; 62917e476dSPeter Dufault return 0; 63917e476dSPeter Dufault } 64917e476dSPeter Dufault 658a6472b7SPeter Dufault int ksched_detach(struct ksched *p) 66917e476dSPeter Dufault { 678a6472b7SPeter Dufault p31b_free(p); 688a6472b7SPeter Dufault 69917e476dSPeter Dufault return 0; 70917e476dSPeter Dufault } 71917e476dSPeter Dufault 72917e476dSPeter Dufault /* 73917e476dSPeter Dufault * XXX About priorities 74917e476dSPeter Dufault * 758a6472b7SPeter Dufault * POSIX 1003.1b requires that numerically higher priorities be of 76917e476dSPeter Dufault * higher priority. It also permits sched_setparam to be 77917e476dSPeter Dufault * implementation defined for SCHED_OTHER. I don't like 78917e476dSPeter Dufault * the notion of inverted priorites for normal processes when 79917e476dSPeter Dufault * you can use "setpriority" for that. 80917e476dSPeter Dufault * 81917e476dSPeter Dufault * I'm rejecting sched_setparam for SCHED_OTHER with EINVAL. 82917e476dSPeter Dufault */ 83917e476dSPeter Dufault 84917e476dSPeter Dufault /* Macros to convert between the unix (lower numerically is higher priority) 858a6472b7SPeter Dufault * and POSIX 1003.1b (higher numerically is higher priority) 86917e476dSPeter Dufault */ 87917e476dSPeter Dufault 88917e476dSPeter Dufault #define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P)) 89917e476dSPeter Dufault #define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P)) 90917e476dSPeter Dufault 91aebde782SPeter Dufault /* These improve readability a bit for me: 92aebde782SPeter Dufault */ 93aebde782SPeter Dufault #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX) 94aebde782SPeter Dufault #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN) 95aebde782SPeter Dufault 96c1087c13SBruce Evans static __inline int 979f79feecSBruce Evans getscheduler(register_t *ret, struct ksched *ksched, struct proc *p) 98917e476dSPeter Dufault { 99d5a08a60SJake Burkholder struct rtprio rtp; 100917e476dSPeter Dufault int e = 0; 101917e476dSPeter Dufault 102d5a08a60SJake Burkholder pri_to_rtp(&p->p_pri, &rtp); 103d5a08a60SJake Burkholder switch (rtp.type) 104917e476dSPeter Dufault { 105917e476dSPeter Dufault case RTP_PRIO_FIFO: 106917e476dSPeter Dufault *ret = SCHED_FIFO; 107917e476dSPeter Dufault break; 108917e476dSPeter Dufault 109917e476dSPeter Dufault case RTP_PRIO_REALTIME: 110917e476dSPeter Dufault *ret = SCHED_RR; 111917e476dSPeter Dufault break; 112917e476dSPeter Dufault 113917e476dSPeter Dufault default: 114917e476dSPeter Dufault *ret = SCHED_OTHER; 115917e476dSPeter Dufault break; 116917e476dSPeter Dufault } 117917e476dSPeter Dufault 118917e476dSPeter Dufault return e; 119917e476dSPeter Dufault } 120917e476dSPeter Dufault 1219f79feecSBruce Evans int ksched_setparam(register_t *ret, struct ksched *ksched, 122917e476dSPeter Dufault struct proc *p, const struct sched_param *param) 123917e476dSPeter Dufault { 1249f79feecSBruce Evans register_t policy; 1259f79feecSBruce Evans int e; 126917e476dSPeter Dufault 1278a6472b7SPeter Dufault e = getscheduler(&policy, ksched, p); 128917e476dSPeter Dufault 129917e476dSPeter Dufault if (e == 0) 130917e476dSPeter Dufault { 131917e476dSPeter Dufault if (policy == SCHED_OTHER) 132917e476dSPeter Dufault e = EINVAL; 133917e476dSPeter Dufault else 1348a6472b7SPeter Dufault e = ksched_setscheduler(ret, ksched, p, policy, param); 135917e476dSPeter Dufault } 136917e476dSPeter Dufault 137917e476dSPeter Dufault return e; 138917e476dSPeter Dufault } 139917e476dSPeter Dufault 1409f79feecSBruce Evans int ksched_getparam(register_t *ret, struct ksched *ksched, 141917e476dSPeter Dufault struct proc *p, struct sched_param *param) 142917e476dSPeter Dufault { 143d5a08a60SJake Burkholder struct rtprio rtp; 144d5a08a60SJake Burkholder 145d5a08a60SJake Burkholder pri_to_rtp(&p->p_pri, &rtp); 146d5a08a60SJake Burkholder if (RTP_PRIO_IS_REALTIME(rtp.type)) 147d5a08a60SJake Burkholder param->sched_priority = rtpprio_to_p4prio(rtp.prio); 148917e476dSPeter Dufault 149917e476dSPeter Dufault return 0; 150917e476dSPeter Dufault } 151917e476dSPeter Dufault 152917e476dSPeter Dufault /* 153917e476dSPeter Dufault * XXX The priority and scheduler modifications should 154917e476dSPeter Dufault * be moved into published interfaces in kern/kern_sync. 155917e476dSPeter Dufault * 1568a6472b7SPeter Dufault * The permissions to modify process p were checked in "p31b_proc()". 157917e476dSPeter Dufault * 158917e476dSPeter Dufault */ 1599f79feecSBruce Evans int ksched_setscheduler(register_t *ret, struct ksched *ksched, 160917e476dSPeter Dufault struct proc *p, int policy, const struct sched_param *param) 161917e476dSPeter Dufault { 162917e476dSPeter Dufault int e = 0; 163917e476dSPeter Dufault struct rtprio rtp; 164917e476dSPeter Dufault 165917e476dSPeter Dufault switch(policy) 166917e476dSPeter Dufault { 167917e476dSPeter Dufault case SCHED_RR: 168917e476dSPeter Dufault case SCHED_FIFO: 169917e476dSPeter Dufault 170aebde782SPeter Dufault if (param->sched_priority >= P1B_PRIO_MIN && 171aebde782SPeter Dufault param->sched_priority <= P1B_PRIO_MAX) 172917e476dSPeter Dufault { 173aebde782SPeter Dufault rtp.prio = p4prio_to_rtpprio(param->sched_priority); 174917e476dSPeter Dufault rtp.type = (policy == SCHED_FIFO) 175917e476dSPeter Dufault ? RTP_PRIO_FIFO : RTP_PRIO_REALTIME; 176917e476dSPeter Dufault 1773a187295SJohn Baldwin mtx_lock_spin(&sched_lock); 178d5a08a60SJake Burkholder rtp_to_pri(&rtp, &p->p_pri); 1796caa8a15SJohn Baldwin need_resched(p); 1803a187295SJohn Baldwin mtx_unlock_spin(&sched_lock); 181917e476dSPeter Dufault } 182917e476dSPeter Dufault else 183917e476dSPeter Dufault e = EPERM; 184917e476dSPeter Dufault 185917e476dSPeter Dufault 186917e476dSPeter Dufault break; 187917e476dSPeter Dufault 188917e476dSPeter Dufault case SCHED_OTHER: 189917e476dSPeter Dufault { 190917e476dSPeter Dufault rtp.type = RTP_PRIO_NORMAL; 1912a61a110SPeter Dufault rtp.prio = p4prio_to_rtpprio(param->sched_priority); 1923a187295SJohn Baldwin mtx_lock_spin(&sched_lock); 193d5a08a60SJake Burkholder rtp_to_pri(&rtp, &p->p_pri); 194917e476dSPeter Dufault 195917e476dSPeter Dufault /* XXX Simply revert to whatever we had for last 196917e476dSPeter Dufault * normal scheduler priorities. 197917e476dSPeter Dufault * This puts a requirement 198917e476dSPeter Dufault * on the scheduling code: You must leave the 199917e476dSPeter Dufault * scheduling info alone. 200917e476dSPeter Dufault */ 2016caa8a15SJohn Baldwin need_resched(p); 2023a187295SJohn Baldwin mtx_unlock_spin(&sched_lock); 203917e476dSPeter Dufault } 204917e476dSPeter Dufault break; 205917e476dSPeter Dufault } 206917e476dSPeter Dufault 207917e476dSPeter Dufault return e; 208917e476dSPeter Dufault } 209917e476dSPeter Dufault 2109f79feecSBruce Evans int ksched_getscheduler(register_t *ret, struct ksched *ksched, struct proc *p) 211917e476dSPeter Dufault { 2128a6472b7SPeter Dufault return getscheduler(ret, ksched, p); 213917e476dSPeter Dufault } 214917e476dSPeter Dufault 215917e476dSPeter Dufault /* ksched_yield: Yield the CPU. 216917e476dSPeter Dufault */ 2179f79feecSBruce Evans int ksched_yield(register_t *ret, struct ksched *ksched) 218917e476dSPeter Dufault { 2193a187295SJohn Baldwin mtx_lock_spin(&sched_lock); 2206caa8a15SJohn Baldwin need_resched(curproc); 2213a187295SJohn Baldwin mtx_unlock_spin(&sched_lock); 222917e476dSPeter Dufault return 0; 223917e476dSPeter Dufault } 224917e476dSPeter Dufault 2259f79feecSBruce Evans int ksched_get_priority_max(register_t*ret, struct ksched *ksched, int policy) 226917e476dSPeter Dufault { 227917e476dSPeter Dufault int e = 0; 228917e476dSPeter Dufault 229917e476dSPeter Dufault switch (policy) 230917e476dSPeter Dufault { 231917e476dSPeter Dufault case SCHED_FIFO: 232917e476dSPeter Dufault case SCHED_RR: 233917e476dSPeter Dufault *ret = RTP_PRIO_MAX; 234917e476dSPeter Dufault break; 235917e476dSPeter Dufault 236917e476dSPeter Dufault case SCHED_OTHER: 237917e476dSPeter Dufault *ret = PRIO_MAX; 238917e476dSPeter Dufault break; 239917e476dSPeter Dufault 240917e476dSPeter Dufault default: 241917e476dSPeter Dufault e = EINVAL; 242917e476dSPeter Dufault } 243917e476dSPeter Dufault 244917e476dSPeter Dufault return e; 245917e476dSPeter Dufault } 246917e476dSPeter Dufault 2479f79feecSBruce Evans int ksched_get_priority_min(register_t *ret, struct ksched *ksched, int policy) 248917e476dSPeter Dufault { 249917e476dSPeter Dufault int e = 0; 250917e476dSPeter Dufault 251917e476dSPeter Dufault switch (policy) 252917e476dSPeter Dufault { 253917e476dSPeter Dufault case SCHED_FIFO: 254917e476dSPeter Dufault case SCHED_RR: 255aebde782SPeter Dufault *ret = P1B_PRIO_MIN; 256917e476dSPeter Dufault break; 257917e476dSPeter Dufault 258917e476dSPeter Dufault case SCHED_OTHER: 259917e476dSPeter Dufault *ret = PRIO_MIN; 260917e476dSPeter Dufault break; 261917e476dSPeter Dufault 262917e476dSPeter Dufault default: 263917e476dSPeter Dufault e = EINVAL; 264917e476dSPeter Dufault } 265917e476dSPeter Dufault 266917e476dSPeter Dufault return e; 267917e476dSPeter Dufault } 268917e476dSPeter Dufault 2699f79feecSBruce Evans int ksched_rr_get_interval(register_t *ret, struct ksched *ksched, 270917e476dSPeter Dufault struct proc *p, struct timespec *timespec) 271917e476dSPeter Dufault { 2728a6472b7SPeter Dufault *timespec = ksched->rr_interval; 273917e476dSPeter Dufault 274917e476dSPeter Dufault return 0; 275917e476dSPeter Dufault } 276