xref: /titanic_50/usr/src/uts/common/disp/priocntl.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
28*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
29*7c478bd9Sstevel@tonic-gate 
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/signal.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/pcb.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/user.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/sysinfo.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/var.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/procset.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/inline.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/priocntl.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/disp.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/class.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/uadmin.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/policy.h>
56*7c478bd9Sstevel@tonic-gate 
57*7c478bd9Sstevel@tonic-gate /*
58*7c478bd9Sstevel@tonic-gate  * Structure used to pass arguments to the proccmp() function.
59*7c478bd9Sstevel@tonic-gate  * The arguments must be passed in a structure because proccmp()
60*7c478bd9Sstevel@tonic-gate  * is called indirectly through the dotoprocs() function which
61*7c478bd9Sstevel@tonic-gate  * will only pass through a single one word argument.
62*7c478bd9Sstevel@tonic-gate  */
63*7c478bd9Sstevel@tonic-gate struct pcmpargs {
64*7c478bd9Sstevel@tonic-gate 	id_t	*pcmp_cidp;
65*7c478bd9Sstevel@tonic-gate 	int	*pcmp_cntp;
66*7c478bd9Sstevel@tonic-gate 	kthread_id_t	*pcmp_retthreadp;
67*7c478bd9Sstevel@tonic-gate };
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate /*
70*7c478bd9Sstevel@tonic-gate  * Structure used to pass arguments to the setparms() function
71*7c478bd9Sstevel@tonic-gate  * which is called indirectly through dotoprocs().
72*7c478bd9Sstevel@tonic-gate  */
73*7c478bd9Sstevel@tonic-gate struct stprmargs {
74*7c478bd9Sstevel@tonic-gate 	struct pcparms	*stp_parmsp;	/* pointer to parameters */
75*7c478bd9Sstevel@tonic-gate 	int		stp_error;	/* some errors returned here */
76*7c478bd9Sstevel@tonic-gate };
77*7c478bd9Sstevel@tonic-gate 
78*7c478bd9Sstevel@tonic-gate #if defined(_SYSCALL32_IMPL) && _LONG_LONG_ALIGNMENT_32 == 4
79*7c478bd9Sstevel@tonic-gate /*
80*7c478bd9Sstevel@tonic-gate  * A vaparm_t is an int followed by a long long -- this packs differently
81*7c478bd9Sstevel@tonic-gate  * between the 64-bit kernel ABI and the 32-bit user ABI.
82*7c478bd9Sstevel@tonic-gate  */
83*7c478bd9Sstevel@tonic-gate static int
84*7c478bd9Sstevel@tonic-gate copyin_vaparms32(caddr_t arg, pc_vaparms_t *vap)
85*7c478bd9Sstevel@tonic-gate {
86*7c478bd9Sstevel@tonic-gate 	pc_vaparms32_t vaparms32;
87*7c478bd9Sstevel@tonic-gate 	pc_vaparm32_t *src;
88*7c478bd9Sstevel@tonic-gate 	pc_vaparm_t *dst;
89*7c478bd9Sstevel@tonic-gate 	uint_t cnt;
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate 	ASSERT(get_udatamodel() == DATAMODEL_ILP32);
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 	if (copyin(arg, &vaparms32, sizeof (vaparms32)))
94*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	vap->pc_vaparmscnt = vaparms32.pc_vaparmscnt;
97*7c478bd9Sstevel@tonic-gate 	if ((cnt = vaparms32.pc_vaparmscnt) > PC_VAPARMCNT)
98*7c478bd9Sstevel@tonic-gate 		cnt = PC_VAPARMCNT;
99*7c478bd9Sstevel@tonic-gate 	for (src = vaparms32.pc_parms, dst = vap->pc_parms;
100*7c478bd9Sstevel@tonic-gate 	    cnt--; src++, dst++) {
101*7c478bd9Sstevel@tonic-gate 		dst->pc_key = src->pc_key;
102*7c478bd9Sstevel@tonic-gate 		dst->pc_parm = src->pc_parm;
103*7c478bd9Sstevel@tonic-gate 	}
104*7c478bd9Sstevel@tonic-gate 	return (0);
105*7c478bd9Sstevel@tonic-gate }
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate #define	COPYIN_VAPARMS(arg, vap, size)	\
108*7c478bd9Sstevel@tonic-gate 	(get_udatamodel() == DATAMODEL_NATIVE ?	\
109*7c478bd9Sstevel@tonic-gate 	copyin(arg, vap, size) : copyin_vaparms32(arg, vap))
110*7c478bd9Sstevel@tonic-gate 
111*7c478bd9Sstevel@tonic-gate #else
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate #define	COPYIN_VAPARMS(arg, vap, size)	copyin(arg, vap, size)
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate #endif
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate static int donice(procset_t *, pcnice_t *);
118*7c478bd9Sstevel@tonic-gate static int proccmp(proc_t *, struct pcmpargs *);
119*7c478bd9Sstevel@tonic-gate static int setparms(proc_t *, struct stprmargs *);
120*7c478bd9Sstevel@tonic-gate extern int threadcmp(struct pcmpargs *, kthread_id_t);
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate /*
123*7c478bd9Sstevel@tonic-gate  * The priocntl system call.
124*7c478bd9Sstevel@tonic-gate  */
125*7c478bd9Sstevel@tonic-gate long
126*7c478bd9Sstevel@tonic-gate priocntlsys(int pc_version, procset_t *psp, int cmd, caddr_t arg, caddr_t arg2)
127*7c478bd9Sstevel@tonic-gate {
128*7c478bd9Sstevel@tonic-gate 	pcinfo_t		pcinfo;
129*7c478bd9Sstevel@tonic-gate 	pcparms_t		pcparms;
130*7c478bd9Sstevel@tonic-gate 	pcnice_t		pcnice;
131*7c478bd9Sstevel@tonic-gate 	pcadmin_t		pcadmin;
132*7c478bd9Sstevel@tonic-gate 	pcpri_t			pcpri;
133*7c478bd9Sstevel@tonic-gate 	procset_t		procset;
134*7c478bd9Sstevel@tonic-gate 	struct stprmargs	stprmargs;
135*7c478bd9Sstevel@tonic-gate 	struct pcmpargs		pcmpargs;
136*7c478bd9Sstevel@tonic-gate 	pc_vaparms_t		vaparms;
137*7c478bd9Sstevel@tonic-gate 	char			clname[PC_CLNMSZ];
138*7c478bd9Sstevel@tonic-gate 	int			count;
139*7c478bd9Sstevel@tonic-gate 	kthread_id_t		retthreadp;
140*7c478bd9Sstevel@tonic-gate 	proc_t			*initpp;
141*7c478bd9Sstevel@tonic-gate 	int			clnullflag;
142*7c478bd9Sstevel@tonic-gate 	int			error = 0;
143*7c478bd9Sstevel@tonic-gate 	int			error1 = 0;
144*7c478bd9Sstevel@tonic-gate 	int			rv = 0;
145*7c478bd9Sstevel@tonic-gate 	pid_t			saved_pid;
146*7c478bd9Sstevel@tonic-gate 	id_t			classid;
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	/*
149*7c478bd9Sstevel@tonic-gate 	 * First just check the version number. Right now there is only
150*7c478bd9Sstevel@tonic-gate 	 * one version we know about and support.  If we get some other
151*7c478bd9Sstevel@tonic-gate 	 * version number from the application it may be that the
152*7c478bd9Sstevel@tonic-gate 	 * application was built with some future version and is trying
153*7c478bd9Sstevel@tonic-gate 	 * to run on an old release of the system (that's us).  In any
154*7c478bd9Sstevel@tonic-gate 	 * case if we don't recognize the version number all we can do is
155*7c478bd9Sstevel@tonic-gate 	 * return error.
156*7c478bd9Sstevel@tonic-gate 	 */
157*7c478bd9Sstevel@tonic-gate 	if (pc_version != PC_VERSION)
158*7c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
161*7c478bd9Sstevel@tonic-gate 	case PC_GETCID:
162*7c478bd9Sstevel@tonic-gate 		/*
163*7c478bd9Sstevel@tonic-gate 		 * If the arg pointer is NULL, the user just wants to
164*7c478bd9Sstevel@tonic-gate 		 * know the number of classes. If non-NULL, the pointer
165*7c478bd9Sstevel@tonic-gate 		 * should point to a valid user pcinfo buffer.  In the
166*7c478bd9Sstevel@tonic-gate 		 * dynamic world we need to return the number of loaded
167*7c478bd9Sstevel@tonic-gate 		 * classes, not the max number of available classes that
168*7c478bd9Sstevel@tonic-gate 		 * can be loaded.
169*7c478bd9Sstevel@tonic-gate 		 */
170*7c478bd9Sstevel@tonic-gate 		if (arg == NULL) {
171*7c478bd9Sstevel@tonic-gate 			rv = loaded_classes;
172*7c478bd9Sstevel@tonic-gate 			break;
173*7c478bd9Sstevel@tonic-gate 		} else {
174*7c478bd9Sstevel@tonic-gate 			if (copyin(arg, &pcinfo, sizeof (pcinfo)))
175*7c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
176*7c478bd9Sstevel@tonic-gate 		}
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 		pcinfo.pc_clname[PC_CLNMSZ-1] = '\0';
179*7c478bd9Sstevel@tonic-gate 
180*7c478bd9Sstevel@tonic-gate 		/*
181*7c478bd9Sstevel@tonic-gate 		 * Get the class ID corresponding to user supplied name.
182*7c478bd9Sstevel@tonic-gate 		 */
183*7c478bd9Sstevel@tonic-gate 		error = getcid(pcinfo.pc_clname, &pcinfo.pc_cid);
184*7c478bd9Sstevel@tonic-gate 		if (error)
185*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 		/*
188*7c478bd9Sstevel@tonic-gate 		 * Can't get info about the sys class.
189*7c478bd9Sstevel@tonic-gate 		 */
190*7c478bd9Sstevel@tonic-gate 		if (pcinfo.pc_cid == 0)
191*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 		/*
194*7c478bd9Sstevel@tonic-gate 		 * Get the class specific information.
195*7c478bd9Sstevel@tonic-gate 		 * we MUST make sure that the class has not already
196*7c478bd9Sstevel@tonic-gate 		 * been unloaded before we try the CL_GETCLINFO.
197*7c478bd9Sstevel@tonic-gate 		 * If it has then we need to load it.
198*7c478bd9Sstevel@tonic-gate 		 */
199*7c478bd9Sstevel@tonic-gate 		error =
200*7c478bd9Sstevel@tonic-gate 		    scheduler_load(pcinfo.pc_clname, &sclass[pcinfo.pc_cid]);
201*7c478bd9Sstevel@tonic-gate 		if (error)
202*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
203*7c478bd9Sstevel@tonic-gate 		error = CL_GETCLINFO(&sclass[pcinfo.pc_cid], pcinfo.pc_clinfo);
204*7c478bd9Sstevel@tonic-gate 		if (error)
205*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 		if (copyout(&pcinfo, arg, sizeof (pcinfo)))
208*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 		rv = loaded_classes;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 		break;
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 	case PC_GETCLINFO:
215*7c478bd9Sstevel@tonic-gate 		/*
216*7c478bd9Sstevel@tonic-gate 		 * If the arg pointer is NULL, the user just wants to know
217*7c478bd9Sstevel@tonic-gate 		 * the number of classes. If non-NULL, the pointer should
218*7c478bd9Sstevel@tonic-gate 		 * point to a valid user pcinfo buffer.
219*7c478bd9Sstevel@tonic-gate 		 */
220*7c478bd9Sstevel@tonic-gate 		if (arg == NULL) {
221*7c478bd9Sstevel@tonic-gate 			rv = loaded_classes;
222*7c478bd9Sstevel@tonic-gate 			break;
223*7c478bd9Sstevel@tonic-gate 		} else {
224*7c478bd9Sstevel@tonic-gate 			if (copyin(arg, &pcinfo, sizeof (pcinfo)))
225*7c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
226*7c478bd9Sstevel@tonic-gate 		}
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate 		if (pcinfo.pc_cid >= loaded_classes || pcinfo.pc_cid < 1)
229*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 		(void) strncpy(pcinfo.pc_clname, sclass[pcinfo.pc_cid].cl_name,
232*7c478bd9Sstevel@tonic-gate 		    PC_CLNMSZ);
233*7c478bd9Sstevel@tonic-gate 
234*7c478bd9Sstevel@tonic-gate 		/*
235*7c478bd9Sstevel@tonic-gate 		 * Get the class specific information.  we MUST make sure
236*7c478bd9Sstevel@tonic-gate 		 * that the class has not already been unloaded before we
237*7c478bd9Sstevel@tonic-gate 		 * try the CL_GETCLINFO.  If it has then we need to load
238*7c478bd9Sstevel@tonic-gate 		 * it.
239*7c478bd9Sstevel@tonic-gate 		 */
240*7c478bd9Sstevel@tonic-gate 		error =
241*7c478bd9Sstevel@tonic-gate 		    scheduler_load(pcinfo.pc_clname, &sclass[pcinfo.pc_cid]);
242*7c478bd9Sstevel@tonic-gate 		if (error)
243*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
244*7c478bd9Sstevel@tonic-gate 		error = CL_GETCLINFO(&sclass[pcinfo.pc_cid], pcinfo.pc_clinfo);
245*7c478bd9Sstevel@tonic-gate 		if (error)
246*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 		if (copyout(&pcinfo, arg, sizeof (pcinfo)))
249*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 		rv = loaded_classes;
252*7c478bd9Sstevel@tonic-gate 		break;
253*7c478bd9Sstevel@tonic-gate 
254*7c478bd9Sstevel@tonic-gate 	case PC_SETPARMS:
255*7c478bd9Sstevel@tonic-gate 	case PC_SETXPARMS:
256*7c478bd9Sstevel@tonic-gate 		/*
257*7c478bd9Sstevel@tonic-gate 		 * First check the validity of the parameters we got from
258*7c478bd9Sstevel@tonic-gate 		 * the user.  We don't do any permissions checking here
259*7c478bd9Sstevel@tonic-gate 		 * because it's done on a per thread basis by parmsset().
260*7c478bd9Sstevel@tonic-gate 		 */
261*7c478bd9Sstevel@tonic-gate 		if (cmd == PC_SETPARMS) {
262*7c478bd9Sstevel@tonic-gate 			if (copyin(arg, &pcparms, sizeof (pcparms)))
263*7c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
264*7c478bd9Sstevel@tonic-gate 
265*7c478bd9Sstevel@tonic-gate 			error = parmsin(&pcparms, NULL);
266*7c478bd9Sstevel@tonic-gate 		} else {
267*7c478bd9Sstevel@tonic-gate 			if (copyin(arg, clname, PC_CLNMSZ) ||
268*7c478bd9Sstevel@tonic-gate 			    COPYIN_VAPARMS(arg2, &vaparms, sizeof (vaparms)))
269*7c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
270*7c478bd9Sstevel@tonic-gate 			clname[PC_CLNMSZ-1] = '\0';
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate 			if (getcid(clname, &pcparms.pc_cid))
273*7c478bd9Sstevel@tonic-gate 				return (set_errno(EINVAL));
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 			error = parmsin(&pcparms, &vaparms);
276*7c478bd9Sstevel@tonic-gate 		}
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate 		if (error)
279*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 		/*
282*7c478bd9Sstevel@tonic-gate 		 * Get the procset from the user.
283*7c478bd9Sstevel@tonic-gate 		 */
284*7c478bd9Sstevel@tonic-gate 		if (copyin(psp, &procset, sizeof (procset)))
285*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 		/*
288*7c478bd9Sstevel@tonic-gate 		 * For performance we do a quick check here to catch
289*7c478bd9Sstevel@tonic-gate 		 * common cases where the current thread is the only one
290*7c478bd9Sstevel@tonic-gate 		 * in the set.  In such cases we can call parmsset()
291*7c478bd9Sstevel@tonic-gate 		 * directly, avoiding the relatively lengthy path through
292*7c478bd9Sstevel@tonic-gate 		 * dotoprocs().  The underlying classes expect pidlock to
293*7c478bd9Sstevel@tonic-gate 		 * be held.
294*7c478bd9Sstevel@tonic-gate 		 */
295*7c478bd9Sstevel@tonic-gate 		if (cur_inset_only(&procset) == B_TRUE) {
296*7c478bd9Sstevel@tonic-gate 			/* do a single LWP */
297*7c478bd9Sstevel@tonic-gate 			if ((procset.p_lidtype == P_LWPID) ||
298*7c478bd9Sstevel@tonic-gate 			    (procset.p_ridtype == P_LWPID)) {
299*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pidlock);
300*7c478bd9Sstevel@tonic-gate 				mutex_enter(&curproc->p_lock);
301*7c478bd9Sstevel@tonic-gate 				error = parmsset(&pcparms, curthread);
302*7c478bd9Sstevel@tonic-gate 				mutex_exit(&curproc->p_lock);
303*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
304*7c478bd9Sstevel@tonic-gate 			} else {
305*7c478bd9Sstevel@tonic-gate 				/* do the entire process otherwise */
306*7c478bd9Sstevel@tonic-gate 				stprmargs.stp_parmsp = &pcparms;
307*7c478bd9Sstevel@tonic-gate 				stprmargs.stp_error = 0;
308*7c478bd9Sstevel@tonic-gate 				mutex_enter(&pidlock);
309*7c478bd9Sstevel@tonic-gate 				error = setparms(curproc, &stprmargs);
310*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pidlock);
311*7c478bd9Sstevel@tonic-gate 				if (error == 0 && stprmargs.stp_error != 0)
312*7c478bd9Sstevel@tonic-gate 					error = stprmargs.stp_error;
313*7c478bd9Sstevel@tonic-gate 			}
314*7c478bd9Sstevel@tonic-gate 			if (error)
315*7c478bd9Sstevel@tonic-gate 				return (set_errno(error));
316*7c478bd9Sstevel@tonic-gate 		} else {
317*7c478bd9Sstevel@tonic-gate 			stprmargs.stp_parmsp = &pcparms;
318*7c478bd9Sstevel@tonic-gate 			stprmargs.stp_error = 0;
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 			error1 = error = ESRCH;
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 			/*
323*7c478bd9Sstevel@tonic-gate 			 * The dotoprocs() call below will cause
324*7c478bd9Sstevel@tonic-gate 			 * setparms() to be called for each thread in the
325*7c478bd9Sstevel@tonic-gate 			 * specified procset. setparms() will in turn
326*7c478bd9Sstevel@tonic-gate 			 * call parmsset() (which does the real work).
327*7c478bd9Sstevel@tonic-gate 			 */
328*7c478bd9Sstevel@tonic-gate 			if ((procset.p_lidtype != P_LWPID) ||
329*7c478bd9Sstevel@tonic-gate 				(procset.p_ridtype != P_LWPID)) {
330*7c478bd9Sstevel@tonic-gate 				error1 = dotoprocs(&procset, setparms,
331*7c478bd9Sstevel@tonic-gate 				    (char *)&stprmargs);
332*7c478bd9Sstevel@tonic-gate 			}
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 			/*
335*7c478bd9Sstevel@tonic-gate 			 * take care of the case when any of the
336*7c478bd9Sstevel@tonic-gate 			 * operands happen to be LWP's
337*7c478bd9Sstevel@tonic-gate 			 */
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 			if ((procset.p_lidtype == P_LWPID) ||
340*7c478bd9Sstevel@tonic-gate 			    (procset.p_ridtype == P_LWPID)) {
341*7c478bd9Sstevel@tonic-gate 				error = dotolwp(&procset, parmsset,
342*7c478bd9Sstevel@tonic-gate 				    (char *)&pcparms);
343*7c478bd9Sstevel@tonic-gate 				/*
344*7c478bd9Sstevel@tonic-gate 				 * Dotolwp() returns with p_lock held.
345*7c478bd9Sstevel@tonic-gate 				 * This is required for the GETPARMS case
346*7c478bd9Sstevel@tonic-gate 				 * below. So, here we just release the
347*7c478bd9Sstevel@tonic-gate 				 * p_lock.
348*7c478bd9Sstevel@tonic-gate 				 */
349*7c478bd9Sstevel@tonic-gate 				if (MUTEX_HELD(&curproc->p_lock))
350*7c478bd9Sstevel@tonic-gate 					mutex_exit(&curproc->p_lock);
351*7c478bd9Sstevel@tonic-gate 			}
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 			/*
354*7c478bd9Sstevel@tonic-gate 			 * If setparms() encounters a permissions error
355*7c478bd9Sstevel@tonic-gate 			 * for one or more of the threads it returns
356*7c478bd9Sstevel@tonic-gate 			 * EPERM in stp_error so dotoprocs() will
357*7c478bd9Sstevel@tonic-gate 			 * continue through the thread set.  If
358*7c478bd9Sstevel@tonic-gate 			 * dotoprocs() returned an error above, it was
359*7c478bd9Sstevel@tonic-gate 			 * more serious than permissions and dotoprocs
360*7c478bd9Sstevel@tonic-gate 			 * quit when the error was encountered.  We
361*7c478bd9Sstevel@tonic-gate 			 * return the more serious error if there was
362*7c478bd9Sstevel@tonic-gate 			 * one, otherwise we return EPERM if we got that
363*7c478bd9Sstevel@tonic-gate 			 * back.
364*7c478bd9Sstevel@tonic-gate 			 */
365*7c478bd9Sstevel@tonic-gate 			if (error1 != ESRCH)
366*7c478bd9Sstevel@tonic-gate 				error = error1;
367*7c478bd9Sstevel@tonic-gate 			if (error == 0 && stprmargs.stp_error != 0)
368*7c478bd9Sstevel@tonic-gate 				error = stprmargs.stp_error;
369*7c478bd9Sstevel@tonic-gate 		}
370*7c478bd9Sstevel@tonic-gate 		break;
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate 	case PC_GETPARMS:
373*7c478bd9Sstevel@tonic-gate 	case PC_GETXPARMS:
374*7c478bd9Sstevel@tonic-gate 		if (cmd == PC_GETPARMS) {
375*7c478bd9Sstevel@tonic-gate 			if (copyin(arg, &pcparms, sizeof (pcparms)))
376*7c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
377*7c478bd9Sstevel@tonic-gate 		} else {
378*7c478bd9Sstevel@tonic-gate 			if (arg != NULL) {
379*7c478bd9Sstevel@tonic-gate 				if (copyin(arg, clname, PC_CLNMSZ))
380*7c478bd9Sstevel@tonic-gate 					return (set_errno(EFAULT));
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 				clname[PC_CLNMSZ-1] = '\0';
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 				if (getcid(clname, &pcparms.pc_cid))
385*7c478bd9Sstevel@tonic-gate 					return (set_errno(EINVAL));
386*7c478bd9Sstevel@tonic-gate 			} else
387*7c478bd9Sstevel@tonic-gate 				pcparms.pc_cid = PC_CLNULL;
388*7c478bd9Sstevel@tonic-gate 			if (COPYIN_VAPARMS(arg2, &vaparms, sizeof (vaparms)))
389*7c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
390*7c478bd9Sstevel@tonic-gate 		}
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate 		if (pcparms.pc_cid >= loaded_classes ||
393*7c478bd9Sstevel@tonic-gate 		    (pcparms.pc_cid < 1 && pcparms.pc_cid != PC_CLNULL))
394*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
395*7c478bd9Sstevel@tonic-gate 
396*7c478bd9Sstevel@tonic-gate 		if (copyin(psp, &procset, sizeof (procset)))
397*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
398*7c478bd9Sstevel@tonic-gate 
399*7c478bd9Sstevel@tonic-gate 		/*
400*7c478bd9Sstevel@tonic-gate 		 * Check to see if the current thread is the only one
401*7c478bd9Sstevel@tonic-gate 		 * in the set. If not we must go through the whole set
402*7c478bd9Sstevel@tonic-gate 		 * to select a thread.
403*7c478bd9Sstevel@tonic-gate 		 */
404*7c478bd9Sstevel@tonic-gate 		if (cur_inset_only(&procset) == B_TRUE) {
405*7c478bd9Sstevel@tonic-gate 			/* do a single LWP */
406*7c478bd9Sstevel@tonic-gate 			if ((procset.p_lidtype == P_LWPID) ||
407*7c478bd9Sstevel@tonic-gate 			    (procset.p_ridtype == P_LWPID)) {
408*7c478bd9Sstevel@tonic-gate 				if (pcparms.pc_cid != PC_CLNULL &&
409*7c478bd9Sstevel@tonic-gate 				    pcparms.pc_cid != curthread->t_cid) {
410*7c478bd9Sstevel@tonic-gate 					/*
411*7c478bd9Sstevel@tonic-gate 					 * Specified thread not in
412*7c478bd9Sstevel@tonic-gate 					 * specified class.
413*7c478bd9Sstevel@tonic-gate 					 */
414*7c478bd9Sstevel@tonic-gate 					return (set_errno(ESRCH));
415*7c478bd9Sstevel@tonic-gate 				} else {
416*7c478bd9Sstevel@tonic-gate 					mutex_enter(&curproc->p_lock);
417*7c478bd9Sstevel@tonic-gate 					retthreadp = curthread;
418*7c478bd9Sstevel@tonic-gate 				}
419*7c478bd9Sstevel@tonic-gate 			} else {
420*7c478bd9Sstevel@tonic-gate 				count = 0;
421*7c478bd9Sstevel@tonic-gate 				retthreadp = NULL;
422*7c478bd9Sstevel@tonic-gate 				pcmpargs.pcmp_cidp = &pcparms.pc_cid;
423*7c478bd9Sstevel@tonic-gate 				pcmpargs.pcmp_cntp = &count;
424*7c478bd9Sstevel@tonic-gate 				pcmpargs.pcmp_retthreadp = &retthreadp;
425*7c478bd9Sstevel@tonic-gate 				/*
426*7c478bd9Sstevel@tonic-gate 				 * Specified thread not in specified class.
427*7c478bd9Sstevel@tonic-gate 				 */
428*7c478bd9Sstevel@tonic-gate 				if (pcparms.pc_cid != PC_CLNULL &&
429*7c478bd9Sstevel@tonic-gate 				    pcparms.pc_cid != curthread->t_cid)
430*7c478bd9Sstevel@tonic-gate 					return (set_errno(ESRCH));
431*7c478bd9Sstevel@tonic-gate 				error = proccmp(curproc, &pcmpargs);
432*7c478bd9Sstevel@tonic-gate 				if (error) {
433*7c478bd9Sstevel@tonic-gate 					if (retthreadp != NULL)
434*7c478bd9Sstevel@tonic-gate 						mutex_exit(&(curproc->p_lock));
435*7c478bd9Sstevel@tonic-gate 					return (set_errno(error));
436*7c478bd9Sstevel@tonic-gate 				}
437*7c478bd9Sstevel@tonic-gate 			}
438*7c478bd9Sstevel@tonic-gate 		} else {
439*7c478bd9Sstevel@tonic-gate 			/*
440*7c478bd9Sstevel@tonic-gate 			 * get initpp early to avoid lock ordering problems
441*7c478bd9Sstevel@tonic-gate 			 * (we cannot get pidlock while holding any p_lock).
442*7c478bd9Sstevel@tonic-gate 			 */
443*7c478bd9Sstevel@tonic-gate 			mutex_enter(&pidlock);
444*7c478bd9Sstevel@tonic-gate 			initpp = prfind(P_INITPID);
445*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pidlock);
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 			/*
448*7c478bd9Sstevel@tonic-gate 			 * Select the thread (from the set) whose
449*7c478bd9Sstevel@tonic-gate 			 * parameters we are going to return.  First we
450*7c478bd9Sstevel@tonic-gate 			 * set up some locations for return values, then
451*7c478bd9Sstevel@tonic-gate 			 * we call proccmp() indirectly through
452*7c478bd9Sstevel@tonic-gate 			 * dotoprocs().  proccmp() will call a class
453*7c478bd9Sstevel@tonic-gate 			 * specific routine which actually does the
454*7c478bd9Sstevel@tonic-gate 			 * selection.  To understand how this works take
455*7c478bd9Sstevel@tonic-gate 			 * a careful look at the code below, the
456*7c478bd9Sstevel@tonic-gate 			 * dotoprocs() function, the proccmp() function,
457*7c478bd9Sstevel@tonic-gate 			 * and the class specific cl_proccmp() functions.
458*7c478bd9Sstevel@tonic-gate 			 */
459*7c478bd9Sstevel@tonic-gate 			if (pcparms.pc_cid == PC_CLNULL)
460*7c478bd9Sstevel@tonic-gate 				clnullflag = 1;
461*7c478bd9Sstevel@tonic-gate 			else
462*7c478bd9Sstevel@tonic-gate 				clnullflag = 0;
463*7c478bd9Sstevel@tonic-gate 			count = 0;
464*7c478bd9Sstevel@tonic-gate 			retthreadp = NULL;
465*7c478bd9Sstevel@tonic-gate 			pcmpargs.pcmp_cidp = &pcparms.pc_cid;
466*7c478bd9Sstevel@tonic-gate 			pcmpargs.pcmp_cntp = &count;
467*7c478bd9Sstevel@tonic-gate 			pcmpargs.pcmp_retthreadp = &retthreadp;
468*7c478bd9Sstevel@tonic-gate 			error1 = error = ESRCH;
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 			if ((procset.p_lidtype != P_LWPID) ||
471*7c478bd9Sstevel@tonic-gate 			    (procset.p_ridtype != P_LWPID)) {
472*7c478bd9Sstevel@tonic-gate 				error1 = dotoprocs(&procset, proccmp,
473*7c478bd9Sstevel@tonic-gate 				    (char *)&pcmpargs);
474*7c478bd9Sstevel@tonic-gate 			}
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 			/*
477*7c478bd9Sstevel@tonic-gate 			 * take care of combination of LWP and process
478*7c478bd9Sstevel@tonic-gate 			 * set case in a procset
479*7c478bd9Sstevel@tonic-gate 			 */
480*7c478bd9Sstevel@tonic-gate 			if ((procset.p_lidtype == P_LWPID) ||
481*7c478bd9Sstevel@tonic-gate 			    (procset.p_ridtype == P_LWPID)) {
482*7c478bd9Sstevel@tonic-gate 				error = dotolwp(&procset, threadcmp,
483*7c478bd9Sstevel@tonic-gate 				    (char *)&pcmpargs);
484*7c478bd9Sstevel@tonic-gate 			}
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 			/*
487*7c478bd9Sstevel@tonic-gate 			 * Both proccmp() and threadcmp() return with the
488*7c478bd9Sstevel@tonic-gate 			 * p_lock held for the ttoproc(retthreadp). This
489*7c478bd9Sstevel@tonic-gate 			 * is required to make sure that the process we
490*7c478bd9Sstevel@tonic-gate 			 * chose as the winner doesn't go away
491*7c478bd9Sstevel@tonic-gate 			 * i.e. retthreadp has to be a valid pointer.
492*7c478bd9Sstevel@tonic-gate 			 *
493*7c478bd9Sstevel@tonic-gate 			 * The case below can only happen if the thread
494*7c478bd9Sstevel@tonic-gate 			 * with the highest priority was not in your
495*7c478bd9Sstevel@tonic-gate 			 * process.  In that case, dotolwp will return
496*7c478bd9Sstevel@tonic-gate 			 * holding p_lock for both your process as well
497*7c478bd9Sstevel@tonic-gate 			 * as the process in which retthreadp is a
498*7c478bd9Sstevel@tonic-gate 			 * thread.
499*7c478bd9Sstevel@tonic-gate 			 */
500*7c478bd9Sstevel@tonic-gate 			if ((retthreadp != NULL) &&
501*7c478bd9Sstevel@tonic-gate 			    (ttoproc(retthreadp) != curproc) &&
502*7c478bd9Sstevel@tonic-gate 			    MUTEX_HELD(&(curproc)->p_lock))
503*7c478bd9Sstevel@tonic-gate 				mutex_exit(&(curproc)->p_lock);
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 			ASSERT(retthreadp == NULL ||
506*7c478bd9Sstevel@tonic-gate 			    MUTEX_HELD(&(ttoproc(retthreadp)->p_lock)));
507*7c478bd9Sstevel@tonic-gate 			if (error1 != ESRCH)
508*7c478bd9Sstevel@tonic-gate 				error = error1;
509*7c478bd9Sstevel@tonic-gate 			if (error) {
510*7c478bd9Sstevel@tonic-gate 				if (retthreadp != NULL)
511*7c478bd9Sstevel@tonic-gate 				    mutex_exit(&(ttoproc(retthreadp)->p_lock));
512*7c478bd9Sstevel@tonic-gate 				ASSERT(MUTEX_NOT_HELD(&(curproc)->p_lock));
513*7c478bd9Sstevel@tonic-gate 				return (set_errno(error));
514*7c478bd9Sstevel@tonic-gate 			}
515*7c478bd9Sstevel@tonic-gate 			/*
516*7c478bd9Sstevel@tonic-gate 			 * dotoprocs() ignores the init process if it is
517*7c478bd9Sstevel@tonic-gate 			 * in the set, unless it was the only process found.
518*7c478bd9Sstevel@tonic-gate 			 * Since we are getting parameters here rather than
519*7c478bd9Sstevel@tonic-gate 			 * setting them, we want to make sure init is not
520*7c478bd9Sstevel@tonic-gate 			 * excluded if it is in the set.
521*7c478bd9Sstevel@tonic-gate 			 */
522*7c478bd9Sstevel@tonic-gate 			if (initpp != NULL &&
523*7c478bd9Sstevel@tonic-gate 			    procinset(initpp, &procset) &&
524*7c478bd9Sstevel@tonic-gate 			    (retthreadp != NULL) &&
525*7c478bd9Sstevel@tonic-gate 			    ttoproc(retthreadp) != initpp)
526*7c478bd9Sstevel@tonic-gate 				(void) proccmp(initpp, &pcmpargs);
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 			/*
529*7c478bd9Sstevel@tonic-gate 			 * If dotoprocs returned success it found at least
530*7c478bd9Sstevel@tonic-gate 			 * one thread in the set.  If proccmp() failed to
531*7c478bd9Sstevel@tonic-gate 			 * select a thread it is because the user specified
532*7c478bd9Sstevel@tonic-gate 			 * a class and none of the threads in the set
533*7c478bd9Sstevel@tonic-gate 			 * belonged to that class, or because the process
534*7c478bd9Sstevel@tonic-gate 			 * specified was in the middle of exiting and had
535*7c478bd9Sstevel@tonic-gate 			 * cleared its thread list.
536*7c478bd9Sstevel@tonic-gate 			 */
537*7c478bd9Sstevel@tonic-gate 			if (retthreadp == NULL) {
538*7c478bd9Sstevel@tonic-gate 				/*
539*7c478bd9Sstevel@tonic-gate 				 * Might be here and still holding p_lock
540*7c478bd9Sstevel@tonic-gate 				 * if we did a dotolwp on an lwp that
541*7c478bd9Sstevel@tonic-gate 				 * existed but was in the wrong class.
542*7c478bd9Sstevel@tonic-gate 				 */
543*7c478bd9Sstevel@tonic-gate 				if (MUTEX_HELD(&(curproc)->p_lock))
544*7c478bd9Sstevel@tonic-gate 					mutex_exit(&(curproc)->p_lock);
545*7c478bd9Sstevel@tonic-gate 				return (set_errno(ESRCH));
546*7c478bd9Sstevel@tonic-gate 			}
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 			/*
549*7c478bd9Sstevel@tonic-gate 			 * User can only use PC_CLNULL with one thread in set.
550*7c478bd9Sstevel@tonic-gate 			 */
551*7c478bd9Sstevel@tonic-gate 			if (clnullflag && count > 1) {
552*7c478bd9Sstevel@tonic-gate 				if (retthreadp != NULL)
553*7c478bd9Sstevel@tonic-gate 					mutex_exit(
554*7c478bd9Sstevel@tonic-gate 					    &(ttoproc(retthreadp)->p_lock));
555*7c478bd9Sstevel@tonic-gate 				ASSERT(MUTEX_NOT_HELD(&(curproc)->p_lock));
556*7c478bd9Sstevel@tonic-gate 				return (set_errno(EINVAL));
557*7c478bd9Sstevel@tonic-gate 			}
558*7c478bd9Sstevel@tonic-gate 		}
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 		ASSERT(retthreadp == NULL ||
561*7c478bd9Sstevel@tonic-gate 		    MUTEX_HELD(&(ttoproc(retthreadp)->p_lock)));
562*7c478bd9Sstevel@tonic-gate 		/*
563*7c478bd9Sstevel@tonic-gate 		 * It is possible to have retthreadp == NULL. Proccmp()
564*7c478bd9Sstevel@tonic-gate 		 * in the rare case (p_tlist == NULL) could return without
565*7c478bd9Sstevel@tonic-gate 		 * setting a value for retthreadp.
566*7c478bd9Sstevel@tonic-gate 		 */
567*7c478bd9Sstevel@tonic-gate 		if (retthreadp == NULL) {
568*7c478bd9Sstevel@tonic-gate 			ASSERT(MUTEX_NOT_HELD(&(curproc)->p_lock));
569*7c478bd9Sstevel@tonic-gate 			return (set_errno(ESRCH));
570*7c478bd9Sstevel@tonic-gate 		}
571*7c478bd9Sstevel@tonic-gate 		/*
572*7c478bd9Sstevel@tonic-gate 		 * We've selected a thread so now get the parameters.
573*7c478bd9Sstevel@tonic-gate 		 */
574*7c478bd9Sstevel@tonic-gate 		parmsget(retthreadp, &pcparms);
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 		/*
577*7c478bd9Sstevel@tonic-gate 		 * Prepare to return parameters to the user
578*7c478bd9Sstevel@tonic-gate 		 */
579*7c478bd9Sstevel@tonic-gate 		error = parmsout(&pcparms,
580*7c478bd9Sstevel@tonic-gate 		    (cmd == PC_GETPARMS ? NULL : &vaparms));
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 		/*
583*7c478bd9Sstevel@tonic-gate 		 * Save pid of selected thread before dropping p_lock.
584*7c478bd9Sstevel@tonic-gate 		 */
585*7c478bd9Sstevel@tonic-gate 		saved_pid = ttoproc(retthreadp)->p_pid;
586*7c478bd9Sstevel@tonic-gate 		mutex_exit(&(ttoproc(retthreadp)->p_lock));
587*7c478bd9Sstevel@tonic-gate 		ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate 		if (error)
590*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
591*7c478bd9Sstevel@tonic-gate 
592*7c478bd9Sstevel@tonic-gate 		if (cmd == PC_GETPARMS) {
593*7c478bd9Sstevel@tonic-gate 			if (copyout(&pcparms, arg, sizeof (pcparms)))
594*7c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
595*7c478bd9Sstevel@tonic-gate 		} else if ((error = vaparmsout(arg, &pcparms, &vaparms)) != 0)
596*7c478bd9Sstevel@tonic-gate 			return (set_errno(error));
597*7c478bd9Sstevel@tonic-gate 
598*7c478bd9Sstevel@tonic-gate 		/*
599*7c478bd9Sstevel@tonic-gate 		 * And finally, return the pid of the selected thread.
600*7c478bd9Sstevel@tonic-gate 		 */
601*7c478bd9Sstevel@tonic-gate 		rv = saved_pid;
602*7c478bd9Sstevel@tonic-gate 		break;
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	case PC_ADMIN:
605*7c478bd9Sstevel@tonic-gate 		if (get_udatamodel() == DATAMODEL_NATIVE) {
606*7c478bd9Sstevel@tonic-gate 			if (copyin(arg, &pcadmin, sizeof (pcadmin_t)))
607*7c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
608*7c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL
609*7c478bd9Sstevel@tonic-gate 		} else {
610*7c478bd9Sstevel@tonic-gate 			/* pcadmin struct from ILP32 callers */
611*7c478bd9Sstevel@tonic-gate 			pcadmin32_t pcadmin32;
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 			if (copyin(arg, &pcadmin32, sizeof (pcadmin32_t)))
614*7c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
615*7c478bd9Sstevel@tonic-gate 			pcadmin.pc_cid = pcadmin32.pc_cid;
616*7c478bd9Sstevel@tonic-gate 			pcadmin.pc_cladmin = (caddr_t)(uintptr_t)
617*7c478bd9Sstevel@tonic-gate 			    pcadmin32.pc_cladmin;
618*7c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */
619*7c478bd9Sstevel@tonic-gate 		}
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 		if (pcadmin.pc_cid >= loaded_classes ||
622*7c478bd9Sstevel@tonic-gate 		    pcadmin.pc_cid < 1)
623*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 		/*
626*7c478bd9Sstevel@tonic-gate 		 * Have the class do whatever the user is requesting.
627*7c478bd9Sstevel@tonic-gate 		 */
628*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ualock);
629*7c478bd9Sstevel@tonic-gate 		error = CL_ADMIN(&sclass[pcadmin.pc_cid], pcadmin.pc_cladmin,
630*7c478bd9Sstevel@tonic-gate 				CRED());
631*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ualock);
632*7c478bd9Sstevel@tonic-gate 		break;
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 	case PC_GETPRIRANGE:
635*7c478bd9Sstevel@tonic-gate 		if (copyin(arg, &pcpri, sizeof (pcpri_t)))
636*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 		if (pcpri.pc_cid >= loaded_classes || pcpri.pc_cid < 0)
639*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 		error = CL_GETCLPRI(&sclass[pcpri.pc_cid], &pcpri);
642*7c478bd9Sstevel@tonic-gate 		if (!error) {
643*7c478bd9Sstevel@tonic-gate 			if (copyout(&pcpri, arg, sizeof (pcpri)))
644*7c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
645*7c478bd9Sstevel@tonic-gate 		}
646*7c478bd9Sstevel@tonic-gate 		break;
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate 	case PC_DONICE:
649*7c478bd9Sstevel@tonic-gate 		/*
650*7c478bd9Sstevel@tonic-gate 		 * Get pcnice and procset structures from the user.
651*7c478bd9Sstevel@tonic-gate 		 */
652*7c478bd9Sstevel@tonic-gate 		if (copyin(arg, &pcnice, sizeof (pcnice)) ||
653*7c478bd9Sstevel@tonic-gate 		    copyin(psp, &procset, sizeof (procset)))
654*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 		error = donice(&procset, &pcnice);
657*7c478bd9Sstevel@tonic-gate 
658*7c478bd9Sstevel@tonic-gate 		if (!error && (pcnice.pc_op == PC_GETNICE)) {
659*7c478bd9Sstevel@tonic-gate 			if (copyout(&pcnice, arg, sizeof (pcnice)))
660*7c478bd9Sstevel@tonic-gate 				return (set_errno(EFAULT));
661*7c478bd9Sstevel@tonic-gate 		}
662*7c478bd9Sstevel@tonic-gate 		break;
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	case PC_SETDFLCL:
665*7c478bd9Sstevel@tonic-gate 		if (secpolicy_dispadm(CRED()) != 0)
666*7c478bd9Sstevel@tonic-gate 			return (set_errno(EPERM));
667*7c478bd9Sstevel@tonic-gate 
668*7c478bd9Sstevel@tonic-gate 		if (copyin(arg, (caddr_t)clname, PC_CLNMSZ) != 0)
669*7c478bd9Sstevel@tonic-gate 			return (set_errno(EFAULT));
670*7c478bd9Sstevel@tonic-gate 		clname[PC_CLNMSZ-1] = '\0';
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 		if (getcid(clname, &classid) != 0)
673*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
674*7c478bd9Sstevel@tonic-gate 		if (classid == syscid)
675*7c478bd9Sstevel@tonic-gate 			return (set_errno(EINVAL));
676*7c478bd9Sstevel@tonic-gate 		defaultcid = classid;
677*7c478bd9Sstevel@tonic-gate 		ASSERT(defaultcid > 0 && defaultcid < loaded_classes);
678*7c478bd9Sstevel@tonic-gate 		break;
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate 	default:
681*7c478bd9Sstevel@tonic-gate 		error = EINVAL;
682*7c478bd9Sstevel@tonic-gate 		break;
683*7c478bd9Sstevel@tonic-gate 	}
684*7c478bd9Sstevel@tonic-gate 	return (error ? (set_errno(error)) : rv);
685*7c478bd9Sstevel@tonic-gate }
686*7c478bd9Sstevel@tonic-gate 
687*7c478bd9Sstevel@tonic-gate 
688*7c478bd9Sstevel@tonic-gate /*
689*7c478bd9Sstevel@tonic-gate  * The proccmp() function is part of the implementation of the
690*7c478bd9Sstevel@tonic-gate  * PC_GETPARMS command of the priocntl system call.  This function works
691*7c478bd9Sstevel@tonic-gate  * with the system call code and with the class specific cl_globpri()
692*7c478bd9Sstevel@tonic-gate  * function to select one thread from a specified procset based on class
693*7c478bd9Sstevel@tonic-gate  * specific criteria. proccmp() is called indirectly from the priocntl
694*7c478bd9Sstevel@tonic-gate  * code through the dotoprocs function.  Basic strategy is dotoprocs()
695*7c478bd9Sstevel@tonic-gate  * calls us once for each thread in the set.  We in turn call the class
696*7c478bd9Sstevel@tonic-gate  * specific function to compare the current thread from dotoprocs to the
697*7c478bd9Sstevel@tonic-gate  * "best" (according to the class criteria) found so far.  We keep the
698*7c478bd9Sstevel@tonic-gate  * "best" thread in *pcmp_retthreadp.
699*7c478bd9Sstevel@tonic-gate  */
700*7c478bd9Sstevel@tonic-gate static int
701*7c478bd9Sstevel@tonic-gate proccmp(proc_t *pp, struct pcmpargs *argp)
702*7c478bd9Sstevel@tonic-gate {
703*7c478bd9Sstevel@tonic-gate 	kthread_id_t	tx, ty;
704*7c478bd9Sstevel@tonic-gate 	int		last_pri = -1;
705*7c478bd9Sstevel@tonic-gate 	int		tx_pri;
706*7c478bd9Sstevel@tonic-gate 	int		found = 0;
707*7c478bd9Sstevel@tonic-gate 
708*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pp->p_lock);
709*7c478bd9Sstevel@tonic-gate 
710*7c478bd9Sstevel@tonic-gate 	if (pp->p_tlist == NULL) {
711*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pp->p_lock);
712*7c478bd9Sstevel@tonic-gate 		return (0);
713*7c478bd9Sstevel@tonic-gate 	}
714*7c478bd9Sstevel@tonic-gate 	(*argp->pcmp_cntp)++;	/* Increment count of procs in the set */
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	if (*argp->pcmp_cidp == PC_CLNULL) {
717*7c478bd9Sstevel@tonic-gate 		/*
718*7c478bd9Sstevel@tonic-gate 		 * If no cid is specified, then lets just pick the first one.
719*7c478bd9Sstevel@tonic-gate 		 * It doesn't matter because if the number of processes in the
720*7c478bd9Sstevel@tonic-gate 		 * set are more than 1, then we return EINVAL in priocntlsys.
721*7c478bd9Sstevel@tonic-gate 		 */
722*7c478bd9Sstevel@tonic-gate 		*argp->pcmp_cidp = pp->p_tlist->t_cid;
723*7c478bd9Sstevel@tonic-gate 	}
724*7c478bd9Sstevel@tonic-gate 	ty = tx = pp->p_tlist;
725*7c478bd9Sstevel@tonic-gate 	do {
726*7c478bd9Sstevel@tonic-gate 		if (tx->t_cid == *argp->pcmp_cidp) {
727*7c478bd9Sstevel@tonic-gate 			/*
728*7c478bd9Sstevel@tonic-gate 			 * We found one which matches the required cid.
729*7c478bd9Sstevel@tonic-gate 			 */
730*7c478bd9Sstevel@tonic-gate 			found = 1;
731*7c478bd9Sstevel@tonic-gate 			if ((tx_pri = CL_GLOBPRI(tx)) > last_pri) {
732*7c478bd9Sstevel@tonic-gate 				last_pri = tx_pri;
733*7c478bd9Sstevel@tonic-gate 				ty = tx;
734*7c478bd9Sstevel@tonic-gate 			}
735*7c478bd9Sstevel@tonic-gate 		}
736*7c478bd9Sstevel@tonic-gate 	} while ((tx = tx->t_forw) != pp->p_tlist);
737*7c478bd9Sstevel@tonic-gate 	if (found) {
738*7c478bd9Sstevel@tonic-gate 		if (*argp->pcmp_retthreadp == NULL) {
739*7c478bd9Sstevel@tonic-gate 			/*
740*7c478bd9Sstevel@tonic-gate 			 * First time through for this set.
741*7c478bd9Sstevel@tonic-gate 			 * keep the mutex held. He might be the one!
742*7c478bd9Sstevel@tonic-gate 			 */
743*7c478bd9Sstevel@tonic-gate 			*argp->pcmp_retthreadp = ty;
744*7c478bd9Sstevel@tonic-gate 		} else {
745*7c478bd9Sstevel@tonic-gate 			tx = *argp->pcmp_retthreadp;
746*7c478bd9Sstevel@tonic-gate 			if (CL_GLOBPRI(ty) <= CL_GLOBPRI(tx)) {
747*7c478bd9Sstevel@tonic-gate 				mutex_exit(&pp->p_lock);
748*7c478bd9Sstevel@tonic-gate 			} else {
749*7c478bd9Sstevel@tonic-gate 				mutex_exit(&(ttoproc(tx)->p_lock));
750*7c478bd9Sstevel@tonic-gate 				*argp->pcmp_retthreadp = ty;
751*7c478bd9Sstevel@tonic-gate 			}
752*7c478bd9Sstevel@tonic-gate 		}
753*7c478bd9Sstevel@tonic-gate 	} else {
754*7c478bd9Sstevel@tonic-gate 		/*
755*7c478bd9Sstevel@tonic-gate 		 * We actually didn't find anything of the same cid in
756*7c478bd9Sstevel@tonic-gate 		 * this process.
757*7c478bd9Sstevel@tonic-gate 		 */
758*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pp->p_lock);
759*7c478bd9Sstevel@tonic-gate 	}
760*7c478bd9Sstevel@tonic-gate 	return (0);
761*7c478bd9Sstevel@tonic-gate }
762*7c478bd9Sstevel@tonic-gate 
763*7c478bd9Sstevel@tonic-gate 
764*7c478bd9Sstevel@tonic-gate int
765*7c478bd9Sstevel@tonic-gate threadcmp(struct pcmpargs *argp, kthread_id_t tp)
766*7c478bd9Sstevel@tonic-gate {
767*7c478bd9Sstevel@tonic-gate 	kthread_id_t	tx;
768*7c478bd9Sstevel@tonic-gate 	proc_t		*pp;
769*7c478bd9Sstevel@tonic-gate 
770*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&(ttoproc(tp))->p_lock));
771*7c478bd9Sstevel@tonic-gate 
772*7c478bd9Sstevel@tonic-gate 	(*argp->pcmp_cntp)++;   /* Increment count of procs in the set */
773*7c478bd9Sstevel@tonic-gate 	if (*argp->pcmp_cidp == PC_CLNULL) {
774*7c478bd9Sstevel@tonic-gate 		/*
775*7c478bd9Sstevel@tonic-gate 		 * If no cid is specified, then lets just pick the first one.
776*7c478bd9Sstevel@tonic-gate 		 * It doesn't matter because if the number of threads in the
777*7c478bd9Sstevel@tonic-gate 		 * set are more than 1, then we return EINVAL in priocntlsys.
778*7c478bd9Sstevel@tonic-gate 		 */
779*7c478bd9Sstevel@tonic-gate 		*argp->pcmp_cidp = tp->t_cid;
780*7c478bd9Sstevel@tonic-gate 	}
781*7c478bd9Sstevel@tonic-gate 	if (tp->t_cid == *argp->pcmp_cidp) {
782*7c478bd9Sstevel@tonic-gate 		if (*argp->pcmp_retthreadp == NULL) {
783*7c478bd9Sstevel@tonic-gate 			/*
784*7c478bd9Sstevel@tonic-gate 			 * First time through for this set.
785*7c478bd9Sstevel@tonic-gate 			 */
786*7c478bd9Sstevel@tonic-gate 			*argp->pcmp_retthreadp = tp;
787*7c478bd9Sstevel@tonic-gate 		} else {
788*7c478bd9Sstevel@tonic-gate 			tx = *argp->pcmp_retthreadp;
789*7c478bd9Sstevel@tonic-gate 			if (CL_GLOBPRI(tp) > CL_GLOBPRI(tx)) {
790*7c478bd9Sstevel@tonic-gate 				/*
791*7c478bd9Sstevel@tonic-gate 				 * Unlike proccmp(), we don't release the
792*7c478bd9Sstevel@tonic-gate 				 * p_lock of the ttoproc(tp) if tp's global
793*7c478bd9Sstevel@tonic-gate 				 * priority is less than tx's. We need to go
794*7c478bd9Sstevel@tonic-gate 				 * through the entire list before we can do
795*7c478bd9Sstevel@tonic-gate 				 * that. The p_lock is released by the caller
796*7c478bd9Sstevel@tonic-gate 				 * of dotolwp().
797*7c478bd9Sstevel@tonic-gate 				 */
798*7c478bd9Sstevel@tonic-gate 				pp = ttoproc(tx);
799*7c478bd9Sstevel@tonic-gate 				ASSERT(MUTEX_HELD(&pp->p_lock));
800*7c478bd9Sstevel@tonic-gate 				if (pp != curproc) {
801*7c478bd9Sstevel@tonic-gate 					mutex_exit(&pp->p_lock);
802*7c478bd9Sstevel@tonic-gate 				}
803*7c478bd9Sstevel@tonic-gate 				*argp->pcmp_retthreadp = tp;
804*7c478bd9Sstevel@tonic-gate 			}
805*7c478bd9Sstevel@tonic-gate 		}
806*7c478bd9Sstevel@tonic-gate 	}
807*7c478bd9Sstevel@tonic-gate 	return (0);
808*7c478bd9Sstevel@tonic-gate }
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate /*
812*7c478bd9Sstevel@tonic-gate  * The setparms() function is called indirectly by priocntlsys()
813*7c478bd9Sstevel@tonic-gate  * through the dotoprocs() function.  setparms() acts as an
814*7c478bd9Sstevel@tonic-gate  * intermediary between dotoprocs() and the parmsset() function,
815*7c478bd9Sstevel@tonic-gate  * calling parmsset() for each thread in the set and handling
816*7c478bd9Sstevel@tonic-gate  * the error returns on their way back up to dotoprocs().
817*7c478bd9Sstevel@tonic-gate  */
818*7c478bd9Sstevel@tonic-gate static int
819*7c478bd9Sstevel@tonic-gate setparms(proc_t *targpp, struct stprmargs *stprmp)
820*7c478bd9Sstevel@tonic-gate {
821*7c478bd9Sstevel@tonic-gate 	int error = 0;
822*7c478bd9Sstevel@tonic-gate 	kthread_id_t t;
823*7c478bd9Sstevel@tonic-gate 	int err;
824*7c478bd9Sstevel@tonic-gate 
825*7c478bd9Sstevel@tonic-gate 	mutex_enter(&targpp->p_lock);
826*7c478bd9Sstevel@tonic-gate 	if ((t = targpp->p_tlist) == NULL) {
827*7c478bd9Sstevel@tonic-gate 		mutex_exit(&targpp->p_lock);
828*7c478bd9Sstevel@tonic-gate 		return (0);
829*7c478bd9Sstevel@tonic-gate 	}
830*7c478bd9Sstevel@tonic-gate 	do {
831*7c478bd9Sstevel@tonic-gate 		err = parmsset(stprmp->stp_parmsp, t);
832*7c478bd9Sstevel@tonic-gate 		if (error == 0)
833*7c478bd9Sstevel@tonic-gate 			error = err;
834*7c478bd9Sstevel@tonic-gate 	} while ((t = t->t_forw) != targpp->p_tlist);
835*7c478bd9Sstevel@tonic-gate 	mutex_exit(&targpp->p_lock);
836*7c478bd9Sstevel@tonic-gate 	if (error) {
837*7c478bd9Sstevel@tonic-gate 		if (error == EPERM) {
838*7c478bd9Sstevel@tonic-gate 			stprmp->stp_error = EPERM;
839*7c478bd9Sstevel@tonic-gate 			return (0);
840*7c478bd9Sstevel@tonic-gate 		} else {
841*7c478bd9Sstevel@tonic-gate 			return (error);
842*7c478bd9Sstevel@tonic-gate 		}
843*7c478bd9Sstevel@tonic-gate 	} else
844*7c478bd9Sstevel@tonic-gate 		return (0);
845*7c478bd9Sstevel@tonic-gate }
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate static int
848*7c478bd9Sstevel@tonic-gate setthreadnice(pcnice_t *pcnice, kthread_t *tp)
849*7c478bd9Sstevel@tonic-gate {
850*7c478bd9Sstevel@tonic-gate 	int error = 0;
851*7c478bd9Sstevel@tonic-gate 	int nice;
852*7c478bd9Sstevel@tonic-gate 	int inc;
853*7c478bd9Sstevel@tonic-gate 	id_t rtcid;
854*7c478bd9Sstevel@tonic-gate 
855*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
856*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&(ttoproc(tp)->p_lock)));
857*7c478bd9Sstevel@tonic-gate 
858*7c478bd9Sstevel@tonic-gate 	/*
859*7c478bd9Sstevel@tonic-gate 	 * The XPG5 standard requires that any realtime process or thread
860*7c478bd9Sstevel@tonic-gate 	 * must be unaffected by a call to setpriority().
861*7c478bd9Sstevel@tonic-gate 	 */
862*7c478bd9Sstevel@tonic-gate 	error = getcidbyname("RT", &rtcid);
863*7c478bd9Sstevel@tonic-gate 	if ((error == 0) && (tp->t_cid == rtcid)) {
864*7c478bd9Sstevel@tonic-gate 		if (pcnice->pc_op == PC_SETNICE)
865*7c478bd9Sstevel@tonic-gate 			return (error);
866*7c478bd9Sstevel@tonic-gate 	}
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 	if ((error = CL_DONICE(tp, CRED(), 0, &nice)) != 0)
869*7c478bd9Sstevel@tonic-gate 		return (error);
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	if (pcnice->pc_op == PC_GETNICE) {
872*7c478bd9Sstevel@tonic-gate 		/*
873*7c478bd9Sstevel@tonic-gate 		 * If there is no change to priority, we should return the
874*7c478bd9Sstevel@tonic-gate 		 * highest priority (lowest numerical value) pertaining to
875*7c478bd9Sstevel@tonic-gate 		 * any of the specified threads.
876*7c478bd9Sstevel@tonic-gate 		 */
877*7c478bd9Sstevel@tonic-gate 		if (nice < pcnice->pc_val)
878*7c478bd9Sstevel@tonic-gate 			pcnice->pc_val = nice;
879*7c478bd9Sstevel@tonic-gate 	} else {
880*7c478bd9Sstevel@tonic-gate 		ASSERT(pcnice->pc_op == PC_SETNICE);
881*7c478bd9Sstevel@tonic-gate 		/*
882*7c478bd9Sstevel@tonic-gate 		 * Try to change the nice value of the thread.
883*7c478bd9Sstevel@tonic-gate 		 */
884*7c478bd9Sstevel@tonic-gate 		inc = pcnice->pc_val - nice;
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 		error = CL_DONICE(tp, CRED(), inc, &inc);
887*7c478bd9Sstevel@tonic-gate 	}
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 	return (error);
890*7c478bd9Sstevel@tonic-gate }
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate static int
893*7c478bd9Sstevel@tonic-gate setprocnice(proc_t *pp, pcnice_t *pcnice)
894*7c478bd9Sstevel@tonic-gate {
895*7c478bd9Sstevel@tonic-gate 	kthread_t *tp;
896*7c478bd9Sstevel@tonic-gate 	int retval = 0;
897*7c478bd9Sstevel@tonic-gate 	int error = 0;
898*7c478bd9Sstevel@tonic-gate 
899*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&pidlock));
900*7c478bd9Sstevel@tonic-gate 	mutex_enter(&pp->p_lock);
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	if ((tp = pp->p_tlist) == NULL) {
903*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pp->p_lock);
904*7c478bd9Sstevel@tonic-gate 		return (ESRCH);
905*7c478bd9Sstevel@tonic-gate 	}
906*7c478bd9Sstevel@tonic-gate 
907*7c478bd9Sstevel@tonic-gate 	/*
908*7c478bd9Sstevel@tonic-gate 	 * Check permissions before changing the nice value.
909*7c478bd9Sstevel@tonic-gate 	 */
910*7c478bd9Sstevel@tonic-gate 	if (pcnice->pc_op == PC_SETNICE) {
911*7c478bd9Sstevel@tonic-gate 		if (!prochasprocperm(pp, curproc, CRED())) {
912*7c478bd9Sstevel@tonic-gate 			mutex_exit(&pp->p_lock);
913*7c478bd9Sstevel@tonic-gate 			return (EPERM);
914*7c478bd9Sstevel@tonic-gate 		}
915*7c478bd9Sstevel@tonic-gate 	}
916*7c478bd9Sstevel@tonic-gate 
917*7c478bd9Sstevel@tonic-gate 	do {
918*7c478bd9Sstevel@tonic-gate 		error = setthreadnice(pcnice, tp);
919*7c478bd9Sstevel@tonic-gate 		if (error)
920*7c478bd9Sstevel@tonic-gate 			retval = error;
921*7c478bd9Sstevel@tonic-gate 	} while ((tp = tp->t_forw) != pp->p_tlist);
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	mutex_exit(&pp->p_lock);
924*7c478bd9Sstevel@tonic-gate 	return (retval);
925*7c478bd9Sstevel@tonic-gate }
926*7c478bd9Sstevel@tonic-gate 
927*7c478bd9Sstevel@tonic-gate /*
928*7c478bd9Sstevel@tonic-gate  * Update the nice value of the specified LWP or set of processes.
929*7c478bd9Sstevel@tonic-gate  */
930*7c478bd9Sstevel@tonic-gate static int
931*7c478bd9Sstevel@tonic-gate donice(procset_t *procset, pcnice_t *pcnice)
932*7c478bd9Sstevel@tonic-gate {
933*7c478bd9Sstevel@tonic-gate 	int err_proc = 0;
934*7c478bd9Sstevel@tonic-gate 	int err_thread = 0;
935*7c478bd9Sstevel@tonic-gate 	int err = 0;
936*7c478bd9Sstevel@tonic-gate 
937*7c478bd9Sstevel@tonic-gate 	/*
938*7c478bd9Sstevel@tonic-gate 	 * Sanity check.
939*7c478bd9Sstevel@tonic-gate 	 */
940*7c478bd9Sstevel@tonic-gate 	if (pcnice->pc_op != PC_GETNICE && pcnice->pc_op != PC_SETNICE)
941*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
942*7c478bd9Sstevel@tonic-gate 
943*7c478bd9Sstevel@tonic-gate 	/*
944*7c478bd9Sstevel@tonic-gate 	 * If it is PC_GETNICE operation then set pc_val to the largest
945*7c478bd9Sstevel@tonic-gate 	 * possible nice value to help us find the lowest nice value
946*7c478bd9Sstevel@tonic-gate 	 * pertaining to any of the specified processes.
947*7c478bd9Sstevel@tonic-gate 	 */
948*7c478bd9Sstevel@tonic-gate 	if (pcnice->pc_op == PC_GETNICE)
949*7c478bd9Sstevel@tonic-gate 		pcnice->pc_val = NZERO;
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate 	if (procset->p_lidtype != P_LWPID ||
952*7c478bd9Sstevel@tonic-gate 	    procset->p_ridtype != P_LWPID)
953*7c478bd9Sstevel@tonic-gate 		err_proc = dotoprocs(procset, setprocnice, (char *)pcnice);
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	if (procset->p_lidtype == P_LWPID || procset->p_ridtype == P_LWPID) {
956*7c478bd9Sstevel@tonic-gate 		err_thread = dotolwp(procset, setthreadnice, (char *)pcnice);
957*7c478bd9Sstevel@tonic-gate 		/*
958*7c478bd9Sstevel@tonic-gate 		 * dotolwp() can return with p_lock held.  This is required
959*7c478bd9Sstevel@tonic-gate 		 * for the priocntl GETPARMS case.  So, here we just release
960*7c478bd9Sstevel@tonic-gate 		 * the p_lock.
961*7c478bd9Sstevel@tonic-gate 		 */
962*7c478bd9Sstevel@tonic-gate 		if (MUTEX_HELD(&curproc->p_lock))
963*7c478bd9Sstevel@tonic-gate 			mutex_exit(&curproc->p_lock);
964*7c478bd9Sstevel@tonic-gate 
965*7c478bd9Sstevel@tonic-gate 		/*
966*7c478bd9Sstevel@tonic-gate 		 * If we were called for a single LWP, then ignore ESRCH
967*7c478bd9Sstevel@tonic-gate 		 * returned by the previous dotoprocs() call.
968*7c478bd9Sstevel@tonic-gate 		 */
969*7c478bd9Sstevel@tonic-gate 		if (err_proc == ESRCH)
970*7c478bd9Sstevel@tonic-gate 			err_proc = 0;
971*7c478bd9Sstevel@tonic-gate 	}
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	/*
974*7c478bd9Sstevel@tonic-gate 	 * dotoprocs() ignores the init process if it is in the set, unless
975*7c478bd9Sstevel@tonic-gate 	 * it was the only process found. We want to make sure init is not
976*7c478bd9Sstevel@tonic-gate 	 * excluded if we're going PC_GETNICE operation.
977*7c478bd9Sstevel@tonic-gate 	 */
978*7c478bd9Sstevel@tonic-gate 	if (pcnice->pc_op == PC_GETNICE) {
979*7c478bd9Sstevel@tonic-gate 		proc_t *initpp;
980*7c478bd9Sstevel@tonic-gate 
981*7c478bd9Sstevel@tonic-gate 		mutex_enter(&pidlock);
982*7c478bd9Sstevel@tonic-gate 		initpp = prfind(P_INITPID);
983*7c478bd9Sstevel@tonic-gate 		if (initpp != NULL && procinset(initpp, procset))
984*7c478bd9Sstevel@tonic-gate 			err = setprocnice(initpp, pcnice);
985*7c478bd9Sstevel@tonic-gate 		mutex_exit(&pidlock);
986*7c478bd9Sstevel@tonic-gate 	}
987*7c478bd9Sstevel@tonic-gate 
988*7c478bd9Sstevel@tonic-gate 	/*
989*7c478bd9Sstevel@tonic-gate 	 * We're returning the latest error here that we've got back from
990*7c478bd9Sstevel@tonic-gate 	 * the setthreadnice() or setprocnice(). That is, err_thread and/or
991*7c478bd9Sstevel@tonic-gate 	 * err_proc can be replaced by err.
992*7c478bd9Sstevel@tonic-gate 	 */
993*7c478bd9Sstevel@tonic-gate 	if (!err)
994*7c478bd9Sstevel@tonic-gate 		err = err_thread ? err_thread : err_proc;
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	return (err);
997*7c478bd9Sstevel@tonic-gate }
998