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 53 FEATURE(kposix_priority_scheduling, "POSIX P1003.1B realtime extensions"); 54 55 /* ksched: Real-time extension to support POSIX priority scheduling. */ 56 57 struct ksched { 58 struct timespec rr_interval; 59 }; 60 61 int 62 ksched_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 73 int 74 ksched_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 107 static __inline int 108 getscheduler(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 129 int 130 ksched_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 141 int 142 ksched_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 */ 171 int 172 ksched_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 209 int 210 ksched_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. */ 217 int 218 ksched_yield(struct ksched *ksched) 219 { 220 221 sched_relinquish(curthread); 222 return (0); 223 } 224 225 int 226 ksched_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 246 int 247 ksched_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 267 int 268 ksched_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