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