xref: /freebsd/sys/kern/ksched.c (revision 1a2cdef4962b47be5057809ce730a733b7f3c27c)
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  * $FreeBSD$
33  */
34 
35 /* ksched: Soft real time scheduling based on "rtprio".
36  */
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/proc.h>
41 #include <sys/mutex.h>
42 #include <sys/resource.h>
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(register_t *ret, struct ksched *ksched, struct proc *p)
97 {
98 	struct rtprio rtp;
99 	int e = 0;
100 
101 	pri_to_rtp(&p->p_pri, &rtp);
102 	switch (rtp.type)
103 	{
104 		case RTP_PRIO_FIFO:
105 		*ret = SCHED_FIFO;
106 		break;
107 
108 		case RTP_PRIO_REALTIME:
109 		*ret = SCHED_RR;
110 		break;
111 
112 		default:
113 		*ret = SCHED_OTHER;
114 		break;
115 	}
116 
117 	return e;
118 }
119 
120 int ksched_setparam(register_t *ret, struct ksched *ksched,
121 	struct proc *p, const struct sched_param *param)
122 {
123 	register_t policy;
124 	int e;
125 
126 	e = getscheduler(&policy, ksched, p);
127 
128 	if (e == 0)
129 	{
130 		if (policy == SCHED_OTHER)
131 			e = EINVAL;
132 		else
133 			e = ksched_setscheduler(ret, ksched, p, policy, param);
134 	}
135 
136 	return e;
137 }
138 
139 int ksched_getparam(register_t *ret, struct ksched *ksched,
140 	struct proc *p, struct sched_param *param)
141 {
142 	struct rtprio rtp;
143 
144 	pri_to_rtp(&p->p_pri, &rtp);
145 	if (RTP_PRIO_IS_REALTIME(rtp.type))
146 		param->sched_priority = rtpprio_to_p4prio(rtp.prio);
147 
148 	return 0;
149 }
150 
151 /*
152  * XXX The priority and scheduler modifications should
153  *     be moved into published interfaces in kern/kern_sync.
154  *
155  * The permissions to modify process p were checked in "p31b_proc()".
156  *
157  */
158 int ksched_setscheduler(register_t *ret, struct ksched *ksched,
159 	struct proc *p, int policy, const struct sched_param *param)
160 {
161 	int e = 0;
162 	struct rtprio rtp;
163 
164 	switch(policy)
165 	{
166 		case SCHED_RR:
167 		case SCHED_FIFO:
168 
169 		if (param->sched_priority >= P1B_PRIO_MIN &&
170 		param->sched_priority <= P1B_PRIO_MAX)
171 		{
172 			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
173 			rtp.type = (policy == SCHED_FIFO)
174 				? RTP_PRIO_FIFO : RTP_PRIO_REALTIME;
175 
176 			mtx_lock_spin(&sched_lock);
177 			rtp_to_pri(&rtp, &p->p_pri);
178 			need_resched();
179 			mtx_unlock_spin(&sched_lock);
180 		}
181 		else
182 			e = EPERM;
183 
184 
185 		break;
186 
187 		case SCHED_OTHER:
188 		{
189 			rtp.type = RTP_PRIO_NORMAL;
190 			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
191 			mtx_lock_spin(&sched_lock);
192 			rtp_to_pri(&rtp, &p->p_pri);
193 
194 			/* XXX Simply revert to whatever we had for last
195 			 *     normal scheduler priorities.
196 			 *     This puts a requirement
197 			 *     on the scheduling code: You must leave the
198 			 *     scheduling info alone.
199 			 */
200 			need_resched();
201 			mtx_unlock_spin(&sched_lock);
202 		}
203 		break;
204 	}
205 
206 	return e;
207 }
208 
209 int ksched_getscheduler(register_t *ret, struct ksched *ksched, struct proc *p)
210 {
211 	return getscheduler(ret, ksched, p);
212 }
213 
214 /* ksched_yield: Yield the CPU.
215  */
216 int ksched_yield(register_t *ret, struct ksched *ksched)
217 {
218 	mtx_lock_spin(&sched_lock);
219 	need_resched();
220 	mtx_unlock_spin(&sched_lock);
221 	return 0;
222 }
223 
224 int ksched_get_priority_max(register_t*ret, struct ksched *ksched, int policy)
225 {
226 	int e = 0;
227 
228 	switch (policy)
229 	{
230 		case SCHED_FIFO:
231 		case SCHED_RR:
232 		*ret = RTP_PRIO_MAX;
233 		break;
234 
235 		case SCHED_OTHER:
236 		*ret =  PRIO_MAX;
237 		break;
238 
239 		default:
240 		e = EINVAL;
241 	}
242 
243 	return e;
244 }
245 
246 int ksched_get_priority_min(register_t *ret, struct ksched *ksched, int policy)
247 {
248 	int e = 0;
249 
250 	switch (policy)
251 	{
252 		case SCHED_FIFO:
253 		case SCHED_RR:
254 		*ret = P1B_PRIO_MIN;
255 		break;
256 
257 		case SCHED_OTHER:
258 		*ret =  PRIO_MIN;
259 		break;
260 
261 		default:
262 		e = EINVAL;
263 	}
264 
265 	return e;
266 }
267 
268 int ksched_rr_get_interval(register_t *ret, struct ksched *ksched,
269 	struct proc *p, struct timespec *timespec)
270 {
271 	*timespec = ksched->rr_interval;
272 
273 	return 0;
274 }
275