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 * $FreeBSD: src/sys/posix4/ksched.c,v 1.7.2.1 2000/05/16 06:58:13 dillon Exp $ 33 * $DragonFly: src/sys/kern/kern_sched.c,v 1.3 2003/08/07 21:17:19 dillon Exp $ 34 */ 35 36 /* ksched: Soft real time scheduling based on "rtprio". 37 */ 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/proc.h> 42 #include <sys/kernel.h> 43 #include <sys/resource.h> 44 #include <machine/cpu.h> /* For need_resched */ 45 #include <machine/ipl.h> /* For need_resched */ 46 47 #include "posix4.h" 48 49 /* ksched: Real-time extension to support POSIX priority scheduling. 50 */ 51 52 struct ksched { 53 struct timespec rr_interval; 54 }; 55 56 int ksched_attach(struct ksched **p) 57 { 58 struct ksched *ksched= p31b_malloc(sizeof(*ksched)); 59 60 ksched->rr_interval.tv_sec = 0; 61 ksched->rr_interval.tv_nsec = 1000000000L / roundrobin_interval(); 62 63 *p = ksched; 64 return 0; 65 } 66 67 int ksched_detach(struct ksched *p) 68 { 69 p31b_free(p); 70 71 return 0; 72 } 73 74 /* 75 * XXX About priorities 76 * 77 * POSIX 1003.1b requires that numerically higher priorities be of 78 * higher priority. It also permits sched_setparam to be 79 * implementation defined for SCHED_OTHER. I don't like 80 * the notion of inverted priorites for normal processes when 81 * you can use "setpriority" for that. 82 * 83 * I'm rejecting sched_setparam for SCHED_OTHER with EINVAL. 84 */ 85 86 /* Macros to convert between the unix (lower numerically is higher priority) 87 * and POSIX 1003.1b (higher numerically is higher priority) 88 */ 89 90 #define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P)) 91 #define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P)) 92 93 /* These improve readability a bit for me: 94 */ 95 #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX) 96 #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN) 97 98 static __inline int 99 getscheduler(register_t *ret, struct ksched *ksched, struct proc *p) 100 { 101 int e = 0; 102 103 switch (p->p_rtprio.type) 104 { 105 case RTP_PRIO_FIFO: 106 *ret = SCHED_FIFO; 107 break; 108 109 case RTP_PRIO_REALTIME: 110 *ret = SCHED_RR; 111 break; 112 113 default: 114 *ret = SCHED_OTHER; 115 break; 116 } 117 118 return e; 119 } 120 121 int ksched_setparam(register_t *ret, struct ksched *ksched, 122 struct proc *p, const struct sched_param *param) 123 { 124 register_t policy; 125 int e; 126 127 e = getscheduler(&policy, ksched, p); 128 129 if (e == 0) 130 { 131 if (policy == SCHED_OTHER) 132 e = EINVAL; 133 else 134 e = ksched_setscheduler(ret, ksched, p, policy, param); 135 } 136 137 return e; 138 } 139 140 int ksched_getparam(register_t *ret, struct ksched *ksched, 141 struct proc *p, struct sched_param *param) 142 { 143 if (RTP_PRIO_IS_REALTIME(p->p_rtprio.type)) 144 param->sched_priority = rtpprio_to_p4prio(p->p_rtprio.prio); 145 146 return 0; 147 } 148 149 /* 150 * XXX The priority and scheduler modifications should 151 * be moved into published interfaces in kern/kern_sync. 152 * 153 * The permissions to modify process p were checked in "p31b_proc()". 154 * 155 */ 156 int ksched_setscheduler(register_t *ret, struct ksched *ksched, 157 struct proc *p, int policy, const struct sched_param *param) 158 { 159 int e = 0; 160 struct rtprio rtp; 161 162 switch(policy) 163 { 164 case SCHED_RR: 165 case SCHED_FIFO: 166 167 if (param->sched_priority >= P1B_PRIO_MIN && 168 param->sched_priority <= P1B_PRIO_MAX) 169 { 170 rtp.prio = p4prio_to_rtpprio(param->sched_priority); 171 rtp.type = (policy == SCHED_FIFO) 172 ? RTP_PRIO_FIFO : RTP_PRIO_REALTIME; 173 174 p->p_rtprio = rtp; 175 need_resched(); 176 } 177 else 178 e = EPERM; 179 180 181 break; 182 183 case SCHED_OTHER: 184 { 185 rtp.type = RTP_PRIO_NORMAL; 186 rtp.prio = p4prio_to_rtpprio(param->sched_priority); 187 p->p_rtprio = rtp; 188 189 /* XXX Simply revert to whatever we had for last 190 * normal scheduler priorities. 191 * This puts a requirement 192 * on the scheduling code: You must leave the 193 * scheduling info alone. 194 */ 195 need_resched(); 196 } 197 break; 198 } 199 200 return e; 201 } 202 203 int ksched_getscheduler(register_t *ret, struct ksched *ksched, struct proc *p) 204 { 205 return getscheduler(ret, ksched, p); 206 } 207 208 /* ksched_yield: Yield the CPU. 209 */ 210 int ksched_yield(register_t *ret, struct ksched *ksched) 211 { 212 need_resched(); 213 return 0; 214 } 215 216 int ksched_get_priority_max(register_t*ret, struct ksched *ksched, int policy) 217 { 218 int e = 0; 219 220 switch (policy) 221 { 222 case SCHED_FIFO: 223 case SCHED_RR: 224 *ret = RTP_PRIO_MAX; 225 break; 226 227 case SCHED_OTHER: 228 *ret = PRIO_MAX; 229 break; 230 231 default: 232 e = EINVAL; 233 } 234 235 return e; 236 } 237 238 int ksched_get_priority_min(register_t *ret, struct ksched *ksched, int policy) 239 { 240 int e = 0; 241 242 switch (policy) 243 { 244 case SCHED_FIFO: 245 case SCHED_RR: 246 *ret = P1B_PRIO_MIN; 247 break; 248 249 case SCHED_OTHER: 250 *ret = PRIO_MIN; 251 break; 252 253 default: 254 e = EINVAL; 255 } 256 257 return e; 258 } 259 260 int ksched_rr_get_interval(register_t *ret, struct ksched *ksched, 261 struct proc *p, struct timespec *timespec) 262 { 263 *timespec = ksched->rr_interval; 264 265 return 0; 266 } 267