ksched.c revision 72376
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: head/sys/kern/ksched.c 72376 2001-02-12 00:20:08Z jake $
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/resource.h>
42#include <machine/cpu.h>	/* For need_resched */
43#include <machine/ipl.h>	/* For need_resched */
44
45#include <posix4/posix4.h>
46
47/* ksched: Real-time extension to support POSIX priority scheduling.
48 */
49
50struct ksched {
51	struct timespec rr_interval;
52};
53
54int ksched_attach(struct ksched **p)
55{
56	struct ksched *ksched= p31b_malloc(sizeof(*ksched));
57
58	ksched->rr_interval.tv_sec = 0;
59	ksched->rr_interval.tv_nsec = 1000000000L / roundrobin_interval();
60
61	*p = ksched;
62	return 0;
63}
64
65int ksched_detach(struct ksched *p)
66{
67	p31b_free(p);
68
69	return 0;
70}
71
72/*
73 * XXX About priorities
74 *
75 *	POSIX 1003.1b requires that numerically higher priorities be of
76 *	higher priority.  It also permits sched_setparam to be
77 *	implementation defined for SCHED_OTHER.  I don't like
78 *	the notion of inverted priorites for normal processes when
79 *  you can use "setpriority" for that.
80 *
81 *	I'm rejecting sched_setparam for SCHED_OTHER with EINVAL.
82 */
83
84/* Macros to convert between the unix (lower numerically is higher priority)
85 * and POSIX 1003.1b (higher numerically is higher priority)
86 */
87
88#define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P))
89#define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P))
90
91/* These improve readability a bit for me:
92 */
93#define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX)
94#define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN)
95
96static __inline int
97getscheduler(register_t *ret, struct ksched *ksched, struct proc *p)
98{
99	struct rtprio rtp;
100	int e = 0;
101
102	pri_to_rtp(&p->p_pri, &rtp);
103	switch (rtp.type)
104	{
105		case RTP_PRIO_FIFO:
106		*ret = SCHED_FIFO;
107		break;
108
109		case RTP_PRIO_REALTIME:
110		*ret = SCHED_RR;
111		break;
112
113		default:
114		*ret = SCHED_OTHER;
115		break;
116	}
117
118	return e;
119}
120
121int ksched_setparam(register_t *ret, struct ksched *ksched,
122	struct proc *p, const struct sched_param *param)
123{
124	register_t policy;
125	int e;
126
127	e = getscheduler(&policy, ksched, p);
128
129	if (e == 0)
130	{
131		if (policy == SCHED_OTHER)
132			e = EINVAL;
133		else
134			e = ksched_setscheduler(ret, ksched, p, policy, param);
135	}
136
137	return e;
138}
139
140int ksched_getparam(register_t *ret, struct ksched *ksched,
141	struct proc *p, struct sched_param *param)
142{
143	struct rtprio rtp;
144
145	pri_to_rtp(&p->p_pri, &rtp);
146	if (RTP_PRIO_IS_REALTIME(rtp.type))
147		param->sched_priority = rtpprio_to_p4prio(rtp.prio);
148
149	return 0;
150}
151
152/*
153 * XXX The priority and scheduler modifications should
154 *     be moved into published interfaces in kern/kern_sync.
155 *
156 * The permissions to modify process p were checked in "p31b_proc()".
157 *
158 */
159int ksched_setscheduler(register_t *ret, struct ksched *ksched,
160	struct proc *p, int policy, const struct sched_param *param)
161{
162	int e = 0;
163	struct rtprio rtp;
164
165	switch(policy)
166	{
167		case SCHED_RR:
168		case SCHED_FIFO:
169
170		if (param->sched_priority >= P1B_PRIO_MIN &&
171		param->sched_priority <= P1B_PRIO_MAX)
172		{
173			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
174			rtp.type = (policy == SCHED_FIFO)
175				? RTP_PRIO_FIFO : RTP_PRIO_REALTIME;
176
177			rtp_to_pri(&rtp, &p->p_pri);
178			need_resched();
179		}
180		else
181			e = EPERM;
182
183
184		break;
185
186		case SCHED_OTHER:
187		{
188			rtp.type = RTP_PRIO_NORMAL;
189			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
190			rtp_to_pri(&rtp, &p->p_pri);
191
192			/* XXX Simply revert to whatever we had for last
193			 *     normal scheduler priorities.
194			 *     This puts a requirement
195			 *     on the scheduling code: You must leave the
196			 *     scheduling info alone.
197			 */
198			need_resched();
199		}
200		break;
201	}
202
203	return e;
204}
205
206int ksched_getscheduler(register_t *ret, struct ksched *ksched, struct proc *p)
207{
208	return getscheduler(ret, ksched, p);
209}
210
211/* ksched_yield: Yield the CPU.
212 */
213int ksched_yield(register_t *ret, struct ksched *ksched)
214{
215	need_resched();
216	return 0;
217}
218
219int ksched_get_priority_max(register_t*ret, struct ksched *ksched, int policy)
220{
221	int e = 0;
222
223	switch (policy)
224	{
225		case SCHED_FIFO:
226		case SCHED_RR:
227		*ret = RTP_PRIO_MAX;
228		break;
229
230		case SCHED_OTHER:
231		*ret =  PRIO_MAX;
232		break;
233
234		default:
235		e = EINVAL;
236	}
237
238	return e;
239}
240
241int ksched_get_priority_min(register_t *ret, struct ksched *ksched, int policy)
242{
243	int e = 0;
244
245	switch (policy)
246	{
247		case SCHED_FIFO:
248		case SCHED_RR:
249		*ret = P1B_PRIO_MIN;
250		break;
251
252		case SCHED_OTHER:
253		*ret =  PRIO_MIN;
254		break;
255
256		default:
257		e = EINVAL;
258	}
259
260	return e;
261}
262
263int ksched_rr_get_interval(register_t *ret, struct ksched *ksched,
264	struct proc *p, struct timespec *timespec)
265{
266	*timespec = ksched->rr_interval;
267
268	return 0;
269}
270