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