xref: /dragonfly/sys/kern/kern_sched.c (revision 62f7f702)
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: src/sys/posix4/ksched.c,v 1.7.2.1 2000/05/16 06:58:13 dillon Exp $
33  * $DragonFly: src/sys/kern/kern_sched.c,v 1.10 2008/04/21 15:24:46 dillon Exp $
34  */
35 
36 /* ksched: Soft real time scheduling based on "rtprio".
37  */
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/posix4.h>
42 #include <sys/proc.h>
43 #include <sys/kernel.h>
44 #include <sys/resource.h>
45 #include <machine/cpu.h>	/* For need_user_resched */
46 
47 
48 /* ksched: Real-time extension to support POSIX priority scheduling.
49  */
50 
51 struct ksched {
52 	struct timespec rr_interval;
53 };
54 
55 int ksched_attach(struct ksched **p)
56 {
57 	struct ksched *ksched= p31b_malloc(sizeof(*ksched));
58 
59 	ksched->rr_interval.tv_sec = 0;
60 	ksched->rr_interval.tv_nsec = 1000000000L / 10;	/* XXX */
61 
62 	*p = ksched;
63 	return 0;
64 }
65 
66 int ksched_detach(struct ksched *p)
67 {
68 	p31b_free(p);
69 
70 	return 0;
71 }
72 
73 /*
74  * XXX About priorities
75  *
76  *	POSIX 1003.1b requires that numerically higher priorities be of
77  *	higher priority.  It also permits sched_setparam to be
78  *	implementation defined for SCHED_OTHER.  I don't like
79  *	the notion of inverted priorites for normal processes when
80  *  you can use "setpriority" for that.
81  *
82  *	I'm rejecting sched_setparam for SCHED_OTHER with EINVAL.
83  */
84 
85 /* Macros to convert between the unix (lower numerically is higher priority)
86  * and POSIX 1003.1b (higher numerically is higher priority)
87  */
88 
89 #define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P))
90 #define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P))
91 
92 /* These improve readability a bit for me:
93  */
94 #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX)
95 #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN)
96 
97 static __inline int
98 getscheduler(register_t *ret, struct ksched *ksched, struct lwp *lp)
99 {
100 	int e = 0;
101 
102 	switch (lp->lwp_rtprio.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 lwp *lp, const struct sched_param *param)
122 {
123 	register_t policy;
124 	int e;
125 
126 	e = getscheduler(&policy, ksched, lp);
127 
128 	if (e == 0)
129 	{
130 		if (policy == SCHED_OTHER)
131 			e = EINVAL;
132 		else
133 			e = ksched_setscheduler(ret, ksched, lp, policy, param);
134 	}
135 
136 	return e;
137 }
138 
139 int ksched_getparam(register_t *ret, struct ksched *ksched,
140 	struct lwp *lp, struct sched_param *param)
141 {
142 	if (RTP_PRIO_IS_REALTIME(lp->lwp_rtprio.type))
143 		param->sched_priority = rtpprio_to_p4prio(lp->lwp_rtprio.prio);
144 
145 	return 0;
146 }
147 
148 /*
149  * XXX The priority and scheduler modifications should
150  *     be moved into published interfaces in kern/kern_sync.
151  *
152  * The permissions to modify process p were checked in "p31b_proc()".
153  *
154  */
155 int ksched_setscheduler(register_t *ret, struct ksched *ksched,
156 	struct lwp *lp, int policy, const struct sched_param *param)
157 {
158 	int e = 0;
159 	struct rtprio rtp;
160 
161 	switch(policy)
162 	{
163 		case SCHED_RR:
164 		case SCHED_FIFO:
165 
166 		if (param->sched_priority >= P1B_PRIO_MIN &&
167 		param->sched_priority <= P1B_PRIO_MAX)
168 		{
169 			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
170 			rtp.type = (policy == SCHED_FIFO)
171 				? RTP_PRIO_FIFO : RTP_PRIO_REALTIME;
172 
173 			lp->lwp_rtprio = rtp;
174 			need_user_resched();
175 		}
176 		else
177 			e = EPERM;
178 
179 
180 		break;
181 
182 		case SCHED_OTHER:
183 		{
184 			rtp.type = RTP_PRIO_NORMAL;
185 			rtp.prio = p4prio_to_rtpprio(param->sched_priority);
186 			lp->lwp_rtprio = rtp;
187 
188 			/* XXX Simply revert to whatever we had for last
189 			 *     normal scheduler priorities.
190 			 *     This puts a requirement
191 			 *     on the scheduling code: You must leave the
192 			 *     scheduling info alone.
193 			 */
194 			need_user_resched();
195 		}
196 		break;
197 	}
198 
199 	return e;
200 }
201 
202 int ksched_getscheduler(register_t *ret, struct ksched *ksched, struct lwp *lp)
203 {
204 	return getscheduler(ret, ksched, lp);
205 }
206 
207 /* ksched_yield: Yield the CPU.
208  */
209 int ksched_yield(register_t *ret, struct ksched *ksched)
210 {
211 	struct lwp *lp;
212 
213 	if ((lp = curthread->td_lwp) != NULL) {
214 		lp->lwp_proc->p_usched->yield(lp);
215 	}
216 	return 0;
217 }
218 
219 int 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 
241 int 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 
263 int ksched_rr_get_interval(register_t *ret, struct ksched *ksched,
264 	struct lwp *lp, struct timespec *timespec)
265 {
266 	*timespec = ksched->rr_interval;
267 
268 	return 0;
269 }
270