xref: /freebsd/sys/kern/ksched.c (revision 65343c78)
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>
4638c76440SPeter Dufault #include <sys/resource.h>
47b43179fbSJeff Roberson #include <sys/sched.h>
48917e476dSPeter Dufault 
498a6472b7SPeter Dufault #include <posix4/posix4.h>
50917e476dSPeter Dufault 
51917e476dSPeter Dufault /* ksched: Real-time extension to support POSIX priority scheduling.
52917e476dSPeter Dufault  */
53917e476dSPeter Dufault 
548a6472b7SPeter Dufault struct ksched {
558a6472b7SPeter Dufault 	struct timespec rr_interval;
568a6472b7SPeter Dufault };
57917e476dSPeter Dufault 
58f6c040a2SDavid Xu int
59f6c040a2SDavid Xu ksched_attach(struct ksched **p)
60917e476dSPeter Dufault {
618a6472b7SPeter Dufault 	struct ksched *ksched= p31b_malloc(sizeof(*ksched));
62917e476dSPeter Dufault 
638a6472b7SPeter Dufault 	ksched->rr_interval.tv_sec = 0;
64b43179fbSJeff Roberson 	ksched->rr_interval.tv_nsec = 1000000000L / sched_rr_interval();
65917e476dSPeter Dufault 
668a6472b7SPeter Dufault 	*p = ksched;
67917e476dSPeter Dufault 	return 0;
68917e476dSPeter Dufault }
69917e476dSPeter Dufault 
70f6c040a2SDavid Xu int
71f6c040a2SDavid Xu ksched_detach(struct ksched *ks)
72917e476dSPeter Dufault {
73b40ce416SJulian Elischer 	p31b_free(ks);
748a6472b7SPeter Dufault 
75917e476dSPeter Dufault 	return 0;
76917e476dSPeter Dufault }
77917e476dSPeter Dufault 
78917e476dSPeter Dufault /*
79917e476dSPeter Dufault  * XXX About priorities
80917e476dSPeter Dufault  *
818a6472b7SPeter Dufault  *	POSIX 1003.1b requires that numerically higher priorities be of
82917e476dSPeter Dufault  *	higher priority.  It also permits sched_setparam to be
83917e476dSPeter Dufault  *	implementation defined for SCHED_OTHER.  I don't like
84917e476dSPeter Dufault  *	the notion of inverted priorites for normal processes when
85917e476dSPeter Dufault  *  you can use "setpriority" for that.
86917e476dSPeter Dufault  *
87917e476dSPeter Dufault  *	I'm rejecting sched_setparam for SCHED_OTHER with EINVAL.
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 
97aebde782SPeter Dufault /* These improve readability a bit for me:
98aebde782SPeter Dufault  */
99aebde782SPeter Dufault #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX)
100aebde782SPeter Dufault #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN)
101aebde782SPeter Dufault 
102c1087c13SBruce Evans static __inline int
10365343c78SDavid Xu getscheduler(struct ksched *ksched, struct thread *td, int *policy)
104917e476dSPeter Dufault {
105d5a08a60SJake Burkholder 	struct rtprio rtp;
106917e476dSPeter Dufault 	int e = 0;
107917e476dSPeter Dufault 
10851b4eed9SJohn Baldwin 	mtx_lock_spin(&sched_lock);
1092c100766SJulian Elischer 	pri_to_rtp(td->td_ksegrp, &rtp);
11051b4eed9SJohn Baldwin 	mtx_unlock_spin(&sched_lock);
111d5a08a60SJake Burkholder 	switch (rtp.type)
112917e476dSPeter Dufault 	{
113917e476dSPeter Dufault 		case RTP_PRIO_FIFO:
11465343c78SDavid Xu 		*policy = SCHED_FIFO;
115917e476dSPeter Dufault 		break;
116917e476dSPeter Dufault 
117917e476dSPeter Dufault 		case RTP_PRIO_REALTIME:
11865343c78SDavid Xu 		*policy = SCHED_RR;
119917e476dSPeter Dufault 		break;
120917e476dSPeter Dufault 
121917e476dSPeter Dufault 		default:
12265343c78SDavid Xu 		*policy = SCHED_OTHER;
123917e476dSPeter Dufault 		break;
124917e476dSPeter Dufault 	}
125917e476dSPeter Dufault 
126917e476dSPeter Dufault 	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 {
13365343c78SDavid Xu 	int policy;
1349f79feecSBruce Evans 	int e;
135917e476dSPeter Dufault 
13665343c78SDavid Xu 	e = getscheduler(ksched, td, &policy);
137917e476dSPeter Dufault 
138917e476dSPeter Dufault 	if (e == 0)
139917e476dSPeter Dufault 	{
140917e476dSPeter Dufault 		if (policy == SCHED_OTHER)
141917e476dSPeter Dufault 			e = EINVAL;
142917e476dSPeter Dufault 		else
14365343c78SDavid Xu 			e = ksched_setscheduler(ksched, td, policy, param);
144917e476dSPeter Dufault 	}
145917e476dSPeter Dufault 
146917e476dSPeter Dufault 	return e;
147917e476dSPeter Dufault }
148917e476dSPeter Dufault 
149f6c040a2SDavid Xu int
15065343c78SDavid Xu ksched_getparam(struct ksched *ksched,
151b40ce416SJulian Elischer     struct thread *td, struct sched_param *param)
152917e476dSPeter Dufault {
153d5a08a60SJake Burkholder 	struct rtprio rtp;
154d5a08a60SJake Burkholder 
15551b4eed9SJohn Baldwin 	mtx_lock_spin(&sched_lock);
1562c100766SJulian Elischer 	pri_to_rtp(td->td_ksegrp, &rtp);
15751b4eed9SJohn Baldwin 	mtx_unlock_spin(&sched_lock);
158d5a08a60SJake Burkholder 	if (RTP_PRIO_IS_REALTIME(rtp.type))
159d5a08a60SJake Burkholder 		param->sched_priority = rtpprio_to_p4prio(rtp.prio);
160917e476dSPeter Dufault 
161917e476dSPeter Dufault 	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
17265343c78SDavid Xu ksched_setscheduler(struct ksched *ksched,
173b40ce416SJulian Elischer     struct thread *td, int policy, const struct sched_param *param)
174917e476dSPeter Dufault {
175917e476dSPeter Dufault 	int e = 0;
176917e476dSPeter Dufault 	struct rtprio rtp;
1772c100766SJulian Elischer 	struct ksegrp *kg = td->td_ksegrp;
178917e476dSPeter Dufault 
179917e476dSPeter Dufault 	switch(policy)
180917e476dSPeter Dufault 	{
181917e476dSPeter Dufault 		case SCHED_RR:
182917e476dSPeter Dufault 		case SCHED_FIFO:
183917e476dSPeter Dufault 
184aebde782SPeter Dufault 		if (param->sched_priority >= P1B_PRIO_MIN &&
185aebde782SPeter Dufault 		    param->sched_priority <= P1B_PRIO_MAX)
186917e476dSPeter Dufault 		{
187aebde782SPeter Dufault 			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
188917e476dSPeter Dufault 			rtp.type = (policy == SCHED_FIFO)
189917e476dSPeter Dufault 				? RTP_PRIO_FIFO : RTP_PRIO_REALTIME;
190917e476dSPeter Dufault 
1913a187295SJohn Baldwin 			mtx_lock_spin(&sched_lock);
1922c100766SJulian Elischer 			rtp_to_pri(&rtp, kg);
193e602ba25SJulian Elischer 			FOREACH_THREAD_IN_GROUP(kg, td) { /* XXXKSE */
19471fad9fdSJulian Elischer 				if (TD_IS_RUNNING(td)) {
1954a338afdSJulian Elischer 					td->td_flags |= TDF_NEEDRESCHED;
19671fad9fdSJulian Elischer 				} else if (TD_ON_RUNQ(td)) {
197e602ba25SJulian Elischer 					if (td->td_priority > kg->kg_user_pri) {
1981f955e2dSJulian Elischer 						sched_prio(td, kg->kg_user_pri);
199e602ba25SJulian Elischer 					}
200e602ba25SJulian Elischer 				}
201e602ba25SJulian Elischer 			}
2023a187295SJohn Baldwin 			mtx_unlock_spin(&sched_lock);
203917e476dSPeter Dufault 		}
204917e476dSPeter Dufault 		else
205917e476dSPeter Dufault 			e = EPERM;
206917e476dSPeter Dufault 
207917e476dSPeter Dufault 
208917e476dSPeter Dufault 		break;
209917e476dSPeter Dufault 
210917e476dSPeter Dufault 		case SCHED_OTHER:
211917e476dSPeter Dufault 		{
212917e476dSPeter Dufault 			rtp.type = RTP_PRIO_NORMAL;
2132a61a110SPeter Dufault 			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
2143a187295SJohn Baldwin 			mtx_lock_spin(&sched_lock);
2152c100766SJulian Elischer 			rtp_to_pri(&rtp, kg);
216917e476dSPeter Dufault 
217917e476dSPeter Dufault 			/* XXX Simply revert to whatever we had for last
218917e476dSPeter Dufault 			 *     normal scheduler priorities.
219917e476dSPeter Dufault 			 *     This puts a requirement
220917e476dSPeter Dufault 			 *     on the scheduling code: You must leave the
221917e476dSPeter Dufault 			 *     scheduling info alone.
222917e476dSPeter Dufault 			 */
223e602ba25SJulian Elischer 			FOREACH_THREAD_IN_GROUP(kg, td) {
22471fad9fdSJulian Elischer 				if (TD_IS_RUNNING(td)) {
2254a338afdSJulian Elischer 					td->td_flags |= TDF_NEEDRESCHED;
22671fad9fdSJulian Elischer 				} else if (TD_ON_RUNQ(td)) {
227e602ba25SJulian Elischer 					if (td->td_priority > kg->kg_user_pri) {
2281f955e2dSJulian Elischer 						sched_prio(td, kg->kg_user_pri);
229e602ba25SJulian Elischer 					}
230e602ba25SJulian Elischer 				}
231e602ba25SJulian Elischer 
232e602ba25SJulian Elischer 			}
2333a187295SJohn Baldwin 			mtx_unlock_spin(&sched_lock);
234917e476dSPeter Dufault 		}
235917e476dSPeter Dufault 		break;
2365949ba21SJacques Vidrine 
2375949ba21SJacques Vidrine 		default:
2385949ba21SJacques Vidrine 			e = EINVAL;
2395949ba21SJacques Vidrine 			break;
240917e476dSPeter Dufault 	}
241917e476dSPeter Dufault 
242917e476dSPeter Dufault 	return e;
243917e476dSPeter Dufault }
244917e476dSPeter Dufault 
245f6c040a2SDavid Xu int
24665343c78SDavid Xu ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy)
247917e476dSPeter Dufault {
24865343c78SDavid Xu 	return getscheduler(ksched, td, policy);
249917e476dSPeter Dufault }
250917e476dSPeter Dufault 
251917e476dSPeter Dufault /* ksched_yield: Yield the CPU.
252917e476dSPeter Dufault  */
253f6c040a2SDavid Xu int
25465343c78SDavid Xu ksched_yield(struct ksched *ksched)
255917e476dSPeter Dufault {
25636ec198bSDavid Xu 	sched_relinquish(curthread);
257917e476dSPeter Dufault 	return 0;
258917e476dSPeter Dufault }
259917e476dSPeter Dufault 
260f6c040a2SDavid Xu int
26165343c78SDavid Xu ksched_get_priority_max(struct ksched *ksched, int policy, int *prio)
262917e476dSPeter Dufault {
263917e476dSPeter Dufault 	int e = 0;
264917e476dSPeter Dufault 
265917e476dSPeter Dufault 	switch (policy)
266917e476dSPeter Dufault 	{
267917e476dSPeter Dufault 		case SCHED_FIFO:
268917e476dSPeter Dufault 		case SCHED_RR:
26965343c78SDavid Xu 		*prio = RTP_PRIO_MAX;
270917e476dSPeter Dufault 		break;
271917e476dSPeter Dufault 
272917e476dSPeter Dufault 		case SCHED_OTHER:
27365343c78SDavid Xu 		*prio =  PRIO_MAX;
274917e476dSPeter Dufault 		break;
275917e476dSPeter Dufault 
276917e476dSPeter Dufault 		default:
277917e476dSPeter Dufault 		e = EINVAL;
278917e476dSPeter Dufault 	}
279917e476dSPeter Dufault 
280917e476dSPeter Dufault 	return e;
281917e476dSPeter Dufault }
282917e476dSPeter Dufault 
283f6c040a2SDavid Xu int
28465343c78SDavid Xu ksched_get_priority_min(struct ksched *ksched, int policy, int *prio)
285917e476dSPeter Dufault {
286917e476dSPeter Dufault 	int e = 0;
287917e476dSPeter Dufault 
288917e476dSPeter Dufault 	switch (policy)
289917e476dSPeter Dufault 	{
290917e476dSPeter Dufault 		case SCHED_FIFO:
291917e476dSPeter Dufault 		case SCHED_RR:
29265343c78SDavid Xu 		*prio = P1B_PRIO_MIN;
293917e476dSPeter Dufault 		break;
294917e476dSPeter Dufault 
295917e476dSPeter Dufault 		case SCHED_OTHER:
29665343c78SDavid Xu 		*prio =  PRIO_MIN;
297917e476dSPeter Dufault 		break;
298917e476dSPeter Dufault 
299917e476dSPeter Dufault 		default:
300917e476dSPeter Dufault 		e = EINVAL;
301917e476dSPeter Dufault 	}
302917e476dSPeter Dufault 
303917e476dSPeter Dufault 	return e;
304917e476dSPeter Dufault }
305917e476dSPeter Dufault 
306f6c040a2SDavid Xu int
30765343c78SDavid Xu ksched_rr_get_interval(struct ksched *ksched,
308b40ce416SJulian Elischer    struct thread *td, struct timespec *timespec)
309917e476dSPeter Dufault {
3108a6472b7SPeter Dufault 	*timespec = ksched->rr_interval;
311917e476dSPeter Dufault 
312917e476dSPeter Dufault 	return 0;
313917e476dSPeter Dufault }
314