1/*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 1996, 1997 5 * HD Associates, Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by HD Associates, Inc 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35/* ksched: Soft real time scheduling based on "rtprio". */ 36 37#include <sys/cdefs.h> 38__FBSDID("$FreeBSD$"); 39 40#include "opt_posix.h" 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/lock.h> 45#include <sys/sysctl.h> 46#include <sys/kernel.h> 47#include <sys/mutex.h> 48#include <sys/proc.h> 49#include <sys/posix4.h> 50#include <sys/resource.h> 51#include <sys/sched.h> 52 53FEATURE(kposix_priority_scheduling, "POSIX P1003.1B realtime extensions"); 54 55/* ksched: Real-time extension to support POSIX priority scheduling. */ 56 57struct ksched { 58 struct timespec rr_interval; 59}; 60 61int 62ksched_attach(struct ksched **p) 63{ 64 struct ksched *ksched; 65 66 ksched = malloc(sizeof(*ksched), M_P31B, M_WAITOK); 67 ksched->rr_interval.tv_sec = 0; 68 ksched->rr_interval.tv_nsec = 1000000000L / hz * sched_rr_interval(); 69 *p = ksched; 70 return (0); 71} 72 73int 74ksched_detach(struct ksched *ks) 75{ 76 77 free(ks, M_P31B); 78 return (0); 79} 80 81/* 82 * XXX About priorities 83 * 84 * POSIX 1003.1b requires that numerically higher priorities be of 85 * higher priority. It also permits sched_setparam to be 86 * implementation defined for SCHED_OTHER. I don't like 87 * the notion of inverted priorites for normal processes when 88 * you can use "setpriority" for that. 89 * 90 */ 91 92/* Macros to convert between the unix (lower numerically is higher priority) 93 * and POSIX 1003.1b (higher numerically is higher priority) 94 */ 95 96#define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P)) 97#define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P)) 98 99#define p4prio_to_tsprio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P)) 100#define tsprio_to_p4prio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P)) 101 102/* These improve readability a bit for me: 103 */ 104#define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX) 105#define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN) 106 107static __inline int 108getscheduler(struct ksched *ksched, struct thread *td, int *policy) 109{ 110 struct rtprio rtp; 111 int e; 112 113 e = 0; 114 pri_to_rtp(td, &rtp); 115 switch (rtp.type) { 116 case RTP_PRIO_FIFO: 117 *policy = SCHED_FIFO; 118 break; 119 case RTP_PRIO_REALTIME: 120 *policy = SCHED_RR; 121 break; 122 default: 123 *policy = SCHED_OTHER; 124 break; 125 } 126 return (e); 127} 128 129int 130ksched_setparam(struct ksched *ksched, 131 struct thread *td, const struct sched_param *param) 132{ 133 int e, policy; 134 135 e = getscheduler(ksched, td, &policy); 136 if (e == 0) 137 e = ksched_setscheduler(ksched, td, policy, param); 138 return (e); 139} 140 141int 142ksched_getparam(struct ksched *ksched, struct thread *td, 143 struct sched_param *param) 144{ 145 struct rtprio rtp; 146 147 pri_to_rtp(td, &rtp); 148 if (RTP_PRIO_IS_REALTIME(rtp.type)) 149 param->sched_priority = rtpprio_to_p4prio(rtp.prio); 150 else { 151 if (PRI_MIN_TIMESHARE < rtp.prio) 152 /* 153 * The interactive score has it to min realtime 154 * so we must show max (64 most likely). 155 */ 156 param->sched_priority = PRI_MAX_TIMESHARE - 157 PRI_MIN_TIMESHARE; 158 else 159 param->sched_priority = tsprio_to_p4prio(rtp.prio); 160 } 161 return (0); 162} 163 164/* 165 * XXX The priority and scheduler modifications should 166 * be moved into published interfaces in kern/kern_sync. 167 * 168 * The permissions to modify process p were checked in "p31b_proc()". 169 * 170 */ 171int 172ksched_setscheduler(struct ksched *ksched, struct thread *td, int policy, 173 const struct sched_param *param) 174{ 175 struct rtprio rtp; 176 int e; 177 178 e = 0; 179 switch(policy) { 180 case SCHED_RR: 181 case SCHED_FIFO: 182 if (param->sched_priority >= P1B_PRIO_MIN && 183 param->sched_priority <= P1B_PRIO_MAX) { 184 rtp.prio = p4prio_to_rtpprio(param->sched_priority); 185 rtp.type = (policy == SCHED_FIFO) ? RTP_PRIO_FIFO : 186 RTP_PRIO_REALTIME; 187 rtp_to_pri(&rtp, td); 188 } else { 189 e = EPERM; 190 } 191 break; 192 case SCHED_OTHER: 193 if (param->sched_priority >= 0 && param->sched_priority <= 194 (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) { 195 rtp.type = RTP_PRIO_NORMAL; 196 rtp.prio = p4prio_to_tsprio(param->sched_priority); 197 rtp_to_pri(&rtp, td); 198 } else { 199 e = EINVAL; 200 } 201 break; 202 default: 203 e = EINVAL; 204 break; 205 } 206 return (e); 207} 208 209int 210ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy) 211{ 212 213 return (getscheduler(ksched, td, policy)); 214} 215 216/* ksched_yield: Yield the CPU. */ 217int 218ksched_yield(struct ksched *ksched) 219{ 220 221 sched_relinquish(curthread); 222 return (0); 223} 224 225int 226ksched_get_priority_max(struct ksched *ksched, int policy, int *prio) 227{ 228 int e; 229 230 e = 0; 231 switch (policy) { 232 case SCHED_FIFO: 233 case SCHED_RR: 234 *prio = P1B_PRIO_MAX; 235 break; 236 case SCHED_OTHER: 237 *prio = PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE; 238 break; 239 default: 240 e = EINVAL; 241 break; 242 } 243 return (e); 244} 245 246int 247ksched_get_priority_min(struct ksched *ksched, int policy, int *prio) 248{ 249 int e; 250 251 e = 0; 252 switch (policy) { 253 case SCHED_FIFO: 254 case SCHED_RR: 255 *prio = P1B_PRIO_MIN; 256 break; 257 case SCHED_OTHER: 258 *prio = 0; 259 break; 260 default: 261 e = EINVAL; 262 break; 263 } 264 return (e); 265} 266 267int 268ksched_rr_get_interval(struct ksched *ksched, struct thread *td, 269 struct timespec *timespec) 270{ 271 272 *timespec = ksched->rr_interval; 273 return (0); 274} 275