xref: /freebsd/sys/kern/ksched.c (revision bec67fd3bbf5a430123b64e7b3bb24988f4c840a)
160727d8bSWarner Losh /*-
2917e476dSPeter Dufault  * Copyright (c) 1996, 1997
3917e476dSPeter Dufault  *	HD Associates, Inc.  All rights reserved.
4917e476dSPeter Dufault  *
5917e476dSPeter Dufault  * Redistribution and use in source and binary forms, with or without
6917e476dSPeter Dufault  * modification, are permitted provided that the following conditions
7917e476dSPeter Dufault  * are met:
8917e476dSPeter Dufault  * 1. Redistributions of source code must retain the above copyright
9917e476dSPeter Dufault  *    notice, this list of conditions and the following disclaimer.
10917e476dSPeter Dufault  * 2. Redistributions in binary form must reproduce the above copyright
11917e476dSPeter Dufault  *    notice, this list of conditions and the following disclaimer in the
12917e476dSPeter Dufault  *    documentation and/or other materials provided with the distribution.
13917e476dSPeter Dufault  * 3. All advertising materials mentioning features or use of this software
14917e476dSPeter Dufault  *    must display the following acknowledgement:
15917e476dSPeter Dufault  *	This product includes software developed by HD Associates, Inc
16917e476dSPeter Dufault  * 4. Neither the name of the author nor the names of any co-contributors
17917e476dSPeter Dufault  *    may be used to endorse or promote products derived from this software
18917e476dSPeter Dufault  *    without specific prior written permission.
19917e476dSPeter Dufault  *
20917e476dSPeter Dufault  * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND
21917e476dSPeter Dufault  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22917e476dSPeter Dufault  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23917e476dSPeter Dufault  * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
24917e476dSPeter Dufault  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25917e476dSPeter Dufault  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26917e476dSPeter Dufault  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27917e476dSPeter Dufault  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28917e476dSPeter Dufault  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29917e476dSPeter Dufault  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30917e476dSPeter Dufault  * SUCH DAMAGE.
31917e476dSPeter Dufault  */
32917e476dSPeter Dufault 
33917e476dSPeter Dufault /* ksched: Soft real time scheduling based on "rtprio".
34917e476dSPeter Dufault  */
35917e476dSPeter Dufault 
36f4636c59SDavid E. O'Brien #include <sys/cdefs.h>
37f4636c59SDavid E. O'Brien __FBSDID("$FreeBSD$");
38f4636c59SDavid E. O'Brien 
39b565fb9eSAlfred Perlstein #include "opt_posix.h"
40b565fb9eSAlfred Perlstein 
41917e476dSPeter Dufault #include <sys/param.h>
42917e476dSPeter Dufault #include <sys/systm.h>
43fb919e4dSMark Murray #include <sys/lock.h>
443a187295SJohn Baldwin #include <sys/mutex.h>
45fb919e4dSMark Murray #include <sys/proc.h>
46bdd04ab1STom Rhodes #include <sys/posix4.h>
4738c76440SPeter Dufault #include <sys/resource.h>
48b43179fbSJeff Roberson #include <sys/sched.h>
49917e476dSPeter Dufault 
50917e476dSPeter Dufault /* ksched: Real-time extension to support POSIX priority scheduling.
51917e476dSPeter Dufault  */
52917e476dSPeter Dufault 
538a6472b7SPeter Dufault struct ksched {
548a6472b7SPeter Dufault 	struct timespec rr_interval;
558a6472b7SPeter Dufault };
56917e476dSPeter Dufault 
57f6c040a2SDavid Xu int
58f6c040a2SDavid Xu ksched_attach(struct ksched **p)
59917e476dSPeter Dufault {
608a6472b7SPeter Dufault 	struct ksched *ksched= p31b_malloc(sizeof(*ksched));
61917e476dSPeter Dufault 
628a6472b7SPeter Dufault 	ksched->rr_interval.tv_sec = 0;
63b43179fbSJeff Roberson 	ksched->rr_interval.tv_nsec = 1000000000L / sched_rr_interval();
64917e476dSPeter Dufault 
658a6472b7SPeter Dufault 	*p = ksched;
66917e476dSPeter Dufault 	return 0;
67917e476dSPeter Dufault }
68917e476dSPeter Dufault 
69f6c040a2SDavid Xu int
70f6c040a2SDavid Xu ksched_detach(struct ksched *ks)
71917e476dSPeter Dufault {
72b40ce416SJulian Elischer 	p31b_free(ks);
738a6472b7SPeter Dufault 
74917e476dSPeter Dufault 	return 0;
75917e476dSPeter Dufault }
76917e476dSPeter Dufault 
77917e476dSPeter Dufault /*
78917e476dSPeter Dufault  * XXX About priorities
79917e476dSPeter Dufault  *
808a6472b7SPeter Dufault  *	POSIX 1003.1b requires that numerically higher priorities be of
81917e476dSPeter Dufault  *	higher priority.  It also permits sched_setparam to be
82917e476dSPeter Dufault  *	implementation defined for SCHED_OTHER.  I don't like
83917e476dSPeter Dufault  *	the notion of inverted priorites for normal processes when
84917e476dSPeter Dufault  *      you can use "setpriority" for that.
85917e476dSPeter Dufault  *
86917e476dSPeter Dufault  */
87917e476dSPeter Dufault 
88917e476dSPeter Dufault /* Macros to convert between the unix (lower numerically is higher priority)
898a6472b7SPeter Dufault  * and POSIX 1003.1b (higher numerically is higher priority)
90917e476dSPeter Dufault  */
91917e476dSPeter Dufault 
92917e476dSPeter Dufault #define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P))
93917e476dSPeter Dufault #define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P))
94917e476dSPeter Dufault 
95bec67fd3SRandall Stewart #define p4prio_to_tsprio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P))
96bec67fd3SRandall Stewart #define tsprio_to_p4prio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P))
97bec67fd3SRandall Stewart 
98aebde782SPeter Dufault /* These improve readability a bit for me:
99aebde782SPeter Dufault  */
100aebde782SPeter Dufault #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX)
101aebde782SPeter Dufault #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN)
102aebde782SPeter Dufault 
103c1087c13SBruce Evans static __inline int
10465343c78SDavid Xu getscheduler(struct ksched *ksched, struct thread *td, int *policy)
105917e476dSPeter Dufault {
106d5a08a60SJake Burkholder 	struct rtprio rtp;
107917e476dSPeter Dufault 	int e = 0;
108917e476dSPeter Dufault 
1098460a577SJohn Birrell 	pri_to_rtp(td, &rtp);
110d5a08a60SJake Burkholder 	switch (rtp.type)
111917e476dSPeter Dufault 	{
112917e476dSPeter Dufault 		case RTP_PRIO_FIFO:
11365343c78SDavid Xu 		*policy = SCHED_FIFO;
114917e476dSPeter Dufault 		break;
115917e476dSPeter Dufault 
116917e476dSPeter Dufault 		case RTP_PRIO_REALTIME:
11765343c78SDavid Xu 		*policy = SCHED_RR;
118917e476dSPeter Dufault 		break;
119917e476dSPeter Dufault 
120917e476dSPeter Dufault 		default:
12165343c78SDavid Xu 		*policy = SCHED_OTHER;
122917e476dSPeter Dufault 		break;
123917e476dSPeter Dufault 	}
124917e476dSPeter Dufault 
125917e476dSPeter Dufault 	return e;
126917e476dSPeter Dufault }
127917e476dSPeter Dufault 
128f6c040a2SDavid Xu int
12965343c78SDavid Xu ksched_setparam(struct ksched *ksched,
130b40ce416SJulian Elischer     struct thread *td, const struct sched_param *param)
131917e476dSPeter Dufault {
13265343c78SDavid Xu 	int policy;
1339f79feecSBruce Evans 	int e;
134917e476dSPeter Dufault 
13565343c78SDavid Xu 	e = getscheduler(ksched, td, &policy);
136917e476dSPeter Dufault 
137917e476dSPeter Dufault 	if (e == 0)
138917e476dSPeter Dufault 	{
13965343c78SDavid Xu 			e = ksched_setscheduler(ksched, td, policy, param);
140917e476dSPeter Dufault 	}
141917e476dSPeter Dufault 
142917e476dSPeter Dufault 	return e;
143917e476dSPeter Dufault }
144917e476dSPeter Dufault 
145f6c040a2SDavid Xu int
14665343c78SDavid Xu ksched_getparam(struct ksched *ksched,
147b40ce416SJulian Elischer     struct thread *td, struct sched_param *param)
148917e476dSPeter Dufault {
149d5a08a60SJake Burkholder 	struct rtprio rtp;
150d5a08a60SJake Burkholder 
1518460a577SJohn Birrell 	pri_to_rtp(td, &rtp);
152d5a08a60SJake Burkholder 	if (RTP_PRIO_IS_REALTIME(rtp.type))
153d5a08a60SJake Burkholder 		param->sched_priority = rtpprio_to_p4prio(rtp.prio);
154bec67fd3SRandall Stewart 	else {
155bec67fd3SRandall Stewart 		if (PRI_MIN_TIMESHARE < rtp.prio)
156bec67fd3SRandall Stewart 			/*
157bec67fd3SRandall Stewart 		 	 * The interactive score has it to min realtime
158bec67fd3SRandall Stewart 			 * so we must show max (64 most likely
159bec67fd3SRandall Stewart 			 */
160bec67fd3SRandall Stewart 			param->sched_priority = (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE);
161bec67fd3SRandall Stewart 		else
162bec67fd3SRandall Stewart 			param->sched_priority = tsprio_to_p4prio(rtp.prio);
163bec67fd3SRandall Stewart 	}
164917e476dSPeter Dufault 	return 0;
165917e476dSPeter Dufault }
166917e476dSPeter Dufault 
167917e476dSPeter Dufault /*
168917e476dSPeter Dufault  * XXX The priority and scheduler modifications should
169917e476dSPeter Dufault  *     be moved into published interfaces in kern/kern_sync.
170917e476dSPeter Dufault  *
1718a6472b7SPeter Dufault  * The permissions to modify process p were checked in "p31b_proc()".
172917e476dSPeter Dufault  *
173917e476dSPeter Dufault  */
174f6c040a2SDavid Xu int
17565343c78SDavid Xu ksched_setscheduler(struct ksched *ksched,
176b40ce416SJulian Elischer     struct thread *td, int policy, const struct sched_param *param)
177917e476dSPeter Dufault {
178917e476dSPeter Dufault 	int e = 0;
179917e476dSPeter Dufault 	struct rtprio rtp;
180917e476dSPeter Dufault 
181917e476dSPeter Dufault 	switch(policy)
182917e476dSPeter Dufault 	{
183917e476dSPeter Dufault 		case SCHED_RR:
184917e476dSPeter Dufault 		case SCHED_FIFO:
185917e476dSPeter Dufault 
186aebde782SPeter Dufault 		if (param->sched_priority >= P1B_PRIO_MIN &&
187aebde782SPeter Dufault 		    param->sched_priority <= P1B_PRIO_MAX)
188917e476dSPeter Dufault 		{
189aebde782SPeter Dufault 			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
190917e476dSPeter Dufault 			rtp.type = (policy == SCHED_FIFO)
191917e476dSPeter Dufault 				? RTP_PRIO_FIFO : RTP_PRIO_REALTIME;
192917e476dSPeter Dufault 
1938460a577SJohn Birrell 			rtp_to_pri(&rtp, td);
194917e476dSPeter Dufault 		}
195917e476dSPeter Dufault 		else
196917e476dSPeter Dufault 			e = EPERM;
197917e476dSPeter Dufault 
198917e476dSPeter Dufault 
199917e476dSPeter Dufault 		break;
200917e476dSPeter Dufault 
201917e476dSPeter Dufault 		case SCHED_OTHER:
202bec67fd3SRandall Stewart 		if (param->sched_priority >= 0 &&
203bec67fd3SRandall Stewart 			param->sched_priority <= (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) {
204917e476dSPeter Dufault 			rtp.type = RTP_PRIO_NORMAL;
2052a61a110SPeter Dufault 			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
2068460a577SJohn Birrell 			rtp_to_pri(&rtp, td);
207bec67fd3SRandall Stewart 		} else
208bec67fd3SRandall Stewart 			e = EINVAL;
209bec67fd3SRandall Stewart 
210917e476dSPeter Dufault 		break;
2115949ba21SJacques Vidrine 
2125949ba21SJacques Vidrine 		default:
2135949ba21SJacques Vidrine 			e = EINVAL;
2145949ba21SJacques Vidrine 			break;
215917e476dSPeter Dufault 	}
216917e476dSPeter Dufault 
217917e476dSPeter Dufault 	return e;
218917e476dSPeter Dufault }
219917e476dSPeter Dufault 
220f6c040a2SDavid Xu int
22165343c78SDavid Xu ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy)
222917e476dSPeter Dufault {
22365343c78SDavid Xu 	return getscheduler(ksched, td, policy);
224917e476dSPeter Dufault }
225917e476dSPeter Dufault 
226917e476dSPeter Dufault /* ksched_yield: Yield the CPU.
227917e476dSPeter Dufault  */
228f6c040a2SDavid Xu int
22965343c78SDavid Xu ksched_yield(struct ksched *ksched)
230917e476dSPeter Dufault {
23136ec198bSDavid Xu 	sched_relinquish(curthread);
232917e476dSPeter Dufault 	return 0;
233917e476dSPeter Dufault }
234917e476dSPeter Dufault 
235f6c040a2SDavid Xu int
23665343c78SDavid Xu ksched_get_priority_max(struct ksched *ksched, int policy, int *prio)
237917e476dSPeter Dufault {
238917e476dSPeter Dufault 	int e = 0;
239917e476dSPeter Dufault 
240917e476dSPeter Dufault 	switch (policy)
241917e476dSPeter Dufault 	{
242917e476dSPeter Dufault 		case SCHED_FIFO:
243917e476dSPeter Dufault 		case SCHED_RR:
24465343c78SDavid Xu 		*prio = RTP_PRIO_MAX;
245917e476dSPeter Dufault 		break;
246917e476dSPeter Dufault 
247917e476dSPeter Dufault 		case SCHED_OTHER:
248c3ab507fSDavid Xu 		*prio = PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE;
249917e476dSPeter Dufault 		break;
250917e476dSPeter Dufault 
251917e476dSPeter Dufault 		default:
252917e476dSPeter Dufault 		e = EINVAL;
253917e476dSPeter Dufault 	}
254917e476dSPeter Dufault 
255917e476dSPeter Dufault 	return e;
256917e476dSPeter Dufault }
257917e476dSPeter Dufault 
258f6c040a2SDavid Xu int
25965343c78SDavid Xu ksched_get_priority_min(struct ksched *ksched, int policy, int *prio)
260917e476dSPeter Dufault {
261917e476dSPeter Dufault 	int e = 0;
262917e476dSPeter Dufault 
263917e476dSPeter Dufault 	switch (policy)
264917e476dSPeter Dufault 	{
265917e476dSPeter Dufault 		case SCHED_FIFO:
266917e476dSPeter Dufault 		case SCHED_RR:
26765343c78SDavid Xu 		*prio = P1B_PRIO_MIN;
268917e476dSPeter Dufault 		break;
269917e476dSPeter Dufault 
270917e476dSPeter Dufault 		case SCHED_OTHER:
271c3ab507fSDavid Xu 		*prio = 0;
272917e476dSPeter Dufault 		break;
273917e476dSPeter Dufault 
274917e476dSPeter Dufault 		default:
275917e476dSPeter Dufault 		e = EINVAL;
276917e476dSPeter Dufault 	}
277917e476dSPeter Dufault 
278917e476dSPeter Dufault 	return e;
279917e476dSPeter Dufault }
280917e476dSPeter Dufault 
281f6c040a2SDavid Xu int
28265343c78SDavid Xu ksched_rr_get_interval(struct ksched *ksched,
283b40ce416SJulian Elischer    struct thread *td, struct timespec *timespec)
284917e476dSPeter Dufault {
2858a6472b7SPeter Dufault 	*timespec = ksched->rr_interval;
286917e476dSPeter Dufault 
287917e476dSPeter Dufault 	return 0;
288917e476dSPeter Dufault }
289