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