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 */ 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/malloc.h> 42 #include <sys/posix4.h> 43 #include <sys/proc.h> 44 #include <sys/kernel.h> 45 #include <sys/resource.h> 46 #include <machine/cpu.h> /* For need_user_resched */ 47 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 57 ksched_attach(struct ksched **p) 58 { 59 struct ksched *ksched; 60 61 ksched = kmalloc(sizeof(*ksched), M_P31B, M_WAITOK); 62 63 ksched->rr_interval.tv_sec = 0; 64 ksched->rr_interval.tv_nsec = 1000000000L / 10; /* XXX */ 65 66 *p = ksched; 67 return 0; 68 } 69 70 int 71 ksched_detach(struct ksched *p) 72 { 73 kfree(p, M_P31B); 74 75 return 0; 76 } 77 78 /* 79 * XXX About priorities 80 * 81 * POSIX 1003.1b requires that numerically higher priorities be of 82 * higher priority. It also permits sched_setparam to be 83 * implementation defined for SCHED_OTHER. I don't like 84 * the notion of inverted priorites for normal processes when 85 * you can use "setpriority" for that. 86 * 87 * I'm rejecting sched_setparam for SCHED_OTHER with EINVAL. 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 /* 98 * These improve readability a bit for me: 99 */ 100 #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX) 101 #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN) 102 103 static __inline int 104 getscheduler(register_t *ret, struct ksched *ksched, struct lwp *lp) 105 { 106 int e = 0; 107 108 switch (lp->lwp_rtprio.type) { 109 case RTP_PRIO_FIFO: 110 *ret = SCHED_FIFO; 111 break; 112 case RTP_PRIO_REALTIME: 113 *ret = SCHED_RR; 114 break; 115 default: 116 *ret = SCHED_OTHER; 117 break; 118 } 119 120 return e; 121 } 122 123 int 124 ksched_setparam(register_t *ret, struct ksched *ksched, 125 struct lwp *lp, const struct sched_param *param) 126 { 127 register_t policy; 128 int e; 129 130 e = getscheduler(&policy, ksched, lp); 131 132 if (e == 0) { 133 if (policy == SCHED_OTHER) 134 e = EINVAL; 135 else 136 e = ksched_setscheduler(ret, ksched, lp, policy, param); 137 } 138 139 return e; 140 } 141 142 int 143 ksched_getparam(register_t *ret, struct ksched *ksched, 144 struct lwp *lp, struct sched_param *param) 145 { 146 if (RTP_PRIO_IS_REALTIME(lp->lwp_rtprio.type)) 147 param->sched_priority = rtpprio_to_p4prio(lp->lwp_rtprio.prio); 148 149 return 0; 150 } 151 152 /* 153 * XXX The priority and scheduler modifications should 154 * be moved into published interfaces in kern/kern_sync. 155 * 156 * The permissions to modify process p were checked in "p31b_proc()". 157 * 158 */ 159 int 160 ksched_setscheduler(register_t *ret, struct ksched *ksched, 161 struct lwp *lp, int policy, const struct sched_param *param) 162 { 163 int e = 0; 164 struct rtprio rtp; 165 166 switch(policy) { 167 case SCHED_RR: 168 case SCHED_FIFO: 169 if (param->sched_priority >= P1B_PRIO_MIN && 170 param->sched_priority <= P1B_PRIO_MAX) { 171 rtp.prio = p4prio_to_rtpprio(param->sched_priority); 172 rtp.type = (policy == SCHED_FIFO) ? 173 RTP_PRIO_FIFO : RTP_PRIO_REALTIME; 174 175 lp->lwp_rtprio = rtp; 176 need_user_resched(); 177 } else { 178 e = EINVAL; 179 } 180 break; 181 case SCHED_OTHER: 182 rtp.type = RTP_PRIO_NORMAL; 183 rtp.prio = p4prio_to_rtpprio(param->sched_priority); 184 lp->lwp_rtprio = rtp; 185 186 /* 187 * XXX Simply revert to whatever we had for last 188 * normal scheduler priorities. 189 * This puts a requirement 190 * on the scheduling code: You must leave the 191 * scheduling info alone. 192 */ 193 need_user_resched(); 194 break; 195 } 196 197 return e; 198 } 199 200 int 201 ksched_getscheduler(register_t *ret, struct ksched *ksched, struct lwp *lp) 202 { 203 return getscheduler(ret, ksched, lp); 204 } 205 206 /* 207 * ksched_yield: Yield the CPU. 208 * 209 * MPSAFE 210 */ 211 int 212 ksched_yield(register_t *ret, struct ksched *ksched) 213 { 214 struct lwp *lp; 215 216 if ((lp = curthread->td_lwp) != NULL) 217 lp->lwp_proc->p_usched->yield(lp); 218 return 0; 219 } 220 221 /* 222 * MPSAFE 223 */ 224 int 225 ksched_get_priority_max(register_t*ret, struct ksched *ksched, int policy) 226 { 227 int e = 0; 228 229 switch (policy) { 230 case SCHED_FIFO: 231 case SCHED_RR: 232 *ret = RTP_PRIO_MAX; 233 break; 234 case SCHED_OTHER: 235 *ret = PRIO_MAX; 236 break; 237 default: 238 e = EINVAL; 239 break; 240 } 241 242 return e; 243 } 244 245 /* 246 * MPSAFE 247 */ 248 int 249 ksched_get_priority_min(register_t *ret, struct ksched *ksched, int policy) 250 { 251 int e = 0; 252 253 switch (policy) { 254 case SCHED_FIFO: 255 case SCHED_RR: 256 *ret = P1B_PRIO_MIN; 257 break; 258 case SCHED_OTHER: 259 *ret = PRIO_MIN; 260 break; 261 default: 262 e = EINVAL; 263 break; 264 } 265 return e; 266 } 267 268 /* 269 * MPSAFE 270 */ 271 int 272 ksched_rr_get_interval(register_t *ret, struct ksched *ksched, 273 struct lwp *lp, struct timespec *timespec) 274 { 275 *timespec = ksched->rr_interval; 276 277 return 0; 278 } 279