xref: /freebsd/sys/kern/ksched.c (revision 917e476dad16ee2bb972f70adede8bd9693aca13)
1917e476dSPeter Dufault /*
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 
34917e476dSPeter Dufault /* ksched: Soft real time scheduling based on "rtprio".
35917e476dSPeter Dufault  */
36917e476dSPeter Dufault 
37917e476dSPeter Dufault #include <sys/param.h>
38917e476dSPeter Dufault #include <sys/systm.h>
39917e476dSPeter Dufault #include <sys/proc.h>
40917e476dSPeter Dufault #include <sys/kernel.h>
41917e476dSPeter Dufault #include <machine/cpu.h>	/* For need_resched */
42917e476dSPeter Dufault #include <fcntl.h>
43917e476dSPeter Dufault 
44917e476dSPeter Dufault #include <sys/posix4.h>
45917e476dSPeter Dufault 
46917e476dSPeter Dufault /* ksched: Real-time extension to support POSIX priority scheduling.
47917e476dSPeter Dufault  */
48917e476dSPeter Dufault 
49917e476dSPeter Dufault static struct timespec rr_interval;
50917e476dSPeter Dufault 
51917e476dSPeter Dufault int ksched_attach(int p4_instance, int fac_code, void **p)
52917e476dSPeter Dufault {
53917e476dSPeter Dufault 	rr_interval.tv_sec = 0;
54917e476dSPeter Dufault 	rr_interval.tv_nsec = 1000000000L / roundrobin_interval();
55917e476dSPeter Dufault 
56917e476dSPeter Dufault 	*p = 0;
57917e476dSPeter Dufault 
58917e476dSPeter Dufault 	return 0;
59917e476dSPeter Dufault }
60917e476dSPeter Dufault 
61917e476dSPeter Dufault int ksched_detach(void *p)
62917e476dSPeter Dufault {
63917e476dSPeter Dufault 	return 0;
64917e476dSPeter Dufault }
65917e476dSPeter Dufault 
66917e476dSPeter Dufault /*
67917e476dSPeter Dufault  * XXX About priorities
68917e476dSPeter Dufault  *
69917e476dSPeter Dufault  *	POSIX4 requires that numerically higher priorities be of
70917e476dSPeter Dufault  *	higher priority.  It also permits sched_setparam to be
71917e476dSPeter Dufault  *	implementation defined for SCHED_OTHER.  I don't like
72917e476dSPeter Dufault  *	the notion of inverted priorites for normal processes when
73917e476dSPeter Dufault  *  you can use "setpriority" for that.
74917e476dSPeter Dufault  *
75917e476dSPeter Dufault  *	I'm rejecting sched_setparam for SCHED_OTHER with EINVAL.
76917e476dSPeter Dufault  */
77917e476dSPeter Dufault 
78917e476dSPeter Dufault /* Macros to convert between the unix (lower numerically is higher priority)
79917e476dSPeter Dufault  * and POSIX4 (higher numerically is higher priority)
80917e476dSPeter Dufault  */
81917e476dSPeter Dufault 
82917e476dSPeter Dufault #define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P))
83917e476dSPeter Dufault #define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P))
84917e476dSPeter Dufault 
85917e476dSPeter Dufault static inline int
86917e476dSPeter Dufault getscheduler(int *ret, void *hook, struct proc *p)
87917e476dSPeter Dufault {
88917e476dSPeter Dufault 	int e = 0;
89917e476dSPeter Dufault 
90917e476dSPeter Dufault 	switch (p->p_rtprio.type)
91917e476dSPeter Dufault 	{
92917e476dSPeter Dufault 		case RTP_PRIO_FIFO:
93917e476dSPeter Dufault 		*ret = SCHED_FIFO;
94917e476dSPeter Dufault 		break;
95917e476dSPeter Dufault 
96917e476dSPeter Dufault 		case RTP_PRIO_REALTIME:
97917e476dSPeter Dufault 		*ret = SCHED_RR;
98917e476dSPeter Dufault 		break;
99917e476dSPeter Dufault 
100917e476dSPeter Dufault 		default:
101917e476dSPeter Dufault 		*ret = SCHED_OTHER;
102917e476dSPeter Dufault 		break;
103917e476dSPeter Dufault 	}
104917e476dSPeter Dufault 
105917e476dSPeter Dufault 	return e;
106917e476dSPeter Dufault }
107917e476dSPeter Dufault 
108917e476dSPeter Dufault int ksched_setparam(int *ret, void *hook,
109917e476dSPeter Dufault 	struct proc *p, const struct sched_param *param)
110917e476dSPeter Dufault {
111917e476dSPeter Dufault 	int e, policy;
112917e476dSPeter Dufault 
113917e476dSPeter Dufault 	e = getscheduler(&policy, hook, p);
114917e476dSPeter Dufault 
115917e476dSPeter Dufault 	if (e == 0)
116917e476dSPeter Dufault 	{
117917e476dSPeter Dufault 		if (policy == SCHED_OTHER)
118917e476dSPeter Dufault 			e = EINVAL;
119917e476dSPeter Dufault 		else
120917e476dSPeter Dufault 			e = ksched_setscheduler(ret, hook, p, policy, param);
121917e476dSPeter Dufault 	}
122917e476dSPeter Dufault 
123917e476dSPeter Dufault 	return e;
124917e476dSPeter Dufault }
125917e476dSPeter Dufault 
126917e476dSPeter Dufault int ksched_getparam(int *ret, void *hook,
127917e476dSPeter Dufault 	struct proc *p, struct sched_param *param)
128917e476dSPeter Dufault {
129917e476dSPeter Dufault 	if (RTP_PRIO_IS_REALTIME(p->p_rtprio.type))
130917e476dSPeter Dufault 		param->sched_priority = rtpprio_to_p4prio(p->p_rtprio.prio);
131917e476dSPeter Dufault 
132917e476dSPeter Dufault 	return 0;
133917e476dSPeter Dufault }
134917e476dSPeter Dufault 
135917e476dSPeter Dufault /*
136917e476dSPeter Dufault  * XXX The priority and scheduler modifications should
137917e476dSPeter Dufault  *     be moved into published interfaces in kern/kern_sync.
138917e476dSPeter Dufault  *
139917e476dSPeter Dufault  * The permissions to modify process p were checked in "posix4proc()".
140917e476dSPeter Dufault  *
141917e476dSPeter Dufault  */
142917e476dSPeter Dufault int ksched_setscheduler(int *ret, void *hook,
143917e476dSPeter Dufault 	struct proc *p, int policy, const struct sched_param *param)
144917e476dSPeter Dufault {
145917e476dSPeter Dufault 	int e = 0;
146917e476dSPeter Dufault 	struct rtprio rtp;
147917e476dSPeter Dufault 
148917e476dSPeter Dufault 	switch(policy)
149917e476dSPeter Dufault 	{
150917e476dSPeter Dufault 		case SCHED_RR:
151917e476dSPeter Dufault 		case SCHED_FIFO:
152917e476dSPeter Dufault 
153917e476dSPeter Dufault 		if (param->sched_priority >= RTP_PRIO_MIN &&
154917e476dSPeter Dufault 		param->sched_priority <= RTP_PRIO_MAX)
155917e476dSPeter Dufault 		{
156917e476dSPeter Dufault 			rtp.type = (policy == SCHED_FIFO)
157917e476dSPeter Dufault 				? RTP_PRIO_FIFO : RTP_PRIO_REALTIME;
158917e476dSPeter Dufault 
159917e476dSPeter Dufault 			rtp.prio = p4prio_to_rtpprio(RTP_PRIO_MAX);
160917e476dSPeter Dufault 			p->p_rtprio = rtp;
161917e476dSPeter Dufault 			(void)resetpriority(p);
162917e476dSPeter Dufault 		}
163917e476dSPeter Dufault 		else
164917e476dSPeter Dufault 			e = EPERM;
165917e476dSPeter Dufault 
166917e476dSPeter Dufault 
167917e476dSPeter Dufault 		break;
168917e476dSPeter Dufault 
169917e476dSPeter Dufault 		case SCHED_OTHER:
170917e476dSPeter Dufault 		{
171917e476dSPeter Dufault 			rtp.type = RTP_PRIO_NORMAL;
172917e476dSPeter Dufault 			rtp.prio = p4prio_to_rtpprio(RTP_PRIO_MIN);
173917e476dSPeter Dufault 			p->p_rtprio = rtp;
174917e476dSPeter Dufault 
175917e476dSPeter Dufault 			/* XXX Simply revert to whatever we had for last
176917e476dSPeter Dufault 			 *     normal scheduler priorities.
177917e476dSPeter Dufault 			 *     This puts a requirement
178917e476dSPeter Dufault 			 *     on the scheduling code: You must leave the
179917e476dSPeter Dufault 			 *     scheduling info alone.
180917e476dSPeter Dufault 			 */
181917e476dSPeter Dufault 			(void)resetpriority(p);
182917e476dSPeter Dufault 		}
183917e476dSPeter Dufault 		break;
184917e476dSPeter Dufault 	}
185917e476dSPeter Dufault 
186917e476dSPeter Dufault 	return e;
187917e476dSPeter Dufault }
188917e476dSPeter Dufault 
189917e476dSPeter Dufault int ksched_getscheduler(int *ret, void *hook, struct proc *p)
190917e476dSPeter Dufault {
191917e476dSPeter Dufault 	return getscheduler(ret, hook, p);
192917e476dSPeter Dufault }
193917e476dSPeter Dufault 
194917e476dSPeter Dufault /* ksched_yield: Yield the CPU.
195917e476dSPeter Dufault  */
196917e476dSPeter Dufault int ksched_yield(int *ret, void *hook)
197917e476dSPeter Dufault {
198917e476dSPeter Dufault 	need_resched();
199917e476dSPeter Dufault 	return 0;
200917e476dSPeter Dufault }
201917e476dSPeter Dufault 
202917e476dSPeter Dufault int ksched_get_priority_max(int *ret, void *hook, int policy)
203917e476dSPeter Dufault {
204917e476dSPeter Dufault 	int e = 0;
205917e476dSPeter Dufault 
206917e476dSPeter Dufault 	switch (policy)
207917e476dSPeter Dufault 	{
208917e476dSPeter Dufault 		case SCHED_FIFO:
209917e476dSPeter Dufault 		case SCHED_RR:
210917e476dSPeter Dufault 		*ret = RTP_PRIO_MAX;
211917e476dSPeter Dufault 		break;
212917e476dSPeter Dufault 
213917e476dSPeter Dufault 		case SCHED_OTHER:
214917e476dSPeter Dufault 		*ret =  PRIO_MAX;
215917e476dSPeter Dufault 		break;
216917e476dSPeter Dufault 
217917e476dSPeter Dufault 		default:
218917e476dSPeter Dufault 		e = EINVAL;
219917e476dSPeter Dufault 	}
220917e476dSPeter Dufault 
221917e476dSPeter Dufault 	return e;
222917e476dSPeter Dufault }
223917e476dSPeter Dufault 
224917e476dSPeter Dufault int ksched_get_priority_min(int *ret, void *hook, int policy)
225917e476dSPeter Dufault {
226917e476dSPeter Dufault 	int e = 0;
227917e476dSPeter Dufault 
228917e476dSPeter Dufault 	switch (policy)
229917e476dSPeter Dufault 	{
230917e476dSPeter Dufault 		case SCHED_FIFO:
231917e476dSPeter Dufault 		case SCHED_RR:
232917e476dSPeter Dufault 		*ret = RTP_PRIO_MIN;
233917e476dSPeter Dufault 		break;
234917e476dSPeter Dufault 
235917e476dSPeter Dufault 		case SCHED_OTHER:
236917e476dSPeter Dufault 		*ret =  PRIO_MIN;
237917e476dSPeter Dufault 		break;
238917e476dSPeter Dufault 
239917e476dSPeter Dufault 		default:
240917e476dSPeter Dufault 		e = EINVAL;
241917e476dSPeter Dufault 	}
242917e476dSPeter Dufault 
243917e476dSPeter Dufault 	return e;
244917e476dSPeter Dufault }
245917e476dSPeter Dufault 
246917e476dSPeter Dufault int ksched_rr_get_interval(int *ret, void *hook,
247917e476dSPeter Dufault 	struct proc *p, struct timespec *timespec)
248917e476dSPeter Dufault {
249917e476dSPeter Dufault 	*timespec = rr_interval;
250917e476dSPeter Dufault 
251917e476dSPeter Dufault 	return 0;
252917e476dSPeter Dufault }
253