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