5158 sed dumps core in new multibyte code
[illumos-gate.git] / usr / src / lib / libc / port / rt / sched.c
blob31da81901715909160d0348324910d0d473084d6
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include "lint.h"
30 #include "thr_uberdata.h"
31 #include <sched.h>
32 #include <sys/tspriocntl.h>
33 #include <sys/rtpriocntl.h>
34 #include <sys/fxpriocntl.h>
37 * The following array is used for caching information
38 * for priocntl scheduling classes.
40 static pcclass_t sched_class[] = {
41 {0, SCHED_OTHER, 0, 0, {-1, "TS", 0}},
42 {0, SCHED_FIFO, 0, 0, {-1, "RT", 0}},
43 {0, SCHED_RR, 0, 0, {-1, "RT", 0}},
44 {0, SCHED_SYS, 0, 0, {0, "SYS", 0}},
45 {0, SCHED_IA, 0, 0, {-1, "IA", 0}},
46 {0, SCHED_FSS, 0, 0, {-1, "FSS", 0}},
47 {0, SCHED_FX, 0, 0, {-1, "FX", 0}},
49 * Allow unknown (to us) scheduling classes.
50 * The kernel allows space for exactly 10 scheduling classes
51 * (see the definitions of 'sclass' and 'nclass' in the kernel).
52 * We need that number of available slots here.
53 * If the kernel space is changed, this has to change too.
55 {0, -1, 0, 0, {-1, "", 0}},
56 {0, -1, 0, 0, {-1, "", 0}},
57 {0, -1, 0, 0, {-1, "", 0}},
58 {0, -1, 0, 0, {-1, "", 0}},
59 {0, -1, 0, 0, {-1, "", 0}},
60 {0, -1, 0, 0, {-1, "", 0}},
61 {0, -1, 0, 0, {-1, "", 0}},
62 {0, -1, 0, 0, {-1, "", 0}},
63 {0, -1, 0, 0, {-1, "", 0}},
64 {0, -1, 0, 0, {-1, "", 0}},
67 #define NPOLICY (sizeof (sched_class) / sizeof (pcclass_t))
69 #if _SCHED_NEXT != SCHED_FX + 1
70 #error "fatal: _SCHED_NEXT != SCHED_FX + 1"
71 #endif
73 static mutex_t class_lock = DEFAULTMUTEX; /* protects sched_class[] */
76 * Helper function for get_info_by_policy(), below.
77 * Don't let a manufactured policy number duplicate
78 * the class of one of our base policy numbers.
80 static int
81 is_base_class(const char *clname)
83 const pcclass_t *pccp;
84 int policy;
86 for (policy = 0, pccp = sched_class;
87 policy < _SCHED_NEXT;
88 policy++, pccp++) {
89 if (strcmp(clname, pccp->pcc_info.pc_clname) == 0)
90 return (1);
92 return (0);
96 * Cache priocntl information on scheduling class by policy.
98 const pcclass_t *
99 get_info_by_policy(int policy)
101 pcclass_t *pccp = &sched_class[policy];
102 pcpri_t pcpri;
103 pri_t prio;
104 int base = 0;
106 if ((uint_t)policy >= NPOLICY || pccp->pcc_state < 0) {
107 errno = EINVAL;
108 return (NULL);
111 if (pccp->pcc_state > 0)
112 return (pccp);
114 lmutex_lock(&class_lock);
116 /* get class info (the system class is known to have class-id == 0) */
117 if (pccp->pcc_policy == -1) {
118 /* policy number not defined in <sched.h> */
119 ASSERT(policy >= _SCHED_NEXT);
120 pccp->pcc_info.pc_cid = policy - _SCHED_NEXT;
121 if (priocntl(0, 0, PC_GETCLINFO, &pccp->pcc_info) == -1 ||
122 (base = is_base_class(pccp->pcc_info.pc_clname)) != 0) {
123 pccp->pcc_info.pc_clname[0] = '\0';
124 pccp->pcc_info.pc_cid = -1;
126 * If we duplicated a base class, permanently
127 * disable this policy entry. Else allow for
128 * dynamic loading of scheduling classes.
130 if (base) {
131 membar_producer();
132 pccp->pcc_state = -1;
134 errno = EINVAL;
135 lmutex_unlock(&class_lock);
136 return (NULL);
138 pccp->pcc_policy = policy;
139 } else if (policy != SCHED_SYS &&
140 priocntl(0, 0, PC_GETCID, &pccp->pcc_info) == -1) {
141 membar_producer();
142 pccp->pcc_state = -1;
143 errno = EINVAL;
144 lmutex_unlock(&class_lock);
145 return (NULL);
148 switch (policy) {
149 case SCHED_OTHER:
150 prio = ((tsinfo_t *)pccp->pcc_info.pc_clinfo)->ts_maxupri;
151 pccp->pcc_primin = -prio;
152 pccp->pcc_primax = prio;
153 break;
154 case SCHED_FIFO:
155 case SCHED_RR:
156 prio = ((rtinfo_t *)pccp->pcc_info.pc_clinfo)->rt_maxpri;
157 pccp->pcc_primin = 0;
158 pccp->pcc_primax = prio;
159 break;
160 default:
162 * All other policy numbers, including policy numbers
163 * not defined in <sched.h>.
165 pcpri.pc_cid = pccp->pcc_info.pc_cid;
166 if (priocntl(0, 0, PC_GETPRIRANGE, &pcpri) == 0) {
167 pccp->pcc_primin = pcpri.pc_clpmin;
168 pccp->pcc_primax = pcpri.pc_clpmax;
170 break;
173 membar_producer();
174 pccp->pcc_state = 1;
175 lmutex_unlock(&class_lock);
176 return (pccp);
179 const pcclass_t *
180 get_info_by_class(id_t classid)
182 pcinfo_t pcinfo;
183 pcclass_t *pccp;
184 int policy;
186 if (classid < 0) {
187 errno = EINVAL;
188 return (NULL);
191 /* determine if we already know this classid */
192 for (policy = 0, pccp = sched_class;
193 policy < NPOLICY;
194 policy++, pccp++) {
195 if (pccp->pcc_state > 0 && pccp->pcc_info.pc_cid == classid)
196 return (pccp);
199 pcinfo.pc_cid = classid;
200 if (priocntl(0, 0, PC_GETCLINFO, &pcinfo) == -1) {
201 if (classid == 0) /* no kernel info for sys class */
202 return (get_info_by_policy(SCHED_SYS));
203 return (NULL);
206 for (policy = 0, pccp = sched_class;
207 policy < NPOLICY;
208 policy++, pccp++) {
209 if (pccp->pcc_state == 0 &&
210 strcmp(pcinfo.pc_clname, pccp->pcc_info.pc_clname) == 0)
211 return (get_info_by_policy(pccp->pcc_policy));
215 * We have encountered an unknown (to us) scheduling class.
216 * Manufacture a policy number for it. Hopefully we still
217 * have room in the sched_class[] table.
219 policy = _SCHED_NEXT + classid;
220 if (policy >= NPOLICY) {
221 errno = EINVAL;
222 return (NULL);
224 lmutex_lock(&class_lock);
225 pccp = &sched_class[policy];
226 pccp->pcc_policy = policy;
227 (void) strlcpy(pccp->pcc_info.pc_clname, pcinfo.pc_clname, PC_CLNMSZ);
228 lmutex_unlock(&class_lock);
229 return (get_info_by_policy(pccp->pcc_policy));
233 * Helper function: get process or lwp current scheduling policy.
235 static const pcclass_t *
236 get_parms(idtype_t idtype, id_t id, pcparms_t *pcparmp)
238 pcparmp->pc_cid = PC_CLNULL;
239 if (priocntl(idtype, id, PC_GETPARMS, pcparmp) == -1)
240 return (NULL);
241 return (get_info_by_class(pcparmp->pc_cid));
245 * Helper function for setprio() and setparam(), below.
247 static int
248 set_priority(idtype_t idtype, id_t id, int policy, int prio,
249 pcparms_t *pcparmp, int settq)
251 int rv;
253 switch (policy) {
254 case SCHED_OTHER:
256 tsparms_t *tsp = (tsparms_t *)pcparmp->pc_clparms;
257 tsp->ts_uprilim = prio;
258 tsp->ts_upri = prio;
259 break;
261 case SCHED_FIFO:
262 case SCHED_RR:
264 rtparms_t *rtp = (rtparms_t *)pcparmp->pc_clparms;
265 rtp->rt_tqnsecs = settq?
266 (policy == SCHED_FIFO? RT_TQINF : RT_TQDEF) :
267 RT_NOCHANGE;
268 rtp->rt_pri = prio;
269 break;
271 default:
274 * Class-independent method for setting the priority.
276 pcprio_t pcprio;
278 pcprio.pc_op = PC_SETPRIO;
279 pcprio.pc_cid = pcparmp->pc_cid;
280 pcprio.pc_val = prio;
281 do {
282 rv = priocntl(idtype, id, PC_DOPRIO, &pcprio);
283 } while (rv == -1 && errno == ENOMEM);
284 return (rv);
288 do {
289 rv = priocntl(idtype, id, PC_SETPARMS, pcparmp);
290 } while (rv == -1 && errno == ENOMEM);
291 return (rv);
295 * Utility function, private to libc, used by sched_setparam()
296 * and posix_spawn(). Because it is called by the vfork() child of
297 * posix_spawn(), we must not call any functions exported from libc.
299 id_t
300 setprio(idtype_t idtype, id_t id, int prio, int *policyp)
302 pcparms_t pcparm;
303 int policy;
304 const pcclass_t *pccp;
306 if ((pccp = get_parms(idtype, id, &pcparm)) == NULL)
307 return (-1);
308 if (prio < pccp->pcc_primin || prio > pccp->pcc_primax) {
309 errno = EINVAL;
310 return (-1);
313 policy = pccp->pcc_policy;
314 if (policyp != NULL &&
315 (policy == SCHED_FIFO || policy == SCHED_RR)) {
316 rtparms_t *rtp = (rtparms_t *)pcparm.pc_clparms;
317 policy = (rtp->rt_tqnsecs == RT_TQINF? SCHED_FIFO : SCHED_RR);
320 if (set_priority(idtype, id, policy, prio, &pcparm, 0) == -1)
321 return (-1);
322 if (policyp != NULL)
323 *policyp = policy;
324 return (pccp->pcc_info.pc_cid);
328 sched_setparam(pid_t pid, const struct sched_param *param)
330 if (pid < 0) {
331 errno = ESRCH;
332 return (-1);
334 if (pid == 0)
335 pid = P_MYID;
337 if (setprio(P_PID, pid, param->sched_priority, NULL) == -1)
338 return (-1);
339 return (0);
342 id_t
343 getparam(idtype_t idtype, id_t id, int *policyp, struct sched_param *param)
345 pcparms_t pcparm;
346 const pcclass_t *pccp;
347 int policy;
348 int priority;
350 if ((pccp = get_parms(idtype, id, &pcparm)) == NULL)
351 return (-1);
353 switch (policy = pccp->pcc_policy) {
354 case SCHED_OTHER:
356 tsparms_t *tsp = (tsparms_t *)pcparm.pc_clparms;
357 priority = tsp->ts_upri;
358 break;
360 case SCHED_FIFO:
361 case SCHED_RR:
363 rtparms_t *rtp = (rtparms_t *)pcparm.pc_clparms;
364 priority = rtp->rt_pri;
365 policy = (rtp->rt_tqnsecs == RT_TQINF? SCHED_FIFO : SCHED_RR);
366 break;
368 default:
371 * Class-independent method for getting the priority.
373 pcprio_t pcprio;
375 pcprio.pc_op = PC_GETPRIO;
376 pcprio.pc_cid = 0;
377 pcprio.pc_val = 0;
378 if (priocntl(idtype, id, PC_DOPRIO, &pcprio) == 0)
379 priority = pcprio.pc_val;
380 else
381 priority = 0;
382 break;
386 *policyp = policy;
387 (void) memset(param, 0, sizeof (*param));
388 param->sched_priority = priority;
390 return (pcparm.pc_cid);
394 sched_getparam(pid_t pid, struct sched_param *param)
396 int policy;
398 if (pid < 0) {
399 errno = ESRCH;
400 return (-1);
402 if (pid == 0)
403 pid = P_MYID;
405 if (getparam(P_PID, pid, &policy, param) == -1)
406 return (-1);
407 return (0);
411 * Utility function, private to libc, used by sched_setscheduler()
412 * and posix_spawn(). Because it is called by the vfork() child of
413 * posix_spawn(), we must not call any functions exported from libc.
415 id_t
416 setparam(idtype_t idtype, id_t id, int policy, int prio)
418 pcparms_t pcparm;
419 const pcclass_t *pccp;
421 if (policy == SCHED_SYS ||
422 (pccp = get_info_by_policy(policy)) == NULL ||
423 prio < pccp->pcc_primin || prio > pccp->pcc_primax) {
424 errno = EINVAL;
425 return (-1);
428 pcparm.pc_cid = pccp->pcc_info.pc_cid;
429 if (set_priority(idtype, id, policy, prio, &pcparm, 1) == -1)
430 return (-1);
431 return (pccp->pcc_info.pc_cid);
435 sched_setscheduler(pid_t pid, int policy, const struct sched_param *param)
437 pri_t prio = param->sched_priority;
438 int oldpolicy;
440 if ((oldpolicy = sched_getscheduler(pid)) < 0)
441 return (-1);
443 if (pid == 0)
444 pid = P_MYID;
446 if (setparam(P_PID, pid, policy, prio) == -1)
447 return (-1);
449 return (oldpolicy);
453 sched_getscheduler(pid_t pid)
455 pcparms_t pcparm;
456 const pcclass_t *pccp;
457 int policy;
459 if (pid < 0) {
460 errno = ESRCH;
461 return (-1);
463 if (pid == 0)
464 pid = P_MYID;
466 if ((pccp = get_parms(P_PID, pid, &pcparm)) == NULL)
467 return (-1);
469 if ((policy = pccp->pcc_policy) == SCHED_FIFO || policy == SCHED_RR) {
470 policy =
471 (((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs == RT_TQINF?
472 SCHED_FIFO : SCHED_RR);
475 return (policy);
479 sched_yield(void)
481 yield();
482 return (0);
486 sched_get_priority_max(int policy)
488 const pcclass_t *pccp;
490 if ((pccp = get_info_by_policy(policy)) != NULL)
491 return (pccp->pcc_primax);
492 errno = EINVAL;
493 return (-1);
497 sched_get_priority_min(int policy)
499 const pcclass_t *pccp;
501 if ((pccp = get_info_by_policy(policy)) != NULL)
502 return (pccp->pcc_primin);
503 errno = EINVAL;
504 return (-1);
508 sched_rr_get_interval(pid_t pid, timespec_t *interval)
510 pcparms_t pcparm;
511 const pcclass_t *pccp;
513 if (pid < 0) {
514 errno = ESRCH;
515 return (-1);
517 if (pid == 0)
518 pid = P_MYID;
520 if ((pccp = get_parms(P_PID, pid, &pcparm)) == NULL)
521 return (-1);
524 * At the moment, we have no class-independent method to fetch
525 * the process/lwp time quantum. Since SUSv3 does not restrict
526 * this operation to the real-time class, we return an indefinite
527 * quantum (tv_sec == 0 and tv_nsec == 0) for scheduling policies
528 * for which this information isn't available.
530 interval->tv_sec = 0;
531 interval->tv_nsec = 0;
533 switch (pccp->pcc_policy) {
534 case SCHED_FIFO:
535 case SCHED_RR:
537 rtparms_t *rtp = (rtparms_t *)pcparm.pc_clparms;
538 if (rtp->rt_tqnsecs != RT_TQINF) {
539 interval->tv_sec = rtp->rt_tqsecs;
540 interval->tv_nsec = rtp->rt_tqnsecs;
543 break;
544 case SCHED_FX:
546 fxparms_t *fxp = (fxparms_t *)pcparm.pc_clparms;
547 if (fxp->fx_tqnsecs != FX_TQINF) {
548 interval->tv_sec = fxp->fx_tqsecs;
549 interval->tv_nsec = fxp->fx_tqnsecs;
552 break;
555 return (0);
559 * Initialize or update ul_policy, ul_cid, and ul_pri.
561 void
562 update_sched(ulwp_t *self)
564 volatile sc_shared_t *scp;
565 pcparms_t pcparm;
566 pcprio_t pcprio;
567 const pcclass_t *pccp;
568 int priority;
569 int policy;
571 ASSERT(self == curthread);
573 enter_critical(self);
575 if ((scp = self->ul_schedctl) == NULL &&
576 (scp = setup_schedctl()) == NULL) { /* can't happen? */
577 if (self->ul_policy < 0) {
578 self->ul_cid = 0;
579 self->ul_pri = 0;
580 membar_producer();
581 self->ul_policy = SCHED_OTHER;
583 exit_critical(self);
584 return;
587 if (self->ul_policy >= 0 &&
588 self->ul_cid == scp->sc_cid &&
589 (self->ul_pri == scp->sc_cpri ||
590 (self->ul_epri > 0 && self->ul_epri == scp->sc_cpri))) {
591 exit_critical(self);
592 return;
595 pccp = get_parms(P_LWPID, P_MYID, &pcparm);
596 if (pccp == NULL) { /* can't happen? */
597 self->ul_cid = scp->sc_cid;
598 self->ul_pri = scp->sc_cpri;
599 membar_producer();
600 self->ul_policy = SCHED_OTHER;
601 exit_critical(self);
602 return;
605 switch (policy = pccp->pcc_policy) {
606 case SCHED_OTHER:
607 priority = ((tsparms_t *)pcparm.pc_clparms)->ts_upri;
608 break;
609 case SCHED_FIFO:
610 case SCHED_RR:
611 self->ul_rtclassid = pccp->pcc_info.pc_cid;
612 priority = ((rtparms_t *)pcparm.pc_clparms)->rt_pri;
613 policy =
614 ((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs == RT_TQINF?
615 SCHED_FIFO : SCHED_RR;
616 break;
617 default:
619 * Class-independent method for getting the priority.
621 pcprio.pc_op = PC_GETPRIO;
622 pcprio.pc_cid = 0;
623 pcprio.pc_val = 0;
624 if (priocntl(P_LWPID, P_MYID, PC_DOPRIO, &pcprio) == 0)
625 priority = pcprio.pc_val;
626 else
627 priority = 0;
630 self->ul_cid = pcparm.pc_cid;
631 self->ul_pri = priority;
632 membar_producer();
633 self->ul_policy = policy;
635 exit_critical(self);