160727d8bSWarner Losh /*- 2*df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause 3*df57947fSPedro F. Giffuni * 4917e476dSPeter Dufault * Copyright (c) 1996, 1997 5917e476dSPeter Dufault * HD Associates, Inc. All rights reserved. 6917e476dSPeter Dufault * 7917e476dSPeter Dufault * Redistribution and use in source and binary forms, with or without 8917e476dSPeter Dufault * modification, are permitted provided that the following conditions 9917e476dSPeter Dufault * are met: 10917e476dSPeter Dufault * 1. Redistributions of source code must retain the above copyright 11917e476dSPeter Dufault * notice, this list of conditions and the following disclaimer. 12917e476dSPeter Dufault * 2. Redistributions in binary form must reproduce the above copyright 13917e476dSPeter Dufault * notice, this list of conditions and the following disclaimer in the 14917e476dSPeter Dufault * documentation and/or other materials provided with the distribution. 15917e476dSPeter Dufault * 3. All advertising materials mentioning features or use of this software 16917e476dSPeter Dufault * must display the following acknowledgement: 17917e476dSPeter Dufault * This product includes software developed by HD Associates, Inc 18917e476dSPeter Dufault * 4. Neither the name of the author nor the names of any co-contributors 19917e476dSPeter Dufault * may be used to endorse or promote products derived from this software 20917e476dSPeter Dufault * without specific prior written permission. 21917e476dSPeter Dufault * 22917e476dSPeter Dufault * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND 23917e476dSPeter Dufault * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24917e476dSPeter Dufault * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25917e476dSPeter Dufault * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE 26917e476dSPeter Dufault * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27917e476dSPeter Dufault * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28917e476dSPeter Dufault * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29917e476dSPeter Dufault * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30917e476dSPeter Dufault * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31917e476dSPeter Dufault * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32917e476dSPeter Dufault * SUCH DAMAGE. 33917e476dSPeter Dufault */ 34917e476dSPeter Dufault 3544e629f1SKonstantin Belousov /* ksched: Soft real time scheduling based on "rtprio". */ 36917e476dSPeter Dufault 37f4636c59SDavid E. O'Brien #include <sys/cdefs.h> 38f4636c59SDavid E. O'Brien __FBSDID("$FreeBSD$"); 39f4636c59SDavid E. O'Brien 40b565fb9eSAlfred Perlstein #include "opt_posix.h" 41b565fb9eSAlfred Perlstein 42917e476dSPeter Dufault #include <sys/param.h> 43917e476dSPeter Dufault #include <sys/systm.h> 44fb919e4dSMark Murray #include <sys/lock.h> 45de5b1952SAlexander Leidinger #include <sys/sysctl.h> 46de5b1952SAlexander Leidinger #include <sys/kernel.h> 473a187295SJohn Baldwin #include <sys/mutex.h> 48fb919e4dSMark Murray #include <sys/proc.h> 49bdd04ab1STom Rhodes #include <sys/posix4.h> 5038c76440SPeter Dufault #include <sys/resource.h> 51b43179fbSJeff Roberson #include <sys/sched.h> 52917e476dSPeter Dufault 53de5b1952SAlexander Leidinger FEATURE(kposix_priority_scheduling, "POSIX P1003.1B realtime extensions"); 54de5b1952SAlexander Leidinger 5544e629f1SKonstantin Belousov /* ksched: Real-time extension to support POSIX priority scheduling. */ 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 { 6444e629f1SKonstantin Belousov struct ksched *ksched; 65917e476dSPeter Dufault 6644e629f1SKonstantin Belousov ksched = malloc(sizeof(*ksched), M_P31B, M_WAITOK); 678a6472b7SPeter Dufault ksched->rr_interval.tv_sec = 0; 689000aabfSAlexander Motin ksched->rr_interval.tv_nsec = 1000000000L / hz * sched_rr_interval(); 698a6472b7SPeter Dufault *p = ksched; 7044e629f1SKonstantin Belousov return (0); 71917e476dSPeter Dufault } 72917e476dSPeter Dufault 73f6c040a2SDavid Xu int 74f6c040a2SDavid Xu ksched_detach(struct ksched *ks) 75917e476dSPeter Dufault { 768a6472b7SPeter Dufault 7744e629f1SKonstantin Belousov free(ks, M_P31B); 7844e629f1SKonstantin Belousov 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; 11144e629f1SKonstantin Belousov int e; 112917e476dSPeter Dufault 11344e629f1SKonstantin Belousov e = 0; 1148460a577SJohn Birrell pri_to_rtp(td, &rtp); 11544e629f1SKonstantin Belousov switch (rtp.type) { 116917e476dSPeter Dufault case RTP_PRIO_FIFO: 11765343c78SDavid Xu *policy = SCHED_FIFO; 118917e476dSPeter Dufault break; 119917e476dSPeter Dufault case RTP_PRIO_REALTIME: 12065343c78SDavid Xu *policy = SCHED_RR; 121917e476dSPeter Dufault break; 122917e476dSPeter Dufault default: 12365343c78SDavid Xu *policy = SCHED_OTHER; 124917e476dSPeter Dufault break; 125917e476dSPeter Dufault } 12644e629f1SKonstantin Belousov 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 { 13344e629f1SKonstantin Belousov int e, policy; 134917e476dSPeter Dufault 13565343c78SDavid Xu e = getscheduler(ksched, td, &policy); 136917e476dSPeter Dufault if (e == 0) 13765343c78SDavid Xu e = ksched_setscheduler(ksched, td, policy, param); 13844e629f1SKonstantin Belousov return (e); 139917e476dSPeter Dufault } 140917e476dSPeter Dufault 141f6c040a2SDavid Xu int 14244e629f1SKonstantin Belousov ksched_getparam(struct ksched *ksched, struct thread *td, 14344e629f1SKonstantin Belousov struct sched_param *param) 144917e476dSPeter Dufault { 145d5a08a60SJake Burkholder struct rtprio rtp; 146d5a08a60SJake Burkholder 1478460a577SJohn Birrell pri_to_rtp(td, &rtp); 148d5a08a60SJake Burkholder if (RTP_PRIO_IS_REALTIME(rtp.type)) 149d5a08a60SJake Burkholder param->sched_priority = rtpprio_to_p4prio(rtp.prio); 150bec67fd3SRandall Stewart else { 151bec67fd3SRandall Stewart if (PRI_MIN_TIMESHARE < rtp.prio) 152bec67fd3SRandall Stewart /* 153bec67fd3SRandall Stewart * The interactive score has it to min realtime 15444e629f1SKonstantin Belousov * so we must show max (64 most likely). 155bec67fd3SRandall Stewart */ 15644e629f1SKonstantin Belousov param->sched_priority = PRI_MAX_TIMESHARE - 15744e629f1SKonstantin Belousov PRI_MIN_TIMESHARE; 158bec67fd3SRandall Stewart else 159bec67fd3SRandall Stewart param->sched_priority = tsprio_to_p4prio(rtp.prio); 160bec67fd3SRandall Stewart } 16144e629f1SKonstantin Belousov 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 17244e629f1SKonstantin Belousov ksched_setscheduler(struct ksched *ksched, struct thread *td, int policy, 17344e629f1SKonstantin Belousov const struct sched_param *param) 174917e476dSPeter Dufault { 175917e476dSPeter Dufault struct rtprio rtp; 17644e629f1SKonstantin Belousov int e; 177917e476dSPeter Dufault 17844e629f1SKonstantin Belousov e = 0; 17944e629f1SKonstantin Belousov switch(policy) { 180917e476dSPeter Dufault case SCHED_RR: 181917e476dSPeter Dufault case SCHED_FIFO: 182aebde782SPeter Dufault if (param->sched_priority >= P1B_PRIO_MIN && 18344e629f1SKonstantin Belousov param->sched_priority <= P1B_PRIO_MAX) { 184aebde782SPeter Dufault rtp.prio = p4prio_to_rtpprio(param->sched_priority); 18544e629f1SKonstantin Belousov rtp.type = (policy == SCHED_FIFO) ? RTP_PRIO_FIFO : 18644e629f1SKonstantin Belousov RTP_PRIO_REALTIME; 1878460a577SJohn Birrell rtp_to_pri(&rtp, td); 18844e629f1SKonstantin Belousov } else { 189917e476dSPeter Dufault e = EPERM; 19044e629f1SKonstantin Belousov } 191917e476dSPeter Dufault break; 192917e476dSPeter Dufault case SCHED_OTHER: 19344e629f1SKonstantin Belousov if (param->sched_priority >= 0 && param->sched_priority <= 19444e629f1SKonstantin Belousov (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) { 195917e476dSPeter Dufault rtp.type = RTP_PRIO_NORMAL; 196a2311449SDavid Xu rtp.prio = p4prio_to_tsprio(param->sched_priority); 1978460a577SJohn Birrell rtp_to_pri(&rtp, td); 19844e629f1SKonstantin Belousov } else { 199bec67fd3SRandall Stewart e = EINVAL; 20044e629f1SKonstantin Belousov } 201917e476dSPeter Dufault break; 2025949ba21SJacques Vidrine default: 2035949ba21SJacques Vidrine e = EINVAL; 2045949ba21SJacques Vidrine break; 205917e476dSPeter Dufault } 20644e629f1SKonstantin Belousov return (e); 207917e476dSPeter Dufault } 208917e476dSPeter Dufault 209f6c040a2SDavid Xu int 21065343c78SDavid Xu ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy) 211917e476dSPeter Dufault { 21244e629f1SKonstantin Belousov 21344e629f1SKonstantin Belousov return (getscheduler(ksched, td, policy)); 214917e476dSPeter Dufault } 215917e476dSPeter Dufault 21644e629f1SKonstantin Belousov /* ksched_yield: Yield the CPU. */ 217f6c040a2SDavid Xu int 21865343c78SDavid Xu ksched_yield(struct ksched *ksched) 219917e476dSPeter Dufault { 22044e629f1SKonstantin Belousov 22136ec198bSDavid Xu sched_relinquish(curthread); 22244e629f1SKonstantin Belousov return (0); 223917e476dSPeter Dufault } 224917e476dSPeter Dufault 225f6c040a2SDavid Xu int 22665343c78SDavid Xu ksched_get_priority_max(struct ksched *ksched, int policy, int *prio) 227917e476dSPeter Dufault { 22844e629f1SKonstantin Belousov int e; 229917e476dSPeter Dufault 23044e629f1SKonstantin Belousov e = 0; 23144e629f1SKonstantin Belousov switch (policy) { 232917e476dSPeter Dufault case SCHED_FIFO: 233917e476dSPeter Dufault case SCHED_RR: 2348d830e02SKonstantin Belousov *prio = P1B_PRIO_MAX; 235917e476dSPeter Dufault break; 236917e476dSPeter Dufault case SCHED_OTHER: 237c3ab507fSDavid Xu *prio = PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE; 238917e476dSPeter Dufault break; 239917e476dSPeter Dufault default: 240917e476dSPeter Dufault e = EINVAL; 24144e629f1SKonstantin Belousov break; 242917e476dSPeter Dufault } 24344e629f1SKonstantin Belousov return (e); 244917e476dSPeter Dufault } 245917e476dSPeter Dufault 246f6c040a2SDavid Xu int 24765343c78SDavid Xu ksched_get_priority_min(struct ksched *ksched, int policy, int *prio) 248917e476dSPeter Dufault { 24944e629f1SKonstantin Belousov int e; 250917e476dSPeter Dufault 25144e629f1SKonstantin Belousov e = 0; 25244e629f1SKonstantin Belousov switch (policy) { 253917e476dSPeter Dufault case SCHED_FIFO: 254917e476dSPeter Dufault case SCHED_RR: 25565343c78SDavid Xu *prio = P1B_PRIO_MIN; 256917e476dSPeter Dufault break; 257917e476dSPeter Dufault case SCHED_OTHER: 258c3ab507fSDavid Xu *prio = 0; 259917e476dSPeter Dufault break; 260917e476dSPeter Dufault default: 261917e476dSPeter Dufault e = EINVAL; 26244e629f1SKonstantin Belousov break; 263917e476dSPeter Dufault } 26444e629f1SKonstantin Belousov return (e); 265917e476dSPeter Dufault } 266917e476dSPeter Dufault 267f6c040a2SDavid Xu int 26844e629f1SKonstantin Belousov ksched_rr_get_interval(struct ksched *ksched, struct thread *td, 26944e629f1SKonstantin Belousov struct timespec *timespec) 270917e476dSPeter Dufault { 271917e476dSPeter Dufault 27244e629f1SKonstantin Belousov *timespec = ksched->rr_interval; 27344e629f1SKonstantin Belousov return (0); 274917e476dSPeter Dufault } 275