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