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