1:1 Userland threading stage 2.11/4:
[dragonfly.git] / sys / kern / kern_sched.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: 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.8 2007/02/03 17:05:57 corecode 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/proc.h>
42 #include <sys/kernel.h>
43 #include <sys/resource.h>
44 #include <machine/cpu.h>        /* For need_user_resched */
45
46 #include "posix4.h"
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         need_user_resched();
212         return 0;
213 }
214
215 int ksched_get_priority_max(register_t*ret, struct ksched *ksched, int policy)
216 {
217         int e = 0;
218
219         switch (policy)
220         {
221                 case SCHED_FIFO:
222                 case SCHED_RR:
223                 *ret = RTP_PRIO_MAX;
224                 break;
225
226                 case SCHED_OTHER:
227                 *ret =  PRIO_MAX;
228                 break;
229
230                 default:
231                 e = EINVAL;
232         }
233
234         return e;
235 }
236
237 int ksched_get_priority_min(register_t *ret, struct ksched *ksched, int policy)
238 {
239         int e = 0;
240
241         switch (policy)
242         {
243                 case SCHED_FIFO:
244                 case SCHED_RR:
245                 *ret = P1B_PRIO_MIN;
246                 break;
247
248                 case SCHED_OTHER:
249                 *ret =  PRIO_MIN;
250                 break;
251
252                 default:
253                 e = EINVAL;
254         }
255
256         return e;
257 }
258
259 int ksched_rr_get_interval(register_t *ret, struct ksched *ksched,
260         struct lwp *lp, struct timespec *timespec)
261 {
262         *timespec = ksched->rr_interval;
263
264         return 0;
265 }