xref: /freebsd/sys/kern/ksched.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
1 /*
2  * Copyright (c) 1996, 1997
3  *	HD Associates, Inc.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by HD Associates, Inc
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  */
33 
34 /* ksched: Soft real time scheduling based on "rtprio".
35  */
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/proc.h>
40 #include <sys/kernel.h>
41 #include <sys/resource.h>
42 #include <machine/cpu.h>	/* For need_resched */
43 
44 #include <posix4/posix4.h>
45 
46 /* ksched: Real-time extension to support POSIX priority scheduling.
47  */
48 
49 struct ksched {
50 	struct timespec rr_interval;
51 };
52 
53 int ksched_attach(struct ksched **p)
54 {
55 	struct ksched *ksched= p31b_malloc(sizeof(*ksched));
56 
57 	ksched->rr_interval.tv_sec = 0;
58 	ksched->rr_interval.tv_nsec = 1000000000L / roundrobin_interval();
59 
60 	*p = ksched;
61 	return 0;
62 }
63 
64 int ksched_detach(struct ksched *p)
65 {
66 	p31b_free(p);
67 
68 	return 0;
69 }
70 
71 /*
72  * XXX About priorities
73  *
74  *	POSIX 1003.1b requires that numerically higher priorities be of
75  *	higher priority.  It also permits sched_setparam to be
76  *	implementation defined for SCHED_OTHER.  I don't like
77  *	the notion of inverted priorites for normal processes when
78  *  you can use "setpriority" for that.
79  *
80  *	I'm rejecting sched_setparam for SCHED_OTHER with EINVAL.
81  */
82 
83 /* Macros to convert between the unix (lower numerically is higher priority)
84  * and POSIX 1003.1b (higher numerically is higher priority)
85  */
86 
87 #define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P))
88 #define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P))
89 
90 /* These improve readability a bit for me:
91  */
92 #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX)
93 #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN)
94 
95 static __inline int
96 getscheduler(int *ret, struct ksched *ksched, struct proc *p)
97 {
98 	int e = 0;
99 
100 	switch (p->p_rtprio.type)
101 	{
102 		case RTP_PRIO_FIFO:
103 		*ret = SCHED_FIFO;
104 		break;
105 
106 		case RTP_PRIO_REALTIME:
107 		*ret = SCHED_RR;
108 		break;
109 
110 		default:
111 		*ret = SCHED_OTHER;
112 		break;
113 	}
114 
115 	return e;
116 }
117 
118 int ksched_setparam(int *ret, struct ksched *ksched,
119 	struct proc *p, const struct sched_param *param)
120 {
121 	int e, policy;
122 
123 	e = getscheduler(&policy, ksched, p);
124 
125 	if (e == 0)
126 	{
127 		if (policy == SCHED_OTHER)
128 			e = EINVAL;
129 		else
130 			e = ksched_setscheduler(ret, ksched, p, policy, param);
131 	}
132 
133 	return e;
134 }
135 
136 int ksched_getparam(int *ret, struct ksched *ksched,
137 	struct proc *p, struct sched_param *param)
138 {
139 	if (RTP_PRIO_IS_REALTIME(p->p_rtprio.type))
140 		param->sched_priority = rtpprio_to_p4prio(p->p_rtprio.prio);
141 
142 	return 0;
143 }
144 
145 /*
146  * XXX The priority and scheduler modifications should
147  *     be moved into published interfaces in kern/kern_sync.
148  *
149  * The permissions to modify process p were checked in "p31b_proc()".
150  *
151  */
152 int ksched_setscheduler(int *ret, struct ksched *ksched,
153 	struct proc *p, int policy, const struct sched_param *param)
154 {
155 	int e = 0;
156 	struct rtprio rtp;
157 
158 	switch(policy)
159 	{
160 		case SCHED_RR:
161 		case SCHED_FIFO:
162 
163 		if (param->sched_priority >= P1B_PRIO_MIN &&
164 		param->sched_priority <= P1B_PRIO_MAX)
165 		{
166 			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
167 			rtp.type = (policy == SCHED_FIFO)
168 				? RTP_PRIO_FIFO : RTP_PRIO_REALTIME;
169 
170 			p->p_rtprio = rtp;
171 			need_resched();
172 		}
173 		else
174 			e = EPERM;
175 
176 
177 		break;
178 
179 		case SCHED_OTHER:
180 		{
181 			rtp.type = RTP_PRIO_NORMAL;
182 			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
183 			p->p_rtprio = rtp;
184 
185 			/* XXX Simply revert to whatever we had for last
186 			 *     normal scheduler priorities.
187 			 *     This puts a requirement
188 			 *     on the scheduling code: You must leave the
189 			 *     scheduling info alone.
190 			 */
191 			need_resched();
192 		}
193 		break;
194 	}
195 
196 	return e;
197 }
198 
199 int ksched_getscheduler(int *ret, struct ksched *ksched, struct proc *p)
200 {
201 	return getscheduler(ret, ksched, p);
202 }
203 
204 /* ksched_yield: Yield the CPU.
205  */
206 int ksched_yield(int *ret, struct ksched *ksched)
207 {
208 	need_resched();
209 	return 0;
210 }
211 
212 int ksched_get_priority_max(int *ret, struct ksched *ksched, int policy)
213 {
214 	int e = 0;
215 
216 	switch (policy)
217 	{
218 		case SCHED_FIFO:
219 		case SCHED_RR:
220 		*ret = RTP_PRIO_MAX;
221 		break;
222 
223 		case SCHED_OTHER:
224 		*ret =  PRIO_MAX;
225 		break;
226 
227 		default:
228 		e = EINVAL;
229 	}
230 
231 	return e;
232 }
233 
234 int ksched_get_priority_min(int *ret, struct ksched *ksched, int policy)
235 {
236 	int e = 0;
237 
238 	switch (policy)
239 	{
240 		case SCHED_FIFO:
241 		case SCHED_RR:
242 		*ret = P1B_PRIO_MIN;
243 		break;
244 
245 		case SCHED_OTHER:
246 		*ret =  PRIO_MIN;
247 		break;
248 
249 		default:
250 		e = EINVAL;
251 	}
252 
253 	return e;
254 }
255 
256 int ksched_rr_get_interval(int *ret, struct ksched *ksched,
257 	struct proc *p, struct timespec *timespec)
258 {
259 	*timespec = ksched->rr_interval;
260 
261 	return 0;
262 }
263