160727d8bSWarner Losh /*-
2df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro 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>
38b565fb9eSAlfred Perlstein #include "opt_posix.h"
39b565fb9eSAlfred Perlstein
40917e476dSPeter Dufault #include <sys/param.h>
41917e476dSPeter Dufault #include <sys/systm.h>
42fb919e4dSMark Murray #include <sys/lock.h>
43de5b1952SAlexander Leidinger #include <sys/sysctl.h>
44de5b1952SAlexander Leidinger #include <sys/kernel.h>
453a187295SJohn Baldwin #include <sys/mutex.h>
46fb919e4dSMark Murray #include <sys/proc.h>
47bdd04ab1STom Rhodes #include <sys/posix4.h>
4838c76440SPeter Dufault #include <sys/resource.h>
49b43179fbSJeff Roberson #include <sys/sched.h>
50917e476dSPeter Dufault
51de5b1952SAlexander Leidinger FEATURE(kposix_priority_scheduling, "POSIX P1003.1B realtime extensions");
52de5b1952SAlexander Leidinger
5344e629f1SKonstantin Belousov /* ksched: Real-time extension to support POSIX priority scheduling. */
54917e476dSPeter Dufault
558a6472b7SPeter Dufault struct ksched {
568a6472b7SPeter Dufault struct timespec rr_interval;
578a6472b7SPeter Dufault };
58917e476dSPeter Dufault
59f6c040a2SDavid Xu int
ksched_attach(struct ksched ** p)60f6c040a2SDavid Xu ksched_attach(struct ksched **p)
61917e476dSPeter Dufault {
6244e629f1SKonstantin Belousov struct ksched *ksched;
63917e476dSPeter Dufault
6444e629f1SKonstantin Belousov ksched = malloc(sizeof(*ksched), M_P31B, M_WAITOK);
658a6472b7SPeter Dufault ksched->rr_interval.tv_sec = 0;
669000aabfSAlexander Motin ksched->rr_interval.tv_nsec = 1000000000L / hz * sched_rr_interval();
678a6472b7SPeter Dufault *p = ksched;
6844e629f1SKonstantin Belousov return (0);
69917e476dSPeter Dufault }
70917e476dSPeter Dufault
71f6c040a2SDavid Xu int
ksched_detach(struct ksched * ks)72f6c040a2SDavid Xu ksched_detach(struct ksched *ks)
73917e476dSPeter Dufault {
748a6472b7SPeter Dufault
7544e629f1SKonstantin Belousov free(ks, M_P31B);
7644e629f1SKonstantin Belousov return (0);
77917e476dSPeter Dufault }
78917e476dSPeter Dufault
79917e476dSPeter Dufault /*
80917e476dSPeter Dufault * XXX About priorities
81917e476dSPeter Dufault *
828a6472b7SPeter Dufault * POSIX 1003.1b requires that numerically higher priorities be of
83917e476dSPeter Dufault * higher priority. It also permits sched_setparam to be
84917e476dSPeter Dufault * implementation defined for SCHED_OTHER. I don't like
85917e476dSPeter Dufault * the notion of inverted priorites for normal processes when
86917e476dSPeter Dufault * you can use "setpriority" for that.
87917e476dSPeter Dufault *
88917e476dSPeter Dufault */
89917e476dSPeter Dufault
90917e476dSPeter Dufault /* Macros to convert between the unix (lower numerically is higher priority)
918a6472b7SPeter Dufault * and POSIX 1003.1b (higher numerically is higher priority)
92917e476dSPeter Dufault */
93917e476dSPeter Dufault
94917e476dSPeter Dufault #define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P))
95917e476dSPeter Dufault #define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P))
96917e476dSPeter Dufault
97bec67fd3SRandall Stewart #define p4prio_to_tsprio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P))
98bec67fd3SRandall Stewart #define tsprio_to_p4prio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P))
99bec67fd3SRandall Stewart
100aebde782SPeter Dufault /* These improve readability a bit for me:
101aebde782SPeter Dufault */
102aebde782SPeter Dufault #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX)
103aebde782SPeter Dufault #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN)
104aebde782SPeter Dufault
105c1087c13SBruce Evans static __inline int
getscheduler(struct ksched * ksched,struct thread * td,int * policy)10665343c78SDavid Xu getscheduler(struct ksched *ksched, struct thread *td, int *policy)
107917e476dSPeter Dufault {
108d5a08a60SJake Burkholder struct rtprio rtp;
10944e629f1SKonstantin Belousov int e;
110917e476dSPeter Dufault
11144e629f1SKonstantin Belousov e = 0;
1128460a577SJohn Birrell pri_to_rtp(td, &rtp);
11344e629f1SKonstantin Belousov switch (rtp.type) {
114917e476dSPeter Dufault case RTP_PRIO_FIFO:
11565343c78SDavid Xu *policy = SCHED_FIFO;
116917e476dSPeter Dufault break;
117917e476dSPeter Dufault case RTP_PRIO_REALTIME:
11865343c78SDavid Xu *policy = SCHED_RR;
119917e476dSPeter Dufault break;
120917e476dSPeter Dufault default:
12165343c78SDavid Xu *policy = SCHED_OTHER;
122917e476dSPeter Dufault break;
123917e476dSPeter Dufault }
12444e629f1SKonstantin Belousov return (e);
125917e476dSPeter Dufault }
126917e476dSPeter Dufault
127f6c040a2SDavid Xu int
ksched_setparam(struct ksched * ksched,struct thread * td,const struct sched_param * param)12865343c78SDavid Xu ksched_setparam(struct ksched *ksched,
129b40ce416SJulian Elischer struct thread *td, const struct sched_param *param)
130917e476dSPeter Dufault {
13144e629f1SKonstantin Belousov int e, policy;
132917e476dSPeter Dufault
13365343c78SDavid Xu e = getscheduler(ksched, td, &policy);
134917e476dSPeter Dufault if (e == 0)
13565343c78SDavid Xu e = ksched_setscheduler(ksched, td, policy, param);
13644e629f1SKonstantin Belousov return (e);
137917e476dSPeter Dufault }
138917e476dSPeter Dufault
139f6c040a2SDavid Xu int
ksched_getparam(struct ksched * ksched,struct thread * td,struct sched_param * param)14044e629f1SKonstantin Belousov ksched_getparam(struct ksched *ksched, struct thread *td,
14144e629f1SKonstantin Belousov struct sched_param *param)
142917e476dSPeter Dufault {
143d5a08a60SJake Burkholder struct rtprio rtp;
144d5a08a60SJake Burkholder
1458460a577SJohn Birrell pri_to_rtp(td, &rtp);
146d5a08a60SJake Burkholder if (RTP_PRIO_IS_REALTIME(rtp.type))
147d5a08a60SJake Burkholder param->sched_priority = rtpprio_to_p4prio(rtp.prio);
148bec67fd3SRandall Stewart else {
149bec67fd3SRandall Stewart if (PRI_MIN_TIMESHARE < rtp.prio)
150bec67fd3SRandall Stewart /*
151bec67fd3SRandall Stewart * The interactive score has it to min realtime
15244e629f1SKonstantin Belousov * so we must show max (64 most likely).
153bec67fd3SRandall Stewart */
15444e629f1SKonstantin Belousov param->sched_priority = PRI_MAX_TIMESHARE -
15544e629f1SKonstantin Belousov PRI_MIN_TIMESHARE;
156bec67fd3SRandall Stewart else
157bec67fd3SRandall Stewart param->sched_priority = tsprio_to_p4prio(rtp.prio);
158bec67fd3SRandall Stewart }
15944e629f1SKonstantin Belousov return (0);
160917e476dSPeter Dufault }
161917e476dSPeter Dufault
162917e476dSPeter Dufault /*
163917e476dSPeter Dufault * XXX The priority and scheduler modifications should
164917e476dSPeter Dufault * be moved into published interfaces in kern/kern_sync.
165917e476dSPeter Dufault *
1668a6472b7SPeter Dufault * The permissions to modify process p were checked in "p31b_proc()".
167917e476dSPeter Dufault *
168917e476dSPeter Dufault */
169f6c040a2SDavid Xu int
ksched_setscheduler(struct ksched * ksched,struct thread * td,int policy,const struct sched_param * param)17044e629f1SKonstantin Belousov ksched_setscheduler(struct ksched *ksched, struct thread *td, int policy,
17144e629f1SKonstantin Belousov const struct sched_param *param)
172917e476dSPeter Dufault {
173917e476dSPeter Dufault struct rtprio rtp;
17444e629f1SKonstantin Belousov int e;
175917e476dSPeter Dufault
17644e629f1SKonstantin Belousov e = 0;
17744e629f1SKonstantin Belousov switch(policy) {
178917e476dSPeter Dufault case SCHED_RR:
179917e476dSPeter Dufault case SCHED_FIFO:
180aebde782SPeter Dufault if (param->sched_priority >= P1B_PRIO_MIN &&
18144e629f1SKonstantin Belousov param->sched_priority <= P1B_PRIO_MAX) {
182aebde782SPeter Dufault rtp.prio = p4prio_to_rtpprio(param->sched_priority);
18344e629f1SKonstantin Belousov rtp.type = (policy == SCHED_FIFO) ? RTP_PRIO_FIFO :
18444e629f1SKonstantin Belousov RTP_PRIO_REALTIME;
1858460a577SJohn Birrell rtp_to_pri(&rtp, td);
18644e629f1SKonstantin Belousov } else {
187*ba478202SAli Abdallah e = EINVAL;
18844e629f1SKonstantin Belousov }
189917e476dSPeter Dufault break;
190917e476dSPeter Dufault case SCHED_OTHER:
19144e629f1SKonstantin Belousov if (param->sched_priority >= 0 && param->sched_priority <=
19244e629f1SKonstantin Belousov (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) {
193917e476dSPeter Dufault rtp.type = RTP_PRIO_NORMAL;
194a2311449SDavid Xu rtp.prio = p4prio_to_tsprio(param->sched_priority);
1958460a577SJohn Birrell rtp_to_pri(&rtp, td);
19644e629f1SKonstantin Belousov } else {
197bec67fd3SRandall Stewart e = EINVAL;
19844e629f1SKonstantin Belousov }
199917e476dSPeter Dufault break;
2005949ba21SJacques Vidrine default:
2015949ba21SJacques Vidrine e = EINVAL;
2025949ba21SJacques Vidrine break;
203917e476dSPeter Dufault }
20444e629f1SKonstantin Belousov return (e);
205917e476dSPeter Dufault }
206917e476dSPeter Dufault
207f6c040a2SDavid Xu int
ksched_getscheduler(struct ksched * ksched,struct thread * td,int * policy)20865343c78SDavid Xu ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy)
209917e476dSPeter Dufault {
21044e629f1SKonstantin Belousov
21144e629f1SKonstantin Belousov return (getscheduler(ksched, td, policy));
212917e476dSPeter Dufault }
213917e476dSPeter Dufault
21444e629f1SKonstantin Belousov /* ksched_yield: Yield the CPU. */
215f6c040a2SDavid Xu int
ksched_yield(struct ksched * ksched)21665343c78SDavid Xu ksched_yield(struct ksched *ksched)
217917e476dSPeter Dufault {
21844e629f1SKonstantin Belousov
21936ec198bSDavid Xu sched_relinquish(curthread);
22044e629f1SKonstantin Belousov return (0);
221917e476dSPeter Dufault }
222917e476dSPeter Dufault
223f6c040a2SDavid Xu int
ksched_get_priority_max(struct ksched * ksched,int policy,int * prio)22465343c78SDavid Xu ksched_get_priority_max(struct ksched *ksched, int policy, int *prio)
225917e476dSPeter Dufault {
22644e629f1SKonstantin Belousov int e;
227917e476dSPeter Dufault
22844e629f1SKonstantin Belousov e = 0;
22944e629f1SKonstantin Belousov switch (policy) {
230917e476dSPeter Dufault case SCHED_FIFO:
231917e476dSPeter Dufault case SCHED_RR:
2328d830e02SKonstantin Belousov *prio = P1B_PRIO_MAX;
233917e476dSPeter Dufault break;
234917e476dSPeter Dufault case SCHED_OTHER:
235c3ab507fSDavid Xu *prio = PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE;
236917e476dSPeter Dufault break;
237917e476dSPeter Dufault default:
238917e476dSPeter Dufault e = EINVAL;
23944e629f1SKonstantin Belousov break;
240917e476dSPeter Dufault }
24144e629f1SKonstantin Belousov return (e);
242917e476dSPeter Dufault }
243917e476dSPeter Dufault
244f6c040a2SDavid Xu int
ksched_get_priority_min(struct ksched * ksched,int policy,int * prio)24565343c78SDavid Xu ksched_get_priority_min(struct ksched *ksched, int policy, int *prio)
246917e476dSPeter Dufault {
24744e629f1SKonstantin Belousov int e;
248917e476dSPeter Dufault
24944e629f1SKonstantin Belousov e = 0;
25044e629f1SKonstantin Belousov switch (policy) {
251917e476dSPeter Dufault case SCHED_FIFO:
252917e476dSPeter Dufault case SCHED_RR:
25365343c78SDavid Xu *prio = P1B_PRIO_MIN;
254917e476dSPeter Dufault break;
255917e476dSPeter Dufault case SCHED_OTHER:
256c3ab507fSDavid Xu *prio = 0;
257917e476dSPeter Dufault break;
258917e476dSPeter Dufault default:
259917e476dSPeter Dufault e = EINVAL;
26044e629f1SKonstantin Belousov break;
261917e476dSPeter Dufault }
26244e629f1SKonstantin Belousov return (e);
263917e476dSPeter Dufault }
264917e476dSPeter Dufault
265f6c040a2SDavid Xu int
ksched_rr_get_interval(struct ksched * ksched,struct thread * td,struct timespec * timespec)26644e629f1SKonstantin Belousov ksched_rr_get_interval(struct ksched *ksched, struct thread *td,
26744e629f1SKonstantin Belousov struct timespec *timespec)
268917e476dSPeter Dufault {
269917e476dSPeter Dufault
27044e629f1SKonstantin Belousov *timespec = ksched->rr_interval;
27144e629f1SKonstantin Belousov return (0);
272917e476dSPeter Dufault }
273