1139825Simp/*- 234030Sdufault * Copyright (c) 1996, 1997 334030Sdufault * HD Associates, Inc. All rights reserved. 434030Sdufault * 534030Sdufault * Redistribution and use in source and binary forms, with or without 634030Sdufault * modification, are permitted provided that the following conditions 734030Sdufault * are met: 834030Sdufault * 1. Redistributions of source code must retain the above copyright 934030Sdufault * notice, this list of conditions and the following disclaimer. 1034030Sdufault * 2. Redistributions in binary form must reproduce the above copyright 1134030Sdufault * notice, this list of conditions and the following disclaimer in the 1234030Sdufault * documentation and/or other materials provided with the distribution. 1334030Sdufault * 3. All advertising materials mentioning features or use of this software 1434030Sdufault * must display the following acknowledgement: 1534030Sdufault * This product includes software developed by HD Associates, Inc 1634030Sdufault * 4. Neither the name of the author nor the names of any co-contributors 1734030Sdufault * may be used to endorse or promote products derived from this software 1834030Sdufault * without specific prior written permission. 1934030Sdufault * 2034030Sdufault * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND 2134030Sdufault * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2234030Sdufault * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2334030Sdufault * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE 2434030Sdufault * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2534030Sdufault * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2634030Sdufault * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2734030Sdufault * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2834030Sdufault * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2934030Sdufault * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3034030Sdufault * SUCH DAMAGE. 3134030Sdufault */ 3234030Sdufault 33287507Skib/* ksched: Soft real time scheduling based on "rtprio". */ 3434030Sdufault 35116192Sobrien#include <sys/cdefs.h> 36116192Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/kern/ksched.c 287508 2015-09-06 17:36:09Z kib $"); 37116192Sobrien 38106969Salfred#include "opt_posix.h" 39106969Salfred 4034030Sdufault#include <sys/param.h> 4134030Sdufault#include <sys/systm.h> 4276166Smarkm#include <sys/lock.h> 43219028Snetchild#include <sys/sysctl.h> 44219028Snetchild#include <sys/kernel.h> 4576166Smarkm#include <sys/mutex.h> 4634030Sdufault#include <sys/proc.h> 47164183Strhodes#include <sys/posix4.h> 4834929Sdufault#include <sys/resource.h> 49104964Sjeff#include <sys/sched.h> 5034030Sdufault 51219028SnetchildFEATURE(kposix_priority_scheduling, "POSIX P1003.1B realtime extensions"); 52219028Snetchild 53287507Skib/* ksched: Real-time extension to support POSIX priority scheduling. */ 5434030Sdufault 5534925Sdufaultstruct ksched { 5634925Sdufault struct timespec rr_interval; 5734925Sdufault}; 5834030Sdufault 59158745Sdavidxuint 60158745Sdavidxuksched_attach(struct ksched **p) 6134030Sdufault{ 62287507Skib struct ksched *ksched; 6334030Sdufault 64287507Skib ksched = malloc(sizeof(*ksched), M_P31B, M_WAITOK); 6534925Sdufault ksched->rr_interval.tv_sec = 0; 66239183Smav ksched->rr_interval.tv_nsec = 1000000000L / hz * sched_rr_interval(); 6734925Sdufault *p = ksched; 68287507Skib return (0); 6934030Sdufault} 7034030Sdufault 71158745Sdavidxuint 72158745Sdavidxuksched_detach(struct ksched *ks) 7334030Sdufault{ 7434925Sdufault 75287507Skib free(ks, M_P31B); 76287507Skib return (0); 7734030Sdufault} 7834030Sdufault 7934030Sdufault/* 8034030Sdufault * XXX About priorities 8134030Sdufault * 8234925Sdufault * POSIX 1003.1b requires that numerically higher priorities be of 8334030Sdufault * higher priority. It also permits sched_setparam to be 8434030Sdufault * implementation defined for SCHED_OTHER. I don't like 8534030Sdufault * the notion of inverted priorites for normal processes when 86204670Srrs * you can use "setpriority" for that. 8734030Sdufault * 8834030Sdufault */ 8934030Sdufault 9034030Sdufault/* Macros to convert between the unix (lower numerically is higher priority) 9134925Sdufault * and POSIX 1003.1b (higher numerically is higher priority) 9234030Sdufault */ 9334030Sdufault 9434030Sdufault#define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P)) 9534030Sdufault#define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P)) 9634030Sdufault 97204670Srrs#define p4prio_to_tsprio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P)) 98204670Srrs#define tsprio_to_p4prio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P)) 99204670Srrs 10036218Sdufault/* These improve readability a bit for me: 10136218Sdufault */ 10236218Sdufault#define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX) 10336218Sdufault#define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN) 10436218Sdufault 10535210Sbdestatic __inline int 106160257Sdavidxugetscheduler(struct ksched *ksched, struct thread *td, int *policy) 10734030Sdufault{ 10872376Sjake struct rtprio rtp; 109287507Skib int e; 11034030Sdufault 111287507Skib e = 0; 112163709Sjb pri_to_rtp(td, &rtp); 113287507Skib switch (rtp.type) { 114287507Skib case RTP_PRIO_FIFO: 115160257Sdavidxu *policy = SCHED_FIFO; 11634030Sdufault break; 117287507Skib case RTP_PRIO_REALTIME: 118160257Sdavidxu *policy = SCHED_RR; 11934030Sdufault break; 120287507Skib default: 121160257Sdavidxu *policy = SCHED_OTHER; 12234030Sdufault break; 12334030Sdufault } 124287507Skib return (e); 12534030Sdufault} 12634030Sdufault 127158745Sdavidxuint 128160257Sdavidxuksched_setparam(struct ksched *ksched, 129158745Sdavidxu struct thread *td, const struct sched_param *param) 13034030Sdufault{ 131287507Skib int e, policy; 13234030Sdufault 133160257Sdavidxu e = getscheduler(ksched, td, &policy); 13434030Sdufault if (e == 0) 135287507Skib e = ksched_setscheduler(ksched, td, policy, param); 136287507Skib return (e); 13734030Sdufault} 13834030Sdufault 139158745Sdavidxuint 140287507Skibksched_getparam(struct ksched *ksched, struct thread *td, 141287507Skib struct sched_param *param) 14234030Sdufault{ 14372376Sjake struct rtprio rtp; 14434030Sdufault 145163709Sjb pri_to_rtp(td, &rtp); 14672376Sjake if (RTP_PRIO_IS_REALTIME(rtp.type)) 14772376Sjake param->sched_priority = rtpprio_to_p4prio(rtp.prio); 148204670Srrs else { 149204670Srrs if (PRI_MIN_TIMESHARE < rtp.prio) 150204670Srrs /* 151204670Srrs * The interactive score has it to min realtime 152287507Skib * so we must show max (64 most likely). 153204670Srrs */ 154287507Skib param->sched_priority = PRI_MAX_TIMESHARE - 155287507Skib PRI_MIN_TIMESHARE; 156204670Srrs else 157204670Srrs param->sched_priority = tsprio_to_p4prio(rtp.prio); 158204670Srrs } 159287507Skib return (0); 16034030Sdufault} 16134030Sdufault 16234030Sdufault/* 16334030Sdufault * XXX The priority and scheduler modifications should 16434030Sdufault * be moved into published interfaces in kern/kern_sync. 16534030Sdufault * 16634925Sdufault * The permissions to modify process p were checked in "p31b_proc()". 16734030Sdufault * 16834030Sdufault */ 169158745Sdavidxuint 170287507Skibksched_setscheduler(struct ksched *ksched, struct thread *td, int policy, 171287507Skib const struct sched_param *param) 17234030Sdufault{ 17334030Sdufault struct rtprio rtp; 174287507Skib int e; 17534030Sdufault 176287507Skib e = 0; 177287507Skib switch(policy) { 178287507Skib case SCHED_RR: 179287507Skib case SCHED_FIFO: 18036218Sdufault if (param->sched_priority >= P1B_PRIO_MIN && 181287507Skib param->sched_priority <= P1B_PRIO_MAX) { 18236218Sdufault rtp.prio = p4prio_to_rtpprio(param->sched_priority); 183287507Skib rtp.type = (policy == SCHED_FIFO) ? RTP_PRIO_FIFO : 184287507Skib RTP_PRIO_REALTIME; 185163709Sjb rtp_to_pri(&rtp, td); 186287507Skib } else { 187287507Skib e = EPERM; 18834030Sdufault } 18934030Sdufault break; 190287507Skib case SCHED_OTHER: 191287507Skib if (param->sched_priority >= 0 && param->sched_priority <= 192287507Skib (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) { 19334030Sdufault rtp.type = RTP_PRIO_NORMAL; 194222802Sdavidxu rtp.prio = p4prio_to_tsprio(param->sched_priority); 195163709Sjb rtp_to_pri(&rtp, td); 196287507Skib } else { 197204670Srrs e = EINVAL; 198287507Skib } 19934030Sdufault break; 200287507Skib default: 201287507Skib e = EINVAL; 202287507Skib break; 20334030Sdufault } 204287507Skib return (e); 20534030Sdufault} 20634030Sdufault 207158745Sdavidxuint 208160257Sdavidxuksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy) 20934030Sdufault{ 210287507Skib 211287507Skib return (getscheduler(ksched, td, policy)); 21234030Sdufault} 21334030Sdufault 214287507Skib/* ksched_yield: Yield the CPU. */ 215158745Sdavidxuint 216160257Sdavidxuksched_yield(struct ksched *ksched) 21734030Sdufault{ 218287507Skib 219159630Sdavidxu sched_relinquish(curthread); 220287507Skib return (0); 22134030Sdufault} 22234030Sdufault 223158745Sdavidxuint 224160257Sdavidxuksched_get_priority_max(struct ksched *ksched, int policy, int *prio) 22534030Sdufault{ 226287507Skib int e; 22734030Sdufault 228287507Skib e = 0; 229287507Skib switch (policy) { 230287507Skib case SCHED_FIFO: 231287507Skib case SCHED_RR: 232287508Skib *prio = P1B_PRIO_MAX; 23334030Sdufault break; 234287507Skib case SCHED_OTHER: 235160285Sdavidxu *prio = PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE; 23634030Sdufault break; 237287507Skib default: 23834030Sdufault e = EINVAL; 239287507Skib break; 24034030Sdufault } 241287507Skib return (e); 24234030Sdufault} 24334030Sdufault 244158745Sdavidxuint 245160257Sdavidxuksched_get_priority_min(struct ksched *ksched, int policy, int *prio) 24634030Sdufault{ 247287507Skib int e; 24834030Sdufault 249287507Skib e = 0; 250287507Skib switch (policy) { 251287507Skib case SCHED_FIFO: 252287507Skib case SCHED_RR: 253160257Sdavidxu *prio = P1B_PRIO_MIN; 25434030Sdufault break; 255287507Skib case SCHED_OTHER: 256160285Sdavidxu *prio = 0; 25734030Sdufault break; 258287507Skib default: 25934030Sdufault e = EINVAL; 260287507Skib break; 26134030Sdufault } 262287507Skib return (e); 26334030Sdufault} 26434030Sdufault 265158745Sdavidxuint 266287507Skibksched_rr_get_interval(struct ksched *ksched, struct thread *td, 267287507Skib struct timespec *timespec) 26834030Sdufault{ 269287507Skib 27034925Sdufault *timespec = ksched->rr_interval; 271287507Skib return (0); 27234030Sdufault} 273