xref: /dragonfly/sys/kern/kern_sched.c (revision dcd37f7d)
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 /*
208  * ksched_yield: Yield the CPU.
209  *
210  * MPSAFE
211  */
212 int
213 ksched_yield(register_t *ret, struct ksched *ksched)
214 {
215 	struct lwp *lp;
216 
217 	if ((lp = curthread->td_lwp) != NULL) {
218 		lp->lwp_proc->p_usched->yield(lp);
219 	}
220 	return 0;
221 }
222 
223 /*
224  * MPSAFE
225  */
226 int
227 ksched_get_priority_max(register_t*ret, struct ksched *ksched, int policy)
228 {
229 	int e = 0;
230 
231 	switch (policy) {
232 	case SCHED_FIFO:
233 	case SCHED_RR:
234 		*ret = RTP_PRIO_MAX;
235 		break;
236 	case SCHED_OTHER:
237 		*ret =  PRIO_MAX;
238 		break;
239 	default:
240 		e = EINVAL;
241 		break;
242 	}
243 
244 	return e;
245 }
246 
247 /*
248  * MPSAFE
249  */
250 int
251 ksched_get_priority_min(register_t *ret, struct ksched *ksched, int policy)
252 {
253 	int e = 0;
254 
255 	switch (policy) {
256 	case SCHED_FIFO:
257 	case SCHED_RR:
258 		*ret = P1B_PRIO_MIN;
259 		break;
260 	case SCHED_OTHER:
261 		*ret =  PRIO_MIN;
262 		break;
263 	default:
264 		e = EINVAL;
265 		break;
266 	}
267 	return e;
268 }
269 
270 /*
271  * MPSAFE
272  */
273 int
274 ksched_rr_get_interval(register_t *ret, struct ksched *ksched,
275 		       struct lwp *lp, struct timespec *timespec)
276 {
277 	*timespec = ksched->rr_interval;
278 
279 	return 0;
280 }
281