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