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