1f841f6adSraf /*
2f841f6adSraf * CDDL HEADER START
3f841f6adSraf *
4f841f6adSraf * The contents of this file are subject to the terms of the
5f841f6adSraf * Common Development and Distribution License (the "License").
6f841f6adSraf * You may not use this file except in compliance with the License.
7f841f6adSraf *
8f841f6adSraf * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f841f6adSraf * or http://www.opensolaris.org/os/licensing.
10f841f6adSraf * See the License for the specific language governing permissions
11f841f6adSraf * and limitations under the License.
12f841f6adSraf *
13f841f6adSraf * When distributing Covered Code, include this CDDL HEADER in each
14f841f6adSraf * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f841f6adSraf * If applicable, add the following below this CDDL HEADER, with the
16f841f6adSraf * fields enclosed by brackets "[]" replaced with your own identifying
17f841f6adSraf * information: Portions Copyright [yyyy] [name of copyright owner]
18f841f6adSraf *
19f841f6adSraf * CDDL HEADER END
20f841f6adSraf */
21f841f6adSraf
22f841f6adSraf /*
23d4204c85Sraf * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24f841f6adSraf * Use is subject to license terms.
25f841f6adSraf */
26f841f6adSraf
27f841f6adSraf #pragma ident "%Z%%M% %I% %E% SMI"
28f841f6adSraf
29*7257d1b4Sraf #include "lint.h"
30d4204c85Sraf #include "thr_uberdata.h"
31f841f6adSraf #include <sched.h>
32f841f6adSraf #include <sys/tspriocntl.h>
33d4204c85Sraf #include <sys/rtpriocntl.h>
34d4204c85Sraf #include <sys/fxpriocntl.h>
35f841f6adSraf
36f841f6adSraf /*
37d4204c85Sraf * The following array is used for caching information
38f841f6adSraf * for priocntl scheduling classes.
39f841f6adSraf */
40d4204c85Sraf static pcclass_t sched_class[] = {
41d4204c85Sraf {0, SCHED_OTHER, 0, 0, {-1, "TS", 0}},
42d4204c85Sraf {0, SCHED_FIFO, 0, 0, {-1, "RT", 0}},
43d4204c85Sraf {0, SCHED_RR, 0, 0, {-1, "RT", 0}},
44d4204c85Sraf {0, SCHED_SYS, 0, 0, {0, "SYS", 0}},
45d4204c85Sraf {0, SCHED_IA, 0, 0, {-1, "IA", 0}},
46d4204c85Sraf {0, SCHED_FSS, 0, 0, {-1, "FSS", 0}},
47d4204c85Sraf {0, SCHED_FX, 0, 0, {-1, "FX", 0}},
48d4204c85Sraf /*
49d4204c85Sraf * Allow unknown (to us) scheduling classes.
50d4204c85Sraf * The kernel allows space for exactly 10 scheduling classes
51d4204c85Sraf * (see the definitions of 'sclass' and 'nclass' in the kernel).
52d4204c85Sraf * We need that number of available slots here.
53d4204c85Sraf * If the kernel space is changed, this has to change too.
54d4204c85Sraf */
55d4204c85Sraf {0, -1, 0, 0, {-1, "", 0}},
56d4204c85Sraf {0, -1, 0, 0, {-1, "", 0}},
57d4204c85Sraf {0, -1, 0, 0, {-1, "", 0}},
58d4204c85Sraf {0, -1, 0, 0, {-1, "", 0}},
59d4204c85Sraf {0, -1, 0, 0, {-1, "", 0}},
60d4204c85Sraf {0, -1, 0, 0, {-1, "", 0}},
61d4204c85Sraf {0, -1, 0, 0, {-1, "", 0}},
62d4204c85Sraf {0, -1, 0, 0, {-1, "", 0}},
63d4204c85Sraf {0, -1, 0, 0, {-1, "", 0}},
64d4204c85Sraf {0, -1, 0, 0, {-1, "", 0}},
65d4204c85Sraf };
66f841f6adSraf
67d4204c85Sraf #define NPOLICY (sizeof (sched_class) / sizeof (pcclass_t))
68f841f6adSraf
69d4204c85Sraf #if _SCHED_NEXT != SCHED_FX + 1
70d4204c85Sraf #error "fatal: _SCHED_NEXT != SCHED_FX + 1"
71d4204c85Sraf #endif
72f841f6adSraf
73d4204c85Sraf static mutex_t class_lock = DEFAULTMUTEX; /* protects sched_class[] */
74f841f6adSraf
75f841f6adSraf /*
76d4204c85Sraf * Helper function for get_info_by_policy(), below.
77d4204c85Sraf * Don't let a manufactured policy number duplicate
78d4204c85Sraf * the class of one of our base policy numbers.
79f841f6adSraf */
80d4204c85Sraf static int
is_base_class(const char * clname)81d4204c85Sraf is_base_class(const char *clname)
82d4204c85Sraf {
83d4204c85Sraf const pcclass_t *pccp;
84d4204c85Sraf int policy;
85d4204c85Sraf
86d4204c85Sraf for (policy = 0, pccp = sched_class;
87d4204c85Sraf policy < _SCHED_NEXT;
88d4204c85Sraf policy++, pccp++) {
89d4204c85Sraf if (strcmp(clname, pccp->pcc_info.pc_clname) == 0)
90d4204c85Sraf return (1);
91d4204c85Sraf }
92d4204c85Sraf return (0);
93d4204c85Sraf }
94d4204c85Sraf
95d4204c85Sraf /*
96d4204c85Sraf * Cache priocntl information on scheduling class by policy.
97d4204c85Sraf */
98d4204c85Sraf const pcclass_t *
get_info_by_policy(int policy)99f841f6adSraf get_info_by_policy(int policy)
100f841f6adSraf {
101d4204c85Sraf pcclass_t *pccp = &sched_class[policy];
102d4204c85Sraf pcpri_t pcpri;
103d4204c85Sraf pri_t prio;
104d4204c85Sraf int base = 0;
105f841f6adSraf
106d4204c85Sraf if ((uint_t)policy >= NPOLICY || pccp->pcc_state < 0) {
107d4204c85Sraf errno = EINVAL;
108d4204c85Sraf return (NULL);
109d4204c85Sraf }
110d4204c85Sraf
111d4204c85Sraf if (pccp->pcc_state > 0)
112d4204c85Sraf return (pccp);
113d4204c85Sraf
114d4204c85Sraf lmutex_lock(&class_lock);
115d4204c85Sraf
116d4204c85Sraf /* get class info (the system class is known to have class-id == 0) */
117d4204c85Sraf if (pccp->pcc_policy == -1) {
118d4204c85Sraf /* policy number not defined in <sched.h> */
119d4204c85Sraf ASSERT(policy >= _SCHED_NEXT);
120d4204c85Sraf pccp->pcc_info.pc_cid = policy - _SCHED_NEXT;
1218cd45542Sraf if (priocntl(0, 0, PC_GETCLINFO, &pccp->pcc_info) == -1 ||
122d4204c85Sraf (base = is_base_class(pccp->pcc_info.pc_clname)) != 0) {
123d4204c85Sraf pccp->pcc_info.pc_clname[0] = '\0';
124d4204c85Sraf pccp->pcc_info.pc_cid = -1;
125d4204c85Sraf /*
126d4204c85Sraf * If we duplicated a base class, permanently
127d4204c85Sraf * disable this policy entry. Else allow for
128d4204c85Sraf * dynamic loading of scheduling classes.
129d4204c85Sraf */
130d4204c85Sraf if (base) {
131*7257d1b4Sraf membar_producer();
132d4204c85Sraf pccp->pcc_state = -1;
133d4204c85Sraf }
134d4204c85Sraf errno = EINVAL;
135d4204c85Sraf lmutex_unlock(&class_lock);
136d4204c85Sraf return (NULL);
137d4204c85Sraf }
138d4204c85Sraf pccp->pcc_policy = policy;
139d4204c85Sraf } else if (policy != SCHED_SYS &&
1408cd45542Sraf priocntl(0, 0, PC_GETCID, &pccp->pcc_info) == -1) {
141*7257d1b4Sraf membar_producer();
142d4204c85Sraf pccp->pcc_state = -1;
143d4204c85Sraf errno = EINVAL;
144d4204c85Sraf lmutex_unlock(&class_lock);
145d4204c85Sraf return (NULL);
146d4204c85Sraf }
147d4204c85Sraf
148d4204c85Sraf switch (policy) {
149d4204c85Sraf case SCHED_OTHER:
150d4204c85Sraf prio = ((tsinfo_t *)pccp->pcc_info.pc_clinfo)->ts_maxupri;
151d4204c85Sraf pccp->pcc_primin = -prio;
152d4204c85Sraf pccp->pcc_primax = prio;
153d4204c85Sraf break;
154d4204c85Sraf case SCHED_FIFO:
155d4204c85Sraf case SCHED_RR:
156d4204c85Sraf prio = ((rtinfo_t *)pccp->pcc_info.pc_clinfo)->rt_maxpri;
157d4204c85Sraf pccp->pcc_primin = 0;
158d4204c85Sraf pccp->pcc_primax = prio;
159d4204c85Sraf break;
160d4204c85Sraf default:
161d4204c85Sraf /*
162d4204c85Sraf * All other policy numbers, including policy numbers
163d4204c85Sraf * not defined in <sched.h>.
164d4204c85Sraf */
165d4204c85Sraf pcpri.pc_cid = pccp->pcc_info.pc_cid;
1668cd45542Sraf if (priocntl(0, 0, PC_GETPRIRANGE, &pcpri) == 0) {
167d4204c85Sraf pccp->pcc_primin = pcpri.pc_clpmin;
168d4204c85Sraf pccp->pcc_primax = pcpri.pc_clpmax;
169d4204c85Sraf }
170d4204c85Sraf break;
171d4204c85Sraf }
172d4204c85Sraf
173*7257d1b4Sraf membar_producer();
174d4204c85Sraf pccp->pcc_state = 1;
175d4204c85Sraf lmutex_unlock(&class_lock);
176d4204c85Sraf return (pccp);
177d4204c85Sraf }
178d4204c85Sraf
179d4204c85Sraf const pcclass_t *
get_info_by_class(id_t classid)180d4204c85Sraf get_info_by_class(id_t classid)
181d4204c85Sraf {
182d4204c85Sraf pcinfo_t pcinfo;
183d4204c85Sraf pcclass_t *pccp;
184d4204c85Sraf int policy;
185d4204c85Sraf
186d4204c85Sraf if (classid < 0) {
187d4204c85Sraf errno = EINVAL;
188d4204c85Sraf return (NULL);
189d4204c85Sraf }
190d4204c85Sraf
191d4204c85Sraf /* determine if we already know this classid */
192d4204c85Sraf for (policy = 0, pccp = sched_class;
193d4204c85Sraf policy < NPOLICY;
194d4204c85Sraf policy++, pccp++) {
195d4204c85Sraf if (pccp->pcc_state > 0 && pccp->pcc_info.pc_cid == classid)
196d4204c85Sraf return (pccp);
197d4204c85Sraf }
198d4204c85Sraf
199d4204c85Sraf pcinfo.pc_cid = classid;
2008cd45542Sraf if (priocntl(0, 0, PC_GETCLINFO, &pcinfo) == -1) {
201d4204c85Sraf if (classid == 0) /* no kernel info for sys class */
202d4204c85Sraf return (get_info_by_policy(SCHED_SYS));
203d4204c85Sraf return (NULL);
204d4204c85Sraf }
205d4204c85Sraf
206d4204c85Sraf for (policy = 0, pccp = sched_class;
207d4204c85Sraf policy < NPOLICY;
208d4204c85Sraf policy++, pccp++) {
209d4204c85Sraf if (pccp->pcc_state == 0 &&
210d4204c85Sraf strcmp(pcinfo.pc_clname, pccp->pcc_info.pc_clname) == 0)
211d4204c85Sraf return (get_info_by_policy(pccp->pcc_policy));
212d4204c85Sraf }
213d4204c85Sraf
214d4204c85Sraf /*
215d4204c85Sraf * We have encountered an unknown (to us) scheduling class.
216d4204c85Sraf * Manufacture a policy number for it. Hopefully we still
217d4204c85Sraf * have room in the sched_class[] table.
218d4204c85Sraf */
219d4204c85Sraf policy = _SCHED_NEXT + classid;
220d4204c85Sraf if (policy >= NPOLICY) {
221d4204c85Sraf errno = EINVAL;
222d4204c85Sraf return (NULL);
223d4204c85Sraf }
224d4204c85Sraf lmutex_lock(&class_lock);
225d4204c85Sraf pccp = &sched_class[policy];
226d4204c85Sraf pccp->pcc_policy = policy;
227d4204c85Sraf (void) strlcpy(pccp->pcc_info.pc_clname, pcinfo.pc_clname, PC_CLNMSZ);
228d4204c85Sraf lmutex_unlock(&class_lock);
229d4204c85Sraf return (get_info_by_policy(pccp->pcc_policy));
230d4204c85Sraf }
231d4204c85Sraf
232d4204c85Sraf /*
233d4204c85Sraf * Helper function: get process or lwp current scheduling policy.
234d4204c85Sraf */
235d4204c85Sraf static const pcclass_t *
get_parms(idtype_t idtype,id_t id,pcparms_t * pcparmp)236d4204c85Sraf get_parms(idtype_t idtype, id_t id, pcparms_t *pcparmp)
237d4204c85Sraf {
238d4204c85Sraf pcparmp->pc_cid = PC_CLNULL;
2398cd45542Sraf if (priocntl(idtype, id, PC_GETPARMS, pcparmp) == -1)
240d4204c85Sraf return (NULL);
241d4204c85Sraf return (get_info_by_class(pcparmp->pc_cid));
242d4204c85Sraf }
243d4204c85Sraf
244d4204c85Sraf /*
245d4204c85Sraf * Helper function for setprio() and setparam(), below.
246d4204c85Sraf */
247d4204c85Sraf static int
set_priority(idtype_t idtype,id_t id,int policy,int prio,pcparms_t * pcparmp,int settq)248d4204c85Sraf set_priority(idtype_t idtype, id_t id, int policy, int prio,
249d4204c85Sraf pcparms_t *pcparmp, int settq)
250d4204c85Sraf {
251d4204c85Sraf int rv;
252d4204c85Sraf
253d4204c85Sraf switch (policy) {
254d4204c85Sraf case SCHED_OTHER:
255d4204c85Sraf {
256d4204c85Sraf tsparms_t *tsp = (tsparms_t *)pcparmp->pc_clparms;
257d4204c85Sraf tsp->ts_uprilim = prio;
258d4204c85Sraf tsp->ts_upri = prio;
259d4204c85Sraf break;
260d4204c85Sraf }
261d4204c85Sraf case SCHED_FIFO:
262d4204c85Sraf case SCHED_RR:
263d4204c85Sraf {
264d4204c85Sraf rtparms_t *rtp = (rtparms_t *)pcparmp->pc_clparms;
265d4204c85Sraf rtp->rt_tqnsecs = settq?
266d4204c85Sraf (policy == SCHED_FIFO? RT_TQINF : RT_TQDEF) :
267d4204c85Sraf RT_NOCHANGE;
268d4204c85Sraf rtp->rt_pri = prio;
269d4204c85Sraf break;
270d4204c85Sraf }
271d4204c85Sraf default:
272d4204c85Sraf {
273d4204c85Sraf /*
274d4204c85Sraf * Class-independent method for setting the priority.
275d4204c85Sraf */
276d4204c85Sraf pcprio_t pcprio;
277d4204c85Sraf
278d4204c85Sraf pcprio.pc_op = PC_SETPRIO;
279d4204c85Sraf pcprio.pc_cid = pcparmp->pc_cid;
280d4204c85Sraf pcprio.pc_val = prio;
281d4204c85Sraf do {
2828cd45542Sraf rv = priocntl(idtype, id, PC_DOPRIO, &pcprio);
283d4204c85Sraf } while (rv == -1 && errno == ENOMEM);
284d4204c85Sraf return (rv);
285d4204c85Sraf }
286d4204c85Sraf }
287d4204c85Sraf
288d4204c85Sraf do {
2898cd45542Sraf rv = priocntl(idtype, id, PC_SETPARMS, pcparmp);
290d4204c85Sraf } while (rv == -1 && errno == ENOMEM);
291d4204c85Sraf return (rv);
292d4204c85Sraf }
293d4204c85Sraf
294d4204c85Sraf /*
295d4204c85Sraf * Utility function, private to libc, used by sched_setparam()
296d4204c85Sraf * and posix_spawn(). Because it is called by the vfork() child of
297d4204c85Sraf * posix_spawn(), we must not call any functions exported from libc.
298d4204c85Sraf */
299d4204c85Sraf id_t
setprio(idtype_t idtype,id_t id,int prio,int * policyp)300d4204c85Sraf setprio(idtype_t idtype, id_t id, int prio, int *policyp)
301d4204c85Sraf {
302d4204c85Sraf pcparms_t pcparm;
303d4204c85Sraf int policy;
304d4204c85Sraf const pcclass_t *pccp;
305d4204c85Sraf
306d4204c85Sraf if ((pccp = get_parms(idtype, id, &pcparm)) == NULL)
307d4204c85Sraf return (-1);
308d4204c85Sraf if (prio < pccp->pcc_primin || prio > pccp->pcc_primax) {
309f841f6adSraf errno = EINVAL;
310f841f6adSraf return (-1);
311f841f6adSraf }
312f841f6adSraf
313d4204c85Sraf policy = pccp->pcc_policy;
314d4204c85Sraf if (policyp != NULL &&
315d4204c85Sraf (policy == SCHED_FIFO || policy == SCHED_RR)) {
316d4204c85Sraf rtparms_t *rtp = (rtparms_t *)pcparm.pc_clparms;
317d4204c85Sraf policy = (rtp->rt_tqnsecs == RT_TQINF? SCHED_FIFO : SCHED_RR);
318f841f6adSraf }
319f841f6adSraf
320d4204c85Sraf if (set_priority(idtype, id, policy, prio, &pcparm, 0) == -1)
321f841f6adSraf return (-1);
322d4204c85Sraf if (policyp != NULL)
323d4204c85Sraf *policyp = policy;
324d4204c85Sraf return (pccp->pcc_info.pc_cid);
325f841f6adSraf }
326f841f6adSraf
327f841f6adSraf int
sched_setparam(pid_t pid,const struct sched_param * param)328f841f6adSraf sched_setparam(pid_t pid, const struct sched_param *param)
329f841f6adSraf {
330f841f6adSraf if (pid < 0) {
331f841f6adSraf errno = ESRCH;
332f841f6adSraf return (-1);
333f841f6adSraf }
334f841f6adSraf if (pid == 0)
335f841f6adSraf pid = P_MYID;
336f841f6adSraf
337d4204c85Sraf if (setprio(P_PID, pid, param->sched_priority, NULL) == -1)
338f841f6adSraf return (-1);
339d4204c85Sraf return (0);
340d4204c85Sraf }
341d4204c85Sraf
342d4204c85Sraf id_t
getparam(idtype_t idtype,id_t id,int * policyp,struct sched_param * param)343d4204c85Sraf getparam(idtype_t idtype, id_t id, int *policyp, struct sched_param *param)
344d4204c85Sraf {
345d4204c85Sraf pcparms_t pcparm;
346d4204c85Sraf const pcclass_t *pccp;
347d4204c85Sraf int policy;
348d4204c85Sraf int priority;
349d4204c85Sraf
350d4204c85Sraf if ((pccp = get_parms(idtype, id, &pcparm)) == NULL)
351f841f6adSraf return (-1);
352f841f6adSraf
353d4204c85Sraf switch (policy = pccp->pcc_policy) {
354d4204c85Sraf case SCHED_OTHER:
355d4204c85Sraf {
356d4204c85Sraf tsparms_t *tsp = (tsparms_t *)pcparm.pc_clparms;
357d4204c85Sraf priority = tsp->ts_upri;
358d4204c85Sraf break;
359f841f6adSraf }
360d4204c85Sraf case SCHED_FIFO:
361d4204c85Sraf case SCHED_RR:
362d4204c85Sraf {
363d4204c85Sraf rtparms_t *rtp = (rtparms_t *)pcparm.pc_clparms;
364d4204c85Sraf priority = rtp->rt_pri;
365d4204c85Sraf policy = (rtp->rt_tqnsecs == RT_TQINF? SCHED_FIFO : SCHED_RR);
366d4204c85Sraf break;
367d4204c85Sraf }
368d4204c85Sraf default:
369d4204c85Sraf {
370f841f6adSraf /*
371d4204c85Sraf * Class-independent method for getting the priority.
372f841f6adSraf */
373d4204c85Sraf pcprio_t pcprio;
374d4204c85Sraf
375d4204c85Sraf pcprio.pc_op = PC_GETPRIO;
376d4204c85Sraf pcprio.pc_cid = 0;
377d4204c85Sraf pcprio.pc_val = 0;
3788cd45542Sraf if (priocntl(idtype, id, PC_DOPRIO, &pcprio) == 0)
379d4204c85Sraf priority = pcprio.pc_val;
380d4204c85Sraf else
381d4204c85Sraf priority = 0;
382d4204c85Sraf break;
383d4204c85Sraf }
384f841f6adSraf }
385f841f6adSraf
386d4204c85Sraf *policyp = policy;
387d4204c85Sraf (void) memset(param, 0, sizeof (*param));
388d4204c85Sraf param->sched_priority = priority;
389d4204c85Sraf
390d4204c85Sraf return (pcparm.pc_cid);
391f841f6adSraf }
392f841f6adSraf
393f841f6adSraf int
sched_getparam(pid_t pid,struct sched_param * param)394f841f6adSraf sched_getparam(pid_t pid, struct sched_param *param)
395f841f6adSraf {
396f841f6adSraf int policy;
397f841f6adSraf
398f841f6adSraf if (pid < 0) {
399f841f6adSraf errno = ESRCH;
400f841f6adSraf return (-1);
401f841f6adSraf }
402f841f6adSraf if (pid == 0)
403f841f6adSraf pid = P_MYID;
404f841f6adSraf
405d4204c85Sraf if (getparam(P_PID, pid, &policy, param) == -1)
406f841f6adSraf return (-1);
407d4204c85Sraf return (0);
408d4204c85Sraf }
409d4204c85Sraf
410d4204c85Sraf /*
411d4204c85Sraf * Utility function, private to libc, used by sched_setscheduler()
412d4204c85Sraf * and posix_spawn(). Because it is called by the vfork() child of
413d4204c85Sraf * posix_spawn(), we must not call any functions exported from libc.
414d4204c85Sraf */
415d4204c85Sraf id_t
setparam(idtype_t idtype,id_t id,int policy,int prio)416d4204c85Sraf setparam(idtype_t idtype, id_t id, int policy, int prio)
417d4204c85Sraf {
418d4204c85Sraf pcparms_t pcparm;
419d4204c85Sraf const pcclass_t *pccp;
420d4204c85Sraf
421d4204c85Sraf if (policy == SCHED_SYS ||
422d4204c85Sraf (pccp = get_info_by_policy(policy)) == NULL ||
423d4204c85Sraf prio < pccp->pcc_primin || prio > pccp->pcc_primax) {
424d4204c85Sraf errno = EINVAL;
425d4204c85Sraf return (-1);
426d4204c85Sraf }
427d4204c85Sraf
428d4204c85Sraf pcparm.pc_cid = pccp->pcc_info.pc_cid;
429d4204c85Sraf if (set_priority(idtype, id, policy, prio, &pcparm, 1) == -1)
430d4204c85Sraf return (-1);
431d4204c85Sraf return (pccp->pcc_info.pc_cid);
432d4204c85Sraf }
433d4204c85Sraf
434d4204c85Sraf int
sched_setscheduler(pid_t pid,int policy,const struct sched_param * param)435d4204c85Sraf sched_setscheduler(pid_t pid, int policy, const struct sched_param *param)
436d4204c85Sraf {
437d4204c85Sraf pri_t prio = param->sched_priority;
438d4204c85Sraf int oldpolicy;
439d4204c85Sraf
440d4204c85Sraf if ((oldpolicy = sched_getscheduler(pid)) < 0)
441f841f6adSraf return (-1);
442f841f6adSraf
443d4204c85Sraf if (pid == 0)
444d4204c85Sraf pid = P_MYID;
445d4204c85Sraf
446d4204c85Sraf if (setparam(P_PID, pid, policy, prio) == -1)
447d4204c85Sraf return (-1);
448d4204c85Sraf
449d4204c85Sraf return (oldpolicy);
450d4204c85Sraf }
451d4204c85Sraf
452d4204c85Sraf int
sched_getscheduler(pid_t pid)453d4204c85Sraf sched_getscheduler(pid_t pid)
454d4204c85Sraf {
455d4204c85Sraf pcparms_t pcparm;
456d4204c85Sraf const pcclass_t *pccp;
457d4204c85Sraf int policy;
458d4204c85Sraf
459d4204c85Sraf if (pid < 0) {
460d4204c85Sraf errno = ESRCH;
461d4204c85Sraf return (-1);
462d4204c85Sraf }
463d4204c85Sraf if (pid == 0)
464d4204c85Sraf pid = P_MYID;
465d4204c85Sraf
466d4204c85Sraf if ((pccp = get_parms(P_PID, pid, &pcparm)) == NULL)
467d4204c85Sraf return (-1);
468d4204c85Sraf
469d4204c85Sraf if ((policy = pccp->pcc_policy) == SCHED_FIFO || policy == SCHED_RR) {
470d4204c85Sraf policy =
471d4204c85Sraf (((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs == RT_TQINF?
472d4204c85Sraf SCHED_FIFO : SCHED_RR);
473f841f6adSraf }
474f841f6adSraf
475f841f6adSraf return (policy);
476f841f6adSraf }
477f841f6adSraf
478f841f6adSraf int
sched_yield(void)479f841f6adSraf sched_yield(void)
480f841f6adSraf {
4818cd45542Sraf yield();
482f841f6adSraf return (0);
483f841f6adSraf }
484f841f6adSraf
485f841f6adSraf int
sched_get_priority_max(int policy)486f841f6adSraf sched_get_priority_max(int policy)
487f841f6adSraf {
488d4204c85Sraf const pcclass_t *pccp;
489f841f6adSraf
490d4204c85Sraf if ((pccp = get_info_by_policy(policy)) != NULL)
491d4204c85Sraf return (pccp->pcc_primax);
492f841f6adSraf errno = EINVAL;
493f841f6adSraf return (-1);
494f841f6adSraf }
495f841f6adSraf
496f841f6adSraf int
sched_get_priority_min(int policy)497f841f6adSraf sched_get_priority_min(int policy)
498f841f6adSraf {
499d4204c85Sraf const pcclass_t *pccp;
500f841f6adSraf
501d4204c85Sraf if ((pccp = get_info_by_policy(policy)) != NULL)
502d4204c85Sraf return (pccp->pcc_primin);
503f841f6adSraf errno = EINVAL;
504f841f6adSraf return (-1);
505f841f6adSraf }
506f841f6adSraf
507f841f6adSraf int
sched_rr_get_interval(pid_t pid,timespec_t * interval)508f841f6adSraf sched_rr_get_interval(pid_t pid, timespec_t *interval)
509f841f6adSraf {
510f841f6adSraf pcparms_t pcparm;
511d4204c85Sraf const pcclass_t *pccp;
512f841f6adSraf
513f841f6adSraf if (pid < 0) {
514f841f6adSraf errno = ESRCH;
515f841f6adSraf return (-1);
516f841f6adSraf }
517f841f6adSraf if (pid == 0)
518f841f6adSraf pid = P_MYID;
519f841f6adSraf
520d4204c85Sraf if ((pccp = get_parms(P_PID, pid, &pcparm)) == NULL)
521f841f6adSraf return (-1);
522f841f6adSraf
523d4204c85Sraf /*
524d4204c85Sraf * At the moment, we have no class-independent method to fetch
525d4204c85Sraf * the process/lwp time quantum. Since SUSv3 does not restrict
526d4204c85Sraf * this operation to the real-time class, we return an indefinite
527d4204c85Sraf * quantum (tv_sec == 0 and tv_nsec == 0) for scheduling policies
528d4204c85Sraf * for which this information isn't available.
529d4204c85Sraf */
530d4204c85Sraf interval->tv_sec = 0;
531d4204c85Sraf interval->tv_nsec = 0;
532f841f6adSraf
533d4204c85Sraf switch (pccp->pcc_policy) {
534d4204c85Sraf case SCHED_FIFO:
535d4204c85Sraf case SCHED_RR:
536d4204c85Sraf {
537d4204c85Sraf rtparms_t *rtp = (rtparms_t *)pcparm.pc_clparms;
538d4204c85Sraf if (rtp->rt_tqnsecs != RT_TQINF) {
539d4204c85Sraf interval->tv_sec = rtp->rt_tqsecs;
540d4204c85Sraf interval->tv_nsec = rtp->rt_tqnsecs;
541d4204c85Sraf }
542d4204c85Sraf }
543d4204c85Sraf break;
544d4204c85Sraf case SCHED_FX:
545d4204c85Sraf {
546d4204c85Sraf fxparms_t *fxp = (fxparms_t *)pcparm.pc_clparms;
547d4204c85Sraf if (fxp->fx_tqnsecs != FX_TQINF) {
548d4204c85Sraf interval->tv_sec = fxp->fx_tqsecs;
549d4204c85Sraf interval->tv_nsec = fxp->fx_tqnsecs;
550d4204c85Sraf }
551d4204c85Sraf }
552d4204c85Sraf break;
553d4204c85Sraf }
554d4204c85Sraf
555f841f6adSraf return (0);
556f841f6adSraf }
557f841f6adSraf
558d4204c85Sraf /*
559d4204c85Sraf * Initialize or update ul_policy, ul_cid, and ul_pri.
560d4204c85Sraf */
561d4204c85Sraf void
update_sched(ulwp_t * self)562d4204c85Sraf update_sched(ulwp_t *self)
563d4204c85Sraf {
564d4204c85Sraf volatile sc_shared_t *scp;
565d4204c85Sraf pcparms_t pcparm;
566d4204c85Sraf pcprio_t pcprio;
567d4204c85Sraf const pcclass_t *pccp;
568d4204c85Sraf int priority;
569d4204c85Sraf int policy;
570d4204c85Sraf
571d4204c85Sraf ASSERT(self == curthread);
572d4204c85Sraf
573d4204c85Sraf enter_critical(self);
574d4204c85Sraf
575d4204c85Sraf if ((scp = self->ul_schedctl) == NULL &&
576d4204c85Sraf (scp = setup_schedctl()) == NULL) { /* can't happen? */
577d4204c85Sraf if (self->ul_policy < 0) {
578d4204c85Sraf self->ul_cid = 0;
579d4204c85Sraf self->ul_pri = 0;
580*7257d1b4Sraf membar_producer();
581d4204c85Sraf self->ul_policy = SCHED_OTHER;
582d4204c85Sraf }
583d4204c85Sraf exit_critical(self);
584d4204c85Sraf return;
585d4204c85Sraf }
586d4204c85Sraf
587d4204c85Sraf if (self->ul_policy >= 0 &&
588d4204c85Sraf self->ul_cid == scp->sc_cid &&
589d4204c85Sraf (self->ul_pri == scp->sc_cpri ||
590d4204c85Sraf (self->ul_epri > 0 && self->ul_epri == scp->sc_cpri))) {
591d4204c85Sraf exit_critical(self);
592d4204c85Sraf return;
593d4204c85Sraf }
594d4204c85Sraf
595d4204c85Sraf pccp = get_parms(P_LWPID, P_MYID, &pcparm);
596d4204c85Sraf if (pccp == NULL) { /* can't happen? */
597d4204c85Sraf self->ul_cid = scp->sc_cid;
598d4204c85Sraf self->ul_pri = scp->sc_cpri;
599*7257d1b4Sraf membar_producer();
600d4204c85Sraf self->ul_policy = SCHED_OTHER;
601d4204c85Sraf exit_critical(self);
602d4204c85Sraf return;
603d4204c85Sraf }
604d4204c85Sraf
605d4204c85Sraf switch (policy = pccp->pcc_policy) {
606d4204c85Sraf case SCHED_OTHER:
607d4204c85Sraf priority = ((tsparms_t *)pcparm.pc_clparms)->ts_upri;
608d4204c85Sraf break;
609d4204c85Sraf case SCHED_FIFO:
610d4204c85Sraf case SCHED_RR:
611e84487aeSraf self->ul_rtclassid = pccp->pcc_info.pc_cid;
612d4204c85Sraf priority = ((rtparms_t *)pcparm.pc_clparms)->rt_pri;
613d4204c85Sraf policy =
614d4204c85Sraf ((rtparms_t *)pcparm.pc_clparms)->rt_tqnsecs == RT_TQINF?
615d4204c85Sraf SCHED_FIFO : SCHED_RR;
616d4204c85Sraf break;
617d4204c85Sraf default:
618d4204c85Sraf /*
619d4204c85Sraf * Class-independent method for getting the priority.
620d4204c85Sraf */
621d4204c85Sraf pcprio.pc_op = PC_GETPRIO;
622d4204c85Sraf pcprio.pc_cid = 0;
623d4204c85Sraf pcprio.pc_val = 0;
6248cd45542Sraf if (priocntl(P_LWPID, P_MYID, PC_DOPRIO, &pcprio) == 0)
625d4204c85Sraf priority = pcprio.pc_val;
626d4204c85Sraf else
627d4204c85Sraf priority = 0;
628d4204c85Sraf }
629d4204c85Sraf
630d4204c85Sraf self->ul_cid = pcparm.pc_cid;
631d4204c85Sraf self->ul_pri = priority;
632*7257d1b4Sraf membar_producer();
633d4204c85Sraf self->ul_policy = policy;
634d4204c85Sraf
635d4204c85Sraf exit_critical(self);
636f841f6adSraf }
637