xref: /freebsd/sys/kern/ksched.c (revision df57947f083046d50552e99b91074927d2458708)
160727d8bSWarner Losh /*-
2*df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
3*df57947fSPedro F. Giffuni  *
4917e476dSPeter Dufault  * Copyright (c) 1996, 1997
5917e476dSPeter Dufault  *	HD Associates, Inc.  All rights reserved.
6917e476dSPeter Dufault  *
7917e476dSPeter Dufault  * Redistribution and use in source and binary forms, with or without
8917e476dSPeter Dufault  * modification, are permitted provided that the following conditions
9917e476dSPeter Dufault  * are met:
10917e476dSPeter Dufault  * 1. Redistributions of source code must retain the above copyright
11917e476dSPeter Dufault  *    notice, this list of conditions and the following disclaimer.
12917e476dSPeter Dufault  * 2. Redistributions in binary form must reproduce the above copyright
13917e476dSPeter Dufault  *    notice, this list of conditions and the following disclaimer in the
14917e476dSPeter Dufault  *    documentation and/or other materials provided with the distribution.
15917e476dSPeter Dufault  * 3. All advertising materials mentioning features or use of this software
16917e476dSPeter Dufault  *    must display the following acknowledgement:
17917e476dSPeter Dufault  *	This product includes software developed by HD Associates, Inc
18917e476dSPeter Dufault  * 4. Neither the name of the author nor the names of any co-contributors
19917e476dSPeter Dufault  *    may be used to endorse or promote products derived from this software
20917e476dSPeter Dufault  *    without specific prior written permission.
21917e476dSPeter Dufault  *
22917e476dSPeter Dufault  * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND
23917e476dSPeter Dufault  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24917e476dSPeter Dufault  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25917e476dSPeter Dufault  * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
26917e476dSPeter Dufault  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27917e476dSPeter Dufault  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28917e476dSPeter Dufault  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29917e476dSPeter Dufault  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30917e476dSPeter Dufault  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31917e476dSPeter Dufault  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32917e476dSPeter Dufault  * SUCH DAMAGE.
33917e476dSPeter Dufault  */
34917e476dSPeter Dufault 
3544e629f1SKonstantin Belousov /* ksched: Soft real time scheduling based on "rtprio". */
36917e476dSPeter Dufault 
37f4636c59SDavid E. O'Brien #include <sys/cdefs.h>
38f4636c59SDavid E. O'Brien __FBSDID("$FreeBSD$");
39f4636c59SDavid E. O'Brien 
40b565fb9eSAlfred Perlstein #include "opt_posix.h"
41b565fb9eSAlfred Perlstein 
42917e476dSPeter Dufault #include <sys/param.h>
43917e476dSPeter Dufault #include <sys/systm.h>
44fb919e4dSMark Murray #include <sys/lock.h>
45de5b1952SAlexander Leidinger #include <sys/sysctl.h>
46de5b1952SAlexander Leidinger #include <sys/kernel.h>
473a187295SJohn Baldwin #include <sys/mutex.h>
48fb919e4dSMark Murray #include <sys/proc.h>
49bdd04ab1STom Rhodes #include <sys/posix4.h>
5038c76440SPeter Dufault #include <sys/resource.h>
51b43179fbSJeff Roberson #include <sys/sched.h>
52917e476dSPeter Dufault 
53de5b1952SAlexander Leidinger FEATURE(kposix_priority_scheduling, "POSIX P1003.1B realtime extensions");
54de5b1952SAlexander Leidinger 
5544e629f1SKonstantin Belousov /* ksched: Real-time extension to support POSIX priority scheduling. */
56917e476dSPeter Dufault 
578a6472b7SPeter Dufault struct ksched {
588a6472b7SPeter Dufault 	struct timespec rr_interval;
598a6472b7SPeter Dufault };
60917e476dSPeter Dufault 
61f6c040a2SDavid Xu int
62f6c040a2SDavid Xu ksched_attach(struct ksched **p)
63917e476dSPeter Dufault {
6444e629f1SKonstantin Belousov 	struct ksched *ksched;
65917e476dSPeter Dufault 
6644e629f1SKonstantin Belousov 	ksched = malloc(sizeof(*ksched), M_P31B, M_WAITOK);
678a6472b7SPeter Dufault 	ksched->rr_interval.tv_sec = 0;
689000aabfSAlexander Motin 	ksched->rr_interval.tv_nsec = 1000000000L / hz * sched_rr_interval();
698a6472b7SPeter Dufault 	*p = ksched;
7044e629f1SKonstantin Belousov 	return (0);
71917e476dSPeter Dufault }
72917e476dSPeter Dufault 
73f6c040a2SDavid Xu int
74f6c040a2SDavid Xu ksched_detach(struct ksched *ks)
75917e476dSPeter Dufault {
768a6472b7SPeter Dufault 
7744e629f1SKonstantin Belousov 	free(ks, M_P31B);
7844e629f1SKonstantin Belousov 	return (0);
79917e476dSPeter Dufault }
80917e476dSPeter Dufault 
81917e476dSPeter Dufault /*
82917e476dSPeter Dufault  * XXX About priorities
83917e476dSPeter Dufault  *
848a6472b7SPeter Dufault  *	POSIX 1003.1b requires that numerically higher priorities be of
85917e476dSPeter Dufault  *	higher priority.  It also permits sched_setparam to be
86917e476dSPeter Dufault  *	implementation defined for SCHED_OTHER.  I don't like
87917e476dSPeter Dufault  *	the notion of inverted priorites for normal processes when
88917e476dSPeter Dufault  *      you can use "setpriority" for that.
89917e476dSPeter Dufault  *
90917e476dSPeter Dufault  */
91917e476dSPeter Dufault 
92917e476dSPeter Dufault /* Macros to convert between the unix (lower numerically is higher priority)
938a6472b7SPeter Dufault  * and POSIX 1003.1b (higher numerically is higher priority)
94917e476dSPeter Dufault  */
95917e476dSPeter Dufault 
96917e476dSPeter Dufault #define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P))
97917e476dSPeter Dufault #define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P))
98917e476dSPeter Dufault 
99bec67fd3SRandall Stewart #define p4prio_to_tsprio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P))
100bec67fd3SRandall Stewart #define tsprio_to_p4prio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P))
101bec67fd3SRandall Stewart 
102aebde782SPeter Dufault /* These improve readability a bit for me:
103aebde782SPeter Dufault  */
104aebde782SPeter Dufault #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX)
105aebde782SPeter Dufault #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN)
106aebde782SPeter Dufault 
107c1087c13SBruce Evans static __inline int
10865343c78SDavid Xu getscheduler(struct ksched *ksched, struct thread *td, int *policy)
109917e476dSPeter Dufault {
110d5a08a60SJake Burkholder 	struct rtprio rtp;
11144e629f1SKonstantin Belousov 	int e;
112917e476dSPeter Dufault 
11344e629f1SKonstantin Belousov 	e = 0;
1148460a577SJohn Birrell 	pri_to_rtp(td, &rtp);
11544e629f1SKonstantin Belousov 	switch (rtp.type) {
116917e476dSPeter Dufault 	case RTP_PRIO_FIFO:
11765343c78SDavid Xu 		*policy = SCHED_FIFO;
118917e476dSPeter Dufault 		break;
119917e476dSPeter Dufault 	case RTP_PRIO_REALTIME:
12065343c78SDavid Xu 		*policy = SCHED_RR;
121917e476dSPeter Dufault 		break;
122917e476dSPeter Dufault 	default:
12365343c78SDavid Xu 		*policy = SCHED_OTHER;
124917e476dSPeter Dufault 		break;
125917e476dSPeter Dufault 	}
12644e629f1SKonstantin Belousov 	return (e);
127917e476dSPeter Dufault }
128917e476dSPeter Dufault 
129f6c040a2SDavid Xu int
13065343c78SDavid Xu ksched_setparam(struct ksched *ksched,
131b40ce416SJulian Elischer     struct thread *td, const struct sched_param *param)
132917e476dSPeter Dufault {
13344e629f1SKonstantin Belousov 	int e, policy;
134917e476dSPeter Dufault 
13565343c78SDavid Xu 	e = getscheduler(ksched, td, &policy);
136917e476dSPeter Dufault 	if (e == 0)
13765343c78SDavid Xu 		e = ksched_setscheduler(ksched, td, policy, param);
13844e629f1SKonstantin Belousov 	return (e);
139917e476dSPeter Dufault }
140917e476dSPeter Dufault 
141f6c040a2SDavid Xu int
14244e629f1SKonstantin Belousov ksched_getparam(struct ksched *ksched, struct thread *td,
14344e629f1SKonstantin Belousov     struct sched_param *param)
144917e476dSPeter Dufault {
145d5a08a60SJake Burkholder 	struct rtprio rtp;
146d5a08a60SJake Burkholder 
1478460a577SJohn Birrell 	pri_to_rtp(td, &rtp);
148d5a08a60SJake Burkholder 	if (RTP_PRIO_IS_REALTIME(rtp.type))
149d5a08a60SJake Burkholder 		param->sched_priority = rtpprio_to_p4prio(rtp.prio);
150bec67fd3SRandall Stewart 	else {
151bec67fd3SRandall Stewart 		if (PRI_MIN_TIMESHARE < rtp.prio)
152bec67fd3SRandall Stewart 			/*
153bec67fd3SRandall Stewart 		 	 * The interactive score has it to min realtime
15444e629f1SKonstantin Belousov 			 * so we must show max (64 most likely).
155bec67fd3SRandall Stewart 			 */
15644e629f1SKonstantin Belousov 			param->sched_priority = PRI_MAX_TIMESHARE -
15744e629f1SKonstantin Belousov 			    PRI_MIN_TIMESHARE;
158bec67fd3SRandall Stewart 		else
159bec67fd3SRandall Stewart 			param->sched_priority = tsprio_to_p4prio(rtp.prio);
160bec67fd3SRandall Stewart 	}
16144e629f1SKonstantin Belousov 	return (0);
162917e476dSPeter Dufault }
163917e476dSPeter Dufault 
164917e476dSPeter Dufault /*
165917e476dSPeter Dufault  * XXX The priority and scheduler modifications should
166917e476dSPeter Dufault  *     be moved into published interfaces in kern/kern_sync.
167917e476dSPeter Dufault  *
1688a6472b7SPeter Dufault  * The permissions to modify process p were checked in "p31b_proc()".
169917e476dSPeter Dufault  *
170917e476dSPeter Dufault  */
171f6c040a2SDavid Xu int
17244e629f1SKonstantin Belousov ksched_setscheduler(struct ksched *ksched, struct thread *td, int policy,
17344e629f1SKonstantin Belousov     const struct sched_param *param)
174917e476dSPeter Dufault {
175917e476dSPeter Dufault 	struct rtprio rtp;
17644e629f1SKonstantin Belousov 	int e;
177917e476dSPeter Dufault 
17844e629f1SKonstantin Belousov 	e = 0;
17944e629f1SKonstantin Belousov 	switch(policy) {
180917e476dSPeter Dufault 	case SCHED_RR:
181917e476dSPeter Dufault 	case SCHED_FIFO:
182aebde782SPeter Dufault 		if (param->sched_priority >= P1B_PRIO_MIN &&
18344e629f1SKonstantin Belousov 		    param->sched_priority <= P1B_PRIO_MAX) {
184aebde782SPeter Dufault 			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
18544e629f1SKonstantin Belousov 			rtp.type = (policy == SCHED_FIFO) ? RTP_PRIO_FIFO :
18644e629f1SKonstantin Belousov 			    RTP_PRIO_REALTIME;
1878460a577SJohn Birrell 			rtp_to_pri(&rtp, td);
18844e629f1SKonstantin Belousov 		} else {
189917e476dSPeter Dufault 			e = EPERM;
19044e629f1SKonstantin Belousov 		}
191917e476dSPeter Dufault 		break;
192917e476dSPeter Dufault 	case SCHED_OTHER:
19344e629f1SKonstantin Belousov 		if (param->sched_priority >= 0 && param->sched_priority <=
19444e629f1SKonstantin Belousov 		    (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) {
195917e476dSPeter Dufault 			rtp.type = RTP_PRIO_NORMAL;
196a2311449SDavid Xu 			rtp.prio = p4prio_to_tsprio(param->sched_priority);
1978460a577SJohn Birrell 			rtp_to_pri(&rtp, td);
19844e629f1SKonstantin Belousov 		} else {
199bec67fd3SRandall Stewart 			e = EINVAL;
20044e629f1SKonstantin Belousov 		}
201917e476dSPeter Dufault 		break;
2025949ba21SJacques Vidrine 	default:
2035949ba21SJacques Vidrine 		e = EINVAL;
2045949ba21SJacques Vidrine 		break;
205917e476dSPeter Dufault 	}
20644e629f1SKonstantin Belousov 	return (e);
207917e476dSPeter Dufault }
208917e476dSPeter Dufault 
209f6c040a2SDavid Xu int
21065343c78SDavid Xu ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy)
211917e476dSPeter Dufault {
21244e629f1SKonstantin Belousov 
21344e629f1SKonstantin Belousov 	return (getscheduler(ksched, td, policy));
214917e476dSPeter Dufault }
215917e476dSPeter Dufault 
21644e629f1SKonstantin Belousov /* ksched_yield: Yield the CPU. */
217f6c040a2SDavid Xu int
21865343c78SDavid Xu ksched_yield(struct ksched *ksched)
219917e476dSPeter Dufault {
22044e629f1SKonstantin Belousov 
22136ec198bSDavid Xu 	sched_relinquish(curthread);
22244e629f1SKonstantin Belousov 	return (0);
223917e476dSPeter Dufault }
224917e476dSPeter Dufault 
225f6c040a2SDavid Xu int
22665343c78SDavid Xu ksched_get_priority_max(struct ksched *ksched, int policy, int *prio)
227917e476dSPeter Dufault {
22844e629f1SKonstantin Belousov 	int e;
229917e476dSPeter Dufault 
23044e629f1SKonstantin Belousov 	e = 0;
23144e629f1SKonstantin Belousov 	switch (policy)	{
232917e476dSPeter Dufault 	case SCHED_FIFO:
233917e476dSPeter Dufault 	case SCHED_RR:
2348d830e02SKonstantin Belousov 		*prio = P1B_PRIO_MAX;
235917e476dSPeter Dufault 		break;
236917e476dSPeter Dufault 	case SCHED_OTHER:
237c3ab507fSDavid Xu 		*prio = PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE;
238917e476dSPeter Dufault 		break;
239917e476dSPeter Dufault 	default:
240917e476dSPeter Dufault 		e = EINVAL;
24144e629f1SKonstantin Belousov 		break;
242917e476dSPeter Dufault 	}
24344e629f1SKonstantin Belousov 	return (e);
244917e476dSPeter Dufault }
245917e476dSPeter Dufault 
246f6c040a2SDavid Xu int
24765343c78SDavid Xu ksched_get_priority_min(struct ksched *ksched, int policy, int *prio)
248917e476dSPeter Dufault {
24944e629f1SKonstantin Belousov 	int e;
250917e476dSPeter Dufault 
25144e629f1SKonstantin Belousov 	e = 0;
25244e629f1SKonstantin Belousov 	switch (policy)	{
253917e476dSPeter Dufault 	case SCHED_FIFO:
254917e476dSPeter Dufault 	case SCHED_RR:
25565343c78SDavid Xu 		*prio = P1B_PRIO_MIN;
256917e476dSPeter Dufault 		break;
257917e476dSPeter Dufault 	case SCHED_OTHER:
258c3ab507fSDavid Xu 		*prio = 0;
259917e476dSPeter Dufault 		break;
260917e476dSPeter Dufault 	default:
261917e476dSPeter Dufault 		e = EINVAL;
26244e629f1SKonstantin Belousov 		break;
263917e476dSPeter Dufault 	}
26444e629f1SKonstantin Belousov 	return (e);
265917e476dSPeter Dufault }
266917e476dSPeter Dufault 
267f6c040a2SDavid Xu int
26844e629f1SKonstantin Belousov ksched_rr_get_interval(struct ksched *ksched, struct thread *td,
26944e629f1SKonstantin Belousov     struct timespec *timespec)
270917e476dSPeter Dufault {
271917e476dSPeter Dufault 
27244e629f1SKonstantin Belousov 	*timespec = ksched->rr_interval;
27344e629f1SKonstantin Belousov 	return (0);
274917e476dSPeter Dufault }
275