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 36 #include <sys/cdefs.h> 37 __FBSDID("$FreeBSD$"); 38 39 #include "opt_posix.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/lock.h> 44 #include <sys/sysctl.h> 45 #include <sys/kernel.h> 46 #include <sys/mutex.h> 47 #include <sys/proc.h> 48 #include <sys/posix4.h> 49 #include <sys/resource.h> 50 #include <sys/sched.h> 51 52 FEATURE(kposix_priority_scheduling, "POSIX P1003.1B realtime extensions"); 53 54 /* ksched: Real-time extension to support POSIX priority scheduling. 55 */ 56 57 struct ksched { 58 struct timespec rr_interval; 59 }; 60 61 int 62 ksched_attach(struct ksched **p) 63 { 64 struct ksched *ksched= p31b_malloc(sizeof(*ksched)); 65 66 ksched->rr_interval.tv_sec = 0; 67 ksched->rr_interval.tv_nsec = 1000000000L / hz * sched_rr_interval(); 68 69 *p = ksched; 70 return 0; 71 } 72 73 int 74 ksched_detach(struct ksched *ks) 75 { 76 p31b_free(ks); 77 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 = 0; 112 113 pri_to_rtp(td, &rtp); 114 switch (rtp.type) 115 { 116 case RTP_PRIO_FIFO: 117 *policy = SCHED_FIFO; 118 break; 119 120 case RTP_PRIO_REALTIME: 121 *policy = SCHED_RR; 122 break; 123 124 default: 125 *policy = SCHED_OTHER; 126 break; 127 } 128 129 return e; 130 } 131 132 int 133 ksched_setparam(struct ksched *ksched, 134 struct thread *td, const struct sched_param *param) 135 { 136 int policy; 137 int e; 138 139 e = getscheduler(ksched, td, &policy); 140 141 if (e == 0) 142 { 143 e = ksched_setscheduler(ksched, td, policy, param); 144 } 145 146 return e; 147 } 148 149 int 150 ksched_getparam(struct ksched *ksched, 151 struct thread *td, struct sched_param *param) 152 { 153 struct rtprio rtp; 154 155 pri_to_rtp(td, &rtp); 156 if (RTP_PRIO_IS_REALTIME(rtp.type)) 157 param->sched_priority = rtpprio_to_p4prio(rtp.prio); 158 else { 159 if (PRI_MIN_TIMESHARE < rtp.prio) 160 /* 161 * The interactive score has it to min realtime 162 * so we must show max (64 most likely 163 */ 164 param->sched_priority = (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE); 165 else 166 param->sched_priority = tsprio_to_p4prio(rtp.prio); 167 } 168 return 0; 169 } 170 171 /* 172 * XXX The priority and scheduler modifications should 173 * be moved into published interfaces in kern/kern_sync. 174 * 175 * The permissions to modify process p were checked in "p31b_proc()". 176 * 177 */ 178 int 179 ksched_setscheduler(struct ksched *ksched, 180 struct thread *td, int policy, const struct sched_param *param) 181 { 182 int e = 0; 183 struct rtprio rtp; 184 185 switch(policy) 186 { 187 case SCHED_RR: 188 case SCHED_FIFO: 189 190 if (param->sched_priority >= P1B_PRIO_MIN && 191 param->sched_priority <= P1B_PRIO_MAX) 192 { 193 rtp.prio = p4prio_to_rtpprio(param->sched_priority); 194 rtp.type = (policy == SCHED_FIFO) 195 ? RTP_PRIO_FIFO : RTP_PRIO_REALTIME; 196 197 rtp_to_pri(&rtp, td); 198 } 199 else 200 e = EPERM; 201 202 203 break; 204 205 case SCHED_OTHER: 206 if (param->sched_priority >= 0 && 207 param->sched_priority <= (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) { 208 rtp.type = RTP_PRIO_NORMAL; 209 rtp.prio = p4prio_to_tsprio(param->sched_priority); 210 rtp_to_pri(&rtp, td); 211 } else 212 e = EINVAL; 213 214 break; 215 216 default: 217 e = EINVAL; 218 break; 219 } 220 221 return e; 222 } 223 224 int 225 ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy) 226 { 227 return getscheduler(ksched, td, policy); 228 } 229 230 /* ksched_yield: Yield the CPU. 231 */ 232 int 233 ksched_yield(struct ksched *ksched) 234 { 235 sched_relinquish(curthread); 236 return 0; 237 } 238 239 int 240 ksched_get_priority_max(struct ksched *ksched, int policy, int *prio) 241 { 242 int e = 0; 243 244 switch (policy) 245 { 246 case SCHED_FIFO: 247 case SCHED_RR: 248 *prio = RTP_PRIO_MAX; 249 break; 250 251 case SCHED_OTHER: 252 *prio = PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE; 253 break; 254 255 default: 256 e = EINVAL; 257 } 258 259 return e; 260 } 261 262 int 263 ksched_get_priority_min(struct ksched *ksched, int policy, int *prio) 264 { 265 int e = 0; 266 267 switch (policy) 268 { 269 case SCHED_FIFO: 270 case SCHED_RR: 271 *prio = P1B_PRIO_MIN; 272 break; 273 274 case SCHED_OTHER: 275 *prio = 0; 276 break; 277 278 default: 279 e = EINVAL; 280 } 281 282 return e; 283 } 284 285 int 286 ksched_rr_get_interval(struct ksched *ksched, 287 struct thread *td, struct timespec *timespec) 288 { 289 *timespec = ksched->rr_interval; 290 291 return 0; 292 } 293