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$ 33 */ 34 35 /* ksched: Soft real time scheduling based on "rtprio". 36 */ 37 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/proc.h> 41 #include <sys/mutex.h> 42 #include <sys/resource.h> 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(register_t *ret, struct ksched *ksched, struct proc *p) 97 { 98 struct rtprio rtp; 99 int e = 0; 100 101 pri_to_rtp(&p->p_pri, &rtp); 102 switch (rtp.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 proc *p, const struct sched_param *param) 122 { 123 register_t policy; 124 int e; 125 126 e = getscheduler(&policy, ksched, p); 127 128 if (e == 0) 129 { 130 if (policy == SCHED_OTHER) 131 e = EINVAL; 132 else 133 e = ksched_setscheduler(ret, ksched, p, policy, param); 134 } 135 136 return e; 137 } 138 139 int ksched_getparam(register_t *ret, struct ksched *ksched, 140 struct proc *p, struct sched_param *param) 141 { 142 struct rtprio rtp; 143 144 pri_to_rtp(&p->p_pri, &rtp); 145 if (RTP_PRIO_IS_REALTIME(rtp.type)) 146 param->sched_priority = rtpprio_to_p4prio(rtp.prio); 147 148 return 0; 149 } 150 151 /* 152 * XXX The priority and scheduler modifications should 153 * be moved into published interfaces in kern/kern_sync. 154 * 155 * The permissions to modify process p were checked in "p31b_proc()". 156 * 157 */ 158 int ksched_setscheduler(register_t *ret, struct ksched *ksched, 159 struct proc *p, int policy, const struct sched_param *param) 160 { 161 int e = 0; 162 struct rtprio rtp; 163 164 switch(policy) 165 { 166 case SCHED_RR: 167 case SCHED_FIFO: 168 169 if (param->sched_priority >= P1B_PRIO_MIN && 170 param->sched_priority <= P1B_PRIO_MAX) 171 { 172 rtp.prio = p4prio_to_rtpprio(param->sched_priority); 173 rtp.type = (policy == SCHED_FIFO) 174 ? RTP_PRIO_FIFO : RTP_PRIO_REALTIME; 175 176 mtx_lock_spin(&sched_lock); 177 rtp_to_pri(&rtp, &p->p_pri); 178 need_resched(); 179 mtx_unlock_spin(&sched_lock); 180 } 181 else 182 e = EPERM; 183 184 185 break; 186 187 case SCHED_OTHER: 188 { 189 rtp.type = RTP_PRIO_NORMAL; 190 rtp.prio = p4prio_to_rtpprio(param->sched_priority); 191 mtx_lock_spin(&sched_lock); 192 rtp_to_pri(&rtp, &p->p_pri); 193 194 /* XXX Simply revert to whatever we had for last 195 * normal scheduler priorities. 196 * This puts a requirement 197 * on the scheduling code: You must leave the 198 * scheduling info alone. 199 */ 200 need_resched(); 201 mtx_unlock_spin(&sched_lock); 202 } 203 break; 204 } 205 206 return e; 207 } 208 209 int ksched_getscheduler(register_t *ret, struct ksched *ksched, struct proc *p) 210 { 211 return getscheduler(ret, ksched, p); 212 } 213 214 /* ksched_yield: Yield the CPU. 215 */ 216 int ksched_yield(register_t *ret, struct ksched *ksched) 217 { 218 mtx_lock_spin(&sched_lock); 219 need_resched(); 220 mtx_unlock_spin(&sched_lock); 221 return 0; 222 } 223 224 int ksched_get_priority_max(register_t*ret, struct ksched *ksched, int policy) 225 { 226 int e = 0; 227 228 switch (policy) 229 { 230 case SCHED_FIFO: 231 case SCHED_RR: 232 *ret = RTP_PRIO_MAX; 233 break; 234 235 case SCHED_OTHER: 236 *ret = PRIO_MAX; 237 break; 238 239 default: 240 e = EINVAL; 241 } 242 243 return e; 244 } 245 246 int ksched_get_priority_min(register_t *ret, struct ksched *ksched, int policy) 247 { 248 int e = 0; 249 250 switch (policy) 251 { 252 case SCHED_FIFO: 253 case SCHED_RR: 254 *ret = P1B_PRIO_MIN; 255 break; 256 257 case SCHED_OTHER: 258 *ret = PRIO_MIN; 259 break; 260 261 default: 262 e = EINVAL; 263 } 264 265 return e; 266 } 267 268 int ksched_rr_get_interval(register_t *ret, struct ksched *ksched, 269 struct proc *p, struct timespec *timespec) 270 { 271 *timespec = ksched->rr_interval; 272 273 return 0; 274 } 275