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> 4638c76440SPeter Dufault #include <sys/resource.h> 47b43179fbSJeff Roberson #include <sys/sched.h> 48917e476dSPeter Dufault 498a6472b7SPeter Dufault #include <posix4/posix4.h> 50917e476dSPeter Dufault 51917e476dSPeter Dufault /* ksched: Real-time extension to support POSIX priority scheduling. 52917e476dSPeter Dufault */ 53917e476dSPeter Dufault 548a6472b7SPeter Dufault struct ksched { 558a6472b7SPeter Dufault struct timespec rr_interval; 568a6472b7SPeter Dufault }; 57917e476dSPeter Dufault 58f6c040a2SDavid Xu int 59f6c040a2SDavid Xu ksched_attach(struct ksched **p) 60917e476dSPeter Dufault { 618a6472b7SPeter Dufault struct ksched *ksched= p31b_malloc(sizeof(*ksched)); 62917e476dSPeter Dufault 638a6472b7SPeter Dufault ksched->rr_interval.tv_sec = 0; 64b43179fbSJeff Roberson ksched->rr_interval.tv_nsec = 1000000000L / sched_rr_interval(); 65917e476dSPeter Dufault 668a6472b7SPeter Dufault *p = ksched; 67917e476dSPeter Dufault return 0; 68917e476dSPeter Dufault } 69917e476dSPeter Dufault 70f6c040a2SDavid Xu int 71f6c040a2SDavid Xu ksched_detach(struct ksched *ks) 72917e476dSPeter Dufault { 73b40ce416SJulian Elischer p31b_free(ks); 748a6472b7SPeter Dufault 75917e476dSPeter Dufault return 0; 76917e476dSPeter Dufault } 77917e476dSPeter Dufault 78917e476dSPeter Dufault /* 79917e476dSPeter Dufault * XXX About priorities 80917e476dSPeter Dufault * 818a6472b7SPeter Dufault * POSIX 1003.1b requires that numerically higher priorities be of 82917e476dSPeter Dufault * higher priority. It also permits sched_setparam to be 83917e476dSPeter Dufault * implementation defined for SCHED_OTHER. I don't like 84917e476dSPeter Dufault * the notion of inverted priorites for normal processes when 85917e476dSPeter Dufault * you can use "setpriority" for that. 86917e476dSPeter Dufault * 87917e476dSPeter Dufault * I'm rejecting sched_setparam for SCHED_OTHER with EINVAL. 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 97aebde782SPeter Dufault /* These improve readability a bit for me: 98aebde782SPeter Dufault */ 99aebde782SPeter Dufault #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX) 100aebde782SPeter Dufault #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN) 101aebde782SPeter Dufault 102c1087c13SBruce Evans static __inline int 10365343c78SDavid Xu getscheduler(struct ksched *ksched, struct thread *td, int *policy) 104917e476dSPeter Dufault { 105d5a08a60SJake Burkholder struct rtprio rtp; 106917e476dSPeter Dufault int e = 0; 107917e476dSPeter Dufault 10851b4eed9SJohn Baldwin mtx_lock_spin(&sched_lock); 1092c100766SJulian Elischer pri_to_rtp(td->td_ksegrp, &rtp); 11051b4eed9SJohn Baldwin mtx_unlock_spin(&sched_lock); 111d5a08a60SJake Burkholder switch (rtp.type) 112917e476dSPeter Dufault { 113917e476dSPeter Dufault case RTP_PRIO_FIFO: 11465343c78SDavid Xu *policy = SCHED_FIFO; 115917e476dSPeter Dufault break; 116917e476dSPeter Dufault 117917e476dSPeter Dufault case RTP_PRIO_REALTIME: 11865343c78SDavid Xu *policy = SCHED_RR; 119917e476dSPeter Dufault break; 120917e476dSPeter Dufault 121917e476dSPeter Dufault default: 12265343c78SDavid Xu *policy = SCHED_OTHER; 123917e476dSPeter Dufault break; 124917e476dSPeter Dufault } 125917e476dSPeter Dufault 126917e476dSPeter Dufault return e; 127917e476dSPeter Dufault } 128917e476dSPeter Dufault 129f6c040a2SDavid Xu int 13065343c78SDavid Xu ksched_setparam(struct ksched *ksched, 131b40ce416SJulian Elischer struct thread *td, const struct sched_param *param) 132917e476dSPeter Dufault { 13365343c78SDavid Xu int policy; 1349f79feecSBruce Evans int e; 135917e476dSPeter Dufault 13665343c78SDavid Xu e = getscheduler(ksched, td, &policy); 137917e476dSPeter Dufault 138917e476dSPeter Dufault if (e == 0) 139917e476dSPeter Dufault { 140917e476dSPeter Dufault if (policy == SCHED_OTHER) 141917e476dSPeter Dufault e = EINVAL; 142917e476dSPeter Dufault else 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 15551b4eed9SJohn Baldwin mtx_lock_spin(&sched_lock); 1562c100766SJulian Elischer pri_to_rtp(td->td_ksegrp, &rtp); 15751b4eed9SJohn Baldwin mtx_unlock_spin(&sched_lock); 158d5a08a60SJake Burkholder if (RTP_PRIO_IS_REALTIME(rtp.type)) 159d5a08a60SJake Burkholder param->sched_priority = rtpprio_to_p4prio(rtp.prio); 160917e476dSPeter Dufault 161917e476dSPeter Dufault return 0; 162917e476dSPeter Dufault } 163917e476dSPeter Dufault 164917e476dSPeter Dufault /* 165917e476dSPeter Dufault * XXX The priority and scheduler modifications should 166917e476dSPeter Dufault * be moved into published interfaces in kern/kern_sync. 167917e476dSPeter Dufault * 1688a6472b7SPeter Dufault * The permissions to modify process p were checked in "p31b_proc()". 169917e476dSPeter Dufault * 170917e476dSPeter Dufault */ 171f6c040a2SDavid Xu int 17265343c78SDavid Xu ksched_setscheduler(struct ksched *ksched, 173b40ce416SJulian Elischer struct thread *td, int policy, const struct sched_param *param) 174917e476dSPeter Dufault { 175917e476dSPeter Dufault int e = 0; 176917e476dSPeter Dufault struct rtprio rtp; 1772c100766SJulian Elischer struct ksegrp *kg = td->td_ksegrp; 178917e476dSPeter Dufault 179917e476dSPeter Dufault switch(policy) 180917e476dSPeter Dufault { 181917e476dSPeter Dufault case SCHED_RR: 182917e476dSPeter Dufault case SCHED_FIFO: 183917e476dSPeter Dufault 184aebde782SPeter Dufault if (param->sched_priority >= P1B_PRIO_MIN && 185aebde782SPeter Dufault param->sched_priority <= P1B_PRIO_MAX) 186917e476dSPeter Dufault { 187aebde782SPeter Dufault rtp.prio = p4prio_to_rtpprio(param->sched_priority); 188917e476dSPeter Dufault rtp.type = (policy == SCHED_FIFO) 189917e476dSPeter Dufault ? RTP_PRIO_FIFO : RTP_PRIO_REALTIME; 190917e476dSPeter Dufault 1913a187295SJohn Baldwin mtx_lock_spin(&sched_lock); 1922c100766SJulian Elischer rtp_to_pri(&rtp, kg); 193e602ba25SJulian Elischer FOREACH_THREAD_IN_GROUP(kg, td) { /* XXXKSE */ 19471fad9fdSJulian Elischer if (TD_IS_RUNNING(td)) { 1954a338afdSJulian Elischer td->td_flags |= TDF_NEEDRESCHED; 19671fad9fdSJulian Elischer } else if (TD_ON_RUNQ(td)) { 197e602ba25SJulian Elischer if (td->td_priority > kg->kg_user_pri) { 1981f955e2dSJulian Elischer sched_prio(td, kg->kg_user_pri); 199e602ba25SJulian Elischer } 200e602ba25SJulian Elischer } 201e602ba25SJulian Elischer } 2023a187295SJohn Baldwin mtx_unlock_spin(&sched_lock); 203917e476dSPeter Dufault } 204917e476dSPeter Dufault else 205917e476dSPeter Dufault e = EPERM; 206917e476dSPeter Dufault 207917e476dSPeter Dufault 208917e476dSPeter Dufault break; 209917e476dSPeter Dufault 210917e476dSPeter Dufault case SCHED_OTHER: 211917e476dSPeter Dufault { 212917e476dSPeter Dufault rtp.type = RTP_PRIO_NORMAL; 2132a61a110SPeter Dufault rtp.prio = p4prio_to_rtpprio(param->sched_priority); 2143a187295SJohn Baldwin mtx_lock_spin(&sched_lock); 2152c100766SJulian Elischer rtp_to_pri(&rtp, kg); 216917e476dSPeter Dufault 217917e476dSPeter Dufault /* XXX Simply revert to whatever we had for last 218917e476dSPeter Dufault * normal scheduler priorities. 219917e476dSPeter Dufault * This puts a requirement 220917e476dSPeter Dufault * on the scheduling code: You must leave the 221917e476dSPeter Dufault * scheduling info alone. 222917e476dSPeter Dufault */ 223e602ba25SJulian Elischer FOREACH_THREAD_IN_GROUP(kg, td) { 22471fad9fdSJulian Elischer if (TD_IS_RUNNING(td)) { 2254a338afdSJulian Elischer td->td_flags |= TDF_NEEDRESCHED; 22671fad9fdSJulian Elischer } else if (TD_ON_RUNQ(td)) { 227e602ba25SJulian Elischer if (td->td_priority > kg->kg_user_pri) { 2281f955e2dSJulian Elischer sched_prio(td, kg->kg_user_pri); 229e602ba25SJulian Elischer } 230e602ba25SJulian Elischer } 231e602ba25SJulian Elischer 232e602ba25SJulian Elischer } 2333a187295SJohn Baldwin mtx_unlock_spin(&sched_lock); 234917e476dSPeter Dufault } 235917e476dSPeter Dufault break; 2365949ba21SJacques Vidrine 2375949ba21SJacques Vidrine default: 2385949ba21SJacques Vidrine e = EINVAL; 2395949ba21SJacques Vidrine break; 240917e476dSPeter Dufault } 241917e476dSPeter Dufault 242917e476dSPeter Dufault return e; 243917e476dSPeter Dufault } 244917e476dSPeter Dufault 245f6c040a2SDavid Xu int 24665343c78SDavid Xu ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy) 247917e476dSPeter Dufault { 24865343c78SDavid Xu return getscheduler(ksched, td, policy); 249917e476dSPeter Dufault } 250917e476dSPeter Dufault 251917e476dSPeter Dufault /* ksched_yield: Yield the CPU. 252917e476dSPeter Dufault */ 253f6c040a2SDavid Xu int 25465343c78SDavid Xu ksched_yield(struct ksched *ksched) 255917e476dSPeter Dufault { 25636ec198bSDavid Xu sched_relinquish(curthread); 257917e476dSPeter Dufault return 0; 258917e476dSPeter Dufault } 259917e476dSPeter Dufault 260f6c040a2SDavid Xu int 26165343c78SDavid Xu ksched_get_priority_max(struct ksched *ksched, int policy, int *prio) 262917e476dSPeter Dufault { 263917e476dSPeter Dufault int e = 0; 264917e476dSPeter Dufault 265917e476dSPeter Dufault switch (policy) 266917e476dSPeter Dufault { 267917e476dSPeter Dufault case SCHED_FIFO: 268917e476dSPeter Dufault case SCHED_RR: 26965343c78SDavid Xu *prio = RTP_PRIO_MAX; 270917e476dSPeter Dufault break; 271917e476dSPeter Dufault 272917e476dSPeter Dufault case SCHED_OTHER: 27365343c78SDavid Xu *prio = PRIO_MAX; 274917e476dSPeter Dufault break; 275917e476dSPeter Dufault 276917e476dSPeter Dufault default: 277917e476dSPeter Dufault e = EINVAL; 278917e476dSPeter Dufault } 279917e476dSPeter Dufault 280917e476dSPeter Dufault return e; 281917e476dSPeter Dufault } 282917e476dSPeter Dufault 283f6c040a2SDavid Xu int 28465343c78SDavid Xu ksched_get_priority_min(struct ksched *ksched, int policy, int *prio) 285917e476dSPeter Dufault { 286917e476dSPeter Dufault int e = 0; 287917e476dSPeter Dufault 288917e476dSPeter Dufault switch (policy) 289917e476dSPeter Dufault { 290917e476dSPeter Dufault case SCHED_FIFO: 291917e476dSPeter Dufault case SCHED_RR: 29265343c78SDavid Xu *prio = P1B_PRIO_MIN; 293917e476dSPeter Dufault break; 294917e476dSPeter Dufault 295917e476dSPeter Dufault case SCHED_OTHER: 29665343c78SDavid Xu *prio = PRIO_MIN; 297917e476dSPeter Dufault break; 298917e476dSPeter Dufault 299917e476dSPeter Dufault default: 300917e476dSPeter Dufault e = EINVAL; 301917e476dSPeter Dufault } 302917e476dSPeter Dufault 303917e476dSPeter Dufault return e; 304917e476dSPeter Dufault } 305917e476dSPeter Dufault 306f6c040a2SDavid Xu int 30765343c78SDavid Xu ksched_rr_get_interval(struct ksched *ksched, 308b40ce416SJulian Elischer struct thread *td, struct timespec *timespec) 309917e476dSPeter Dufault { 3108a6472b7SPeter Dufault *timespec = ksched->rr_interval; 311917e476dSPeter Dufault 312917e476dSPeter Dufault return 0; 313917e476dSPeter Dufault } 314