]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - sys/kern/ksched.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / sys / kern / 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 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
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/sysctl.h>
44 #include <sys/kernel.h>
45 #include <sys/mutex.h>
46 #include <sys/proc.h>
47 #include <sys/posix4.h>
48 #include <sys/resource.h>
49 #include <sys/sched.h>
50
51 FEATURE(kposix_priority_scheduling, "POSIX P1003.1B realtime extensions");
52
53 /* ksched: Real-time extension to support POSIX priority scheduling. */
54
55 struct ksched {
56         struct timespec rr_interval;
57 };
58
59 int
60 ksched_attach(struct ksched **p)
61 {
62         struct ksched *ksched;
63
64         ksched = malloc(sizeof(*ksched), M_P31B, M_WAITOK);
65         ksched->rr_interval.tv_sec = 0;
66         ksched->rr_interval.tv_nsec = 1000000000L / hz * sched_rr_interval();
67         *p = ksched;
68         return (0);
69 }
70
71 int
72 ksched_detach(struct ksched *ks)
73 {
74
75         free(ks, M_P31B);
76         return (0);
77 }
78
79 /*
80  * XXX About priorities
81  *
82  *      POSIX 1003.1b requires that numerically higher priorities be of
83  *      higher priority.  It also permits sched_setparam to be
84  *      implementation defined for SCHED_OTHER.  I don't like
85  *      the notion of inverted priorites for normal processes when
86  *      you can use "setpriority" for that.
87  *
88  */
89
90 /* Macros to convert between the unix (lower numerically is higher priority)
91  * and POSIX 1003.1b (higher numerically is higher priority)
92  */
93
94 #define p4prio_to_rtpprio(P) (RTP_PRIO_MAX - (P))
95 #define rtpprio_to_p4prio(P) (RTP_PRIO_MAX - (P))
96
97 #define p4prio_to_tsprio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P))
98 #define tsprio_to_p4prio(P) ((PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE) - (P))
99
100 /* These improve readability a bit for me:
101  */
102 #define P1B_PRIO_MIN rtpprio_to_p4prio(RTP_PRIO_MAX)
103 #define P1B_PRIO_MAX rtpprio_to_p4prio(RTP_PRIO_MIN)
104
105 static __inline int
106 getscheduler(struct ksched *ksched, struct thread *td, int *policy)
107 {
108         struct rtprio rtp;
109         int e;
110
111         e = 0;
112         pri_to_rtp(td, &rtp);
113         switch (rtp.type) {
114         case RTP_PRIO_FIFO:
115                 *policy = SCHED_FIFO;
116                 break;
117         case RTP_PRIO_REALTIME:
118                 *policy = SCHED_RR;
119                 break;
120         default:
121                 *policy = SCHED_OTHER;
122                 break;
123         }
124         return (e);
125 }
126
127 int
128 ksched_setparam(struct ksched *ksched,
129     struct thread *td, const struct sched_param *param)
130 {
131         int e, policy;
132
133         e = getscheduler(ksched, td, &policy);
134         if (e == 0)
135                 e = ksched_setscheduler(ksched, td, policy, param);
136         return (e);
137 }
138
139 int
140 ksched_getparam(struct ksched *ksched, struct thread *td,
141     struct sched_param *param)
142 {
143         struct rtprio rtp;
144
145         pri_to_rtp(td, &rtp);
146         if (RTP_PRIO_IS_REALTIME(rtp.type))
147                 param->sched_priority = rtpprio_to_p4prio(rtp.prio);
148         else {
149                 if (PRI_MIN_TIMESHARE < rtp.prio) 
150                         /*
151                          * The interactive score has it to min realtime
152                          * so we must show max (64 most likely).
153                          */ 
154                         param->sched_priority = PRI_MAX_TIMESHARE -
155                             PRI_MIN_TIMESHARE;
156                 else
157                         param->sched_priority = tsprio_to_p4prio(rtp.prio);
158         }
159         return (0);
160 }
161
162 /*
163  * XXX The priority and scheduler modifications should
164  *     be moved into published interfaces in kern/kern_sync.
165  *
166  * The permissions to modify process p were checked in "p31b_proc()".
167  *
168  */
169 int
170 ksched_setscheduler(struct ksched *ksched, struct thread *td, int policy,
171     const struct sched_param *param)
172 {
173         struct rtprio rtp;
174         int e;
175
176         e = 0;
177         switch(policy) {
178         case SCHED_RR:
179         case SCHED_FIFO:
180                 if (param->sched_priority >= P1B_PRIO_MIN &&
181                     param->sched_priority <= P1B_PRIO_MAX) {
182                         rtp.prio = p4prio_to_rtpprio(param->sched_priority);
183                         rtp.type = (policy == SCHED_FIFO) ? RTP_PRIO_FIFO :
184                             RTP_PRIO_REALTIME;
185                         rtp_to_pri(&rtp, td);
186                 } else {
187                         e = EPERM;
188                 }
189                 break;
190         case SCHED_OTHER:
191                 if (param->sched_priority >= 0 && param->sched_priority <=
192                     (PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE)) {
193                         rtp.type = RTP_PRIO_NORMAL;
194                         rtp.prio = p4prio_to_tsprio(param->sched_priority);
195                         rtp_to_pri(&rtp, td);
196                 } else {
197                         e = EINVAL;
198                 }
199                 break;
200         default:
201                 e = EINVAL;
202                 break;
203         }
204         return (e);
205 }
206
207 int
208 ksched_getscheduler(struct ksched *ksched, struct thread *td, int *policy)
209 {
210
211         return (getscheduler(ksched, td, policy));
212 }
213
214 /* ksched_yield: Yield the CPU. */
215 int
216 ksched_yield(struct ksched *ksched)
217 {
218
219         sched_relinquish(curthread);
220         return (0);
221 }
222
223 int
224 ksched_get_priority_max(struct ksched *ksched, int policy, int *prio)
225 {
226         int e;
227
228         e = 0;
229         switch (policy) {
230         case SCHED_FIFO:
231         case SCHED_RR:
232                 *prio = P1B_PRIO_MAX;
233                 break;
234         case SCHED_OTHER:
235                 *prio = PRI_MAX_TIMESHARE - PRI_MIN_TIMESHARE;
236                 break;
237         default:
238                 e = EINVAL;
239                 break;
240         }
241         return (e);
242 }
243
244 int
245 ksched_get_priority_min(struct ksched *ksched, int policy, int *prio)
246 {
247         int e;
248
249         e = 0;
250         switch (policy) {
251         case SCHED_FIFO:
252         case SCHED_RR:
253                 *prio = P1B_PRIO_MIN;
254                 break;
255         case SCHED_OTHER:
256                 *prio = 0;
257                 break;
258         default:
259                 e = EINVAL;
260                 break;
261         }
262         return (e);
263 }
264
265 int
266 ksched_rr_get_interval(struct ksched *ksched, struct thread *td,
267     struct timespec *timespec)
268 {
269
270         *timespec = ksched->rr_interval;
271         return (0);
272 }