xref: /titanic_51/usr/src/lib/libc/port/rt/sched.c (revision 7257d1b4d25bfac0c802847390e98a464fd787ac)
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
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 *
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 *
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 *
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
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
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
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
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
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
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
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
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
479f841f6adSraf sched_yield(void)
480f841f6adSraf {
4818cd45542Sraf 	yield();
482f841f6adSraf 	return (0);
483f841f6adSraf }
484f841f6adSraf 
485f841f6adSraf int
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
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
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
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