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