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