4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2016 by Delphix. All rights reserved.
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
31 #include <sys/types.h>
32 #include <sys/param.h>
33 #include <sys/sysmacros.h>
34 #include <sys/signal.h>
37 #include <sys/systm.h>
38 #include <sys/sysinfo.h>
40 #include <sys/errno.h>
43 #include <sys/procset.h>
44 #include <sys/debug.h>
45 #include <sys/inline.h>
46 #include <sys/priocntl.h>
48 #include <sys/class.h>
49 #include <sys/modctl.h>
50 #include <sys/t_lock.h>
51 #include <sys/uadmin.h>
52 #include <sys/cmn_err.h>
53 #include <sys/policy.h>
54 #include <sys/schedctl.h>
57 * Structure used to pass arguments to the proccmp() function.
58 * The arguments must be passed in a structure because proccmp()
59 * is called indirectly through the dotoprocs() function which
60 * will only pass through a single one word argument.
65 kthread_t
**pcmp_retthreadp
;
69 * Structure used to pass arguments to the setparms() function
70 * which is called indirectly through dotoprocs().
73 struct pcparms
*stp_parmsp
; /* pointer to parameters */
74 int stp_error
; /* some errors returned here */
77 #if defined(_SYSCALL32_IMPL) && _LONG_LONG_ALIGNMENT_32 == 4
79 * A vaparm_t is an int followed by a long long -- this packs differently
80 * between the 64-bit kernel ABI and the 32-bit user ABI.
83 copyin_vaparms32(caddr_t arg
, pc_vaparms_t
*vap
, uio_seg_t seg
)
85 pc_vaparms32_t vaparms32
;
90 ASSERT(get_udatamodel() == DATAMODEL_ILP32
);
92 if ((seg
== UIO_USERSPACE
? copyin
: kcopy
)(arg
, &vaparms32
,
96 vap
->pc_vaparmscnt
= vaparms32
.pc_vaparmscnt
;
97 if ((cnt
= vaparms32
.pc_vaparmscnt
) > PC_VAPARMCNT
)
99 for (src
= vaparms32
.pc_parms
, dst
= vap
->pc_parms
;
100 cnt
--; src
++, dst
++) {
101 dst
->pc_key
= src
->pc_key
;
102 dst
->pc_parm
= src
->pc_parm
;
107 #define COPYIN_VAPARMS(arg, vap, size, seg) \
108 (get_udatamodel() == DATAMODEL_NATIVE ? \
109 (*copyinfn)(arg, vap, size) : copyin_vaparms32(arg, vap, seg))
113 #define COPYIN_VAPARMS(arg, vap, size, seg) (*copyinfn)(arg, vap, size)
117 static int donice(procset_t
*, pcnice_t
*);
118 static int doprio(procset_t
*, pcprio_t
*);
119 static int proccmp(proc_t
*, struct pcmpargs
*);
120 static int setparms(proc_t
*, struct stprmargs
*);
121 extern int threadcmp(struct pcmpargs
*, kthread_t
*);
124 * The priocntl system call.
127 priocntl_common(int pc_version
, procset_t
*psp
, int cmd
, caddr_t arg
,
128 caddr_t arg2
, uio_seg_t seg
)
137 struct stprmargs stprmargs
;
138 struct pcmpargs pcmpargs
;
139 pc_vaparms_t vaparms
;
140 char clname
[PC_CLNMSZ
];
143 kthread_t
*retthreadp
;
152 int (*copyinfn
)(const void *, void *, size_t);
153 int (*copyoutfn
)(const void *, void *, size_t);
156 * First just check the version number. Right now there is only
157 * one version we know about and support. If we get some other
158 * version number from the application it may be that the
159 * application was built with some future version and is trying
160 * to run on an old release of the system (that's us). In any
161 * case if we don't recognize the version number all we can do is
164 if (pc_version
!= PC_VERSION
)
165 return (set_errno(EINVAL
));
167 if (seg
== UIO_USERSPACE
) {
178 * If the arg pointer is NULL, the user just wants to
179 * know the number of classes. If non-NULL, the pointer
180 * should point to a valid user pcinfo buffer. In the
181 * dynamic world we need to return the number of loaded
182 * classes, not the max number of available classes that
189 if ((*copyinfn
)(arg
, &pcinfo
, sizeof (pcinfo
)))
190 return (set_errno(EFAULT
));
193 pcinfo
.pc_clname
[PC_CLNMSZ
-1] = '\0';
196 * Get the class ID corresponding to user supplied name.
198 error
= getcid(pcinfo
.pc_clname
, &pcinfo
.pc_cid
);
200 return (set_errno(error
));
203 * Can't get info about the sys class.
205 if (pcinfo
.pc_cid
== 0)
206 return (set_errno(EINVAL
));
209 * Get the class specific information.
210 * we MUST make sure that the class has not already
211 * been unloaded before we try the CL_GETCLINFO.
212 * If it has then we need to load it.
215 scheduler_load(pcinfo
.pc_clname
, &sclass
[pcinfo
.pc_cid
]);
217 return (set_errno(error
));
218 error
= CL_GETCLINFO(&sclass
[pcinfo
.pc_cid
], pcinfo
.pc_clinfo
);
220 return (set_errno(error
));
222 if ((*copyoutfn
)(&pcinfo
, arg
, sizeof (pcinfo
)))
223 return (set_errno(EFAULT
));
231 * If the arg pointer is NULL, the user just wants to know
232 * the number of classes. If non-NULL, the pointer should
233 * point to a valid user pcinfo buffer.
239 if ((*copyinfn
)(arg
, &pcinfo
, sizeof (pcinfo
)))
240 return (set_errno(EFAULT
));
243 if (pcinfo
.pc_cid
>= loaded_classes
|| pcinfo
.pc_cid
< 1)
244 return (set_errno(EINVAL
));
246 (void) strncpy(pcinfo
.pc_clname
, sclass
[pcinfo
.pc_cid
].cl_name
,
250 * Get the class specific information. we MUST make sure
251 * that the class has not already been unloaded before we
252 * try the CL_GETCLINFO. If it has then we need to load
256 scheduler_load(pcinfo
.pc_clname
, &sclass
[pcinfo
.pc_cid
]);
258 return (set_errno(error
));
259 error
= CL_GETCLINFO(&sclass
[pcinfo
.pc_cid
], pcinfo
.pc_clinfo
);
261 return (set_errno(error
));
263 if ((*copyoutfn
)(&pcinfo
, arg
, sizeof (pcinfo
)))
264 return (set_errno(EFAULT
));
272 * First check the validity of the parameters we got from
273 * the user. We don't do any permissions checking here
274 * because it's done on a per thread basis by parmsset().
276 if (cmd
== PC_SETPARMS
) {
277 if ((*copyinfn
)(arg
, &pcparms
, sizeof (pcparms
)))
278 return (set_errno(EFAULT
));
280 error
= parmsin(&pcparms
, NULL
);
282 if ((*copyinfn
)(arg
, clname
, PC_CLNMSZ
) ||
283 COPYIN_VAPARMS(arg2
, &vaparms
, sizeof (vaparms
),
285 return (set_errno(EFAULT
));
286 clname
[PC_CLNMSZ
-1] = '\0';
288 if (getcid(clname
, &pcparms
.pc_cid
))
289 return (set_errno(EINVAL
));
291 error
= parmsin(&pcparms
, &vaparms
);
295 return (set_errno(error
));
298 * Get the procset from the user.
300 if ((*copyinfn
)(psp
, &procset
, sizeof (procset
)))
301 return (set_errno(EFAULT
));
304 * For performance we do a quick check here to catch
305 * common cases where the current thread is the only one
306 * in the set. In such cases we can call parmsset()
307 * directly, avoiding the relatively lengthy path through
308 * dotoprocs(). The underlying classes expect pidlock to
311 if (cur_inset_only(&procset
) == B_TRUE
) {
312 /* do a single LWP */
313 if ((procset
.p_lidtype
== P_LWPID
) ||
314 (procset
.p_ridtype
== P_LWPID
)) {
315 mutex_enter(&pidlock
);
316 mutex_enter(&curproc
->p_lock
);
317 error
= parmsset(&pcparms
, curthread
);
318 mutex_exit(&curproc
->p_lock
);
319 mutex_exit(&pidlock
);
321 /* do the entire process otherwise */
322 stprmargs
.stp_parmsp
= &pcparms
;
323 stprmargs
.stp_error
= 0;
324 mutex_enter(&pidlock
);
325 error
= setparms(curproc
, &stprmargs
);
326 mutex_exit(&pidlock
);
327 if (error
== 0 && stprmargs
.stp_error
!= 0)
328 error
= stprmargs
.stp_error
;
331 return (set_errno(error
));
333 stprmargs
.stp_parmsp
= &pcparms
;
334 stprmargs
.stp_error
= 0;
336 error1
= error
= ESRCH
;
339 * The dotoprocs() call below will cause
340 * setparms() to be called for each thread in the
341 * specified procset. setparms() will in turn
342 * call parmsset() (which does the real work).
344 if ((procset
.p_lidtype
!= P_LWPID
) ||
345 (procset
.p_ridtype
!= P_LWPID
)) {
346 error1
= dotoprocs(&procset
, setparms
,
351 * take care of the case when any of the
352 * operands happen to be LWP's
355 if ((procset
.p_lidtype
== P_LWPID
) ||
356 (procset
.p_ridtype
== P_LWPID
)) {
357 error
= dotolwp(&procset
, parmsset
,
360 * Dotolwp() returns with p_lock held.
361 * This is required for the GETPARMS case
362 * below. So, here we just release the
365 if (MUTEX_HELD(&curproc
->p_lock
))
366 mutex_exit(&curproc
->p_lock
);
370 * If setparms() encounters a permissions error
371 * for one or more of the threads it returns
372 * EPERM in stp_error so dotoprocs() will
373 * continue through the thread set. If
374 * dotoprocs() returned an error above, it was
375 * more serious than permissions and dotoprocs
376 * quit when the error was encountered. We
377 * return the more serious error if there was
378 * one, otherwise we return EPERM if we got that
383 if (error
== 0 && stprmargs
.stp_error
!= 0)
384 error
= stprmargs
.stp_error
;
390 if (cmd
== PC_GETPARMS
) {
391 if ((*copyinfn
)(arg
, &pcparms
, sizeof (pcparms
)))
392 return (set_errno(EFAULT
));
395 if ((*copyinfn
)(arg
, clname
, PC_CLNMSZ
))
396 return (set_errno(EFAULT
));
398 clname
[PC_CLNMSZ
-1] = '\0';
400 if (getcid(clname
, &pcparms
.pc_cid
))
401 return (set_errno(EINVAL
));
403 pcparms
.pc_cid
= PC_CLNULL
;
405 if (COPYIN_VAPARMS(arg2
, &vaparms
, sizeof (vaparms
),
407 return (set_errno(EFAULT
));
410 if (pcparms
.pc_cid
>= loaded_classes
||
411 (pcparms
.pc_cid
< 1 && pcparms
.pc_cid
!= PC_CLNULL
))
412 return (set_errno(EINVAL
));
414 if ((*copyinfn
)(psp
, &procset
, sizeof (procset
)))
415 return (set_errno(EFAULT
));
418 * Check to see if the current thread is the only one
419 * in the set. If not we must go through the whole set
420 * to select a thread.
422 if (cur_inset_only(&procset
) == B_TRUE
) {
423 /* do a single LWP */
424 if ((procset
.p_lidtype
== P_LWPID
) ||
425 (procset
.p_ridtype
== P_LWPID
)) {
426 if (pcparms
.pc_cid
!= PC_CLNULL
&&
427 pcparms
.pc_cid
!= curthread
->t_cid
) {
429 * Specified thread not in
432 return (set_errno(ESRCH
));
434 mutex_enter(&curproc
->p_lock
);
435 retthreadp
= curthread
;
440 pcmpargs
.pcmp_cidp
= &pcparms
.pc_cid
;
441 pcmpargs
.pcmp_cntp
= &count
;
442 pcmpargs
.pcmp_retthreadp
= &retthreadp
;
444 * Specified thread not in specified class.
446 if (pcparms
.pc_cid
!= PC_CLNULL
&&
447 pcparms
.pc_cid
!= curthread
->t_cid
)
448 return (set_errno(ESRCH
));
449 error
= proccmp(curproc
, &pcmpargs
);
451 if (retthreadp
!= NULL
)
452 mutex_exit(&(curproc
->p_lock
));
453 return (set_errno(error
));
458 * get initpp early to avoid lock ordering problems
459 * (we cannot get pidlock while holding any p_lock).
461 mutex_enter(&pidlock
);
462 initpp
= prfind(P_INITPID
);
463 mutex_exit(&pidlock
);
466 * Select the thread (from the set) whose
467 * parameters we are going to return. First we
468 * set up some locations for return values, then
469 * we call proccmp() indirectly through
470 * dotoprocs(). proccmp() will call a class
471 * specific routine which actually does the
472 * selection. To understand how this works take
473 * a careful look at the code below, the
474 * dotoprocs() function, the proccmp() function,
475 * and the class specific cl_proccmp() functions.
477 if (pcparms
.pc_cid
== PC_CLNULL
)
483 pcmpargs
.pcmp_cidp
= &pcparms
.pc_cid
;
484 pcmpargs
.pcmp_cntp
= &count
;
485 pcmpargs
.pcmp_retthreadp
= &retthreadp
;
486 error1
= error
= ESRCH
;
488 if ((procset
.p_lidtype
!= P_LWPID
) ||
489 (procset
.p_ridtype
!= P_LWPID
)) {
490 error1
= dotoprocs(&procset
, proccmp
,
495 * take care of combination of LWP and process
496 * set case in a procset
498 if ((procset
.p_lidtype
== P_LWPID
) ||
499 (procset
.p_ridtype
== P_LWPID
)) {
500 error
= dotolwp(&procset
, threadcmp
,
505 * Both proccmp() and threadcmp() return with the
506 * p_lock held for the ttoproc(retthreadp). This
507 * is required to make sure that the process we
508 * chose as the winner doesn't go away
509 * i.e. retthreadp has to be a valid pointer.
511 * The case below can only happen if the thread
512 * with the highest priority was not in your
513 * process. In that case, dotolwp will return
514 * holding p_lock for both your process as well
515 * as the process in which retthreadp is a
518 if ((retthreadp
!= NULL
) &&
519 (ttoproc(retthreadp
) != curproc
) &&
520 MUTEX_HELD(&(curproc
)->p_lock
))
521 mutex_exit(&(curproc
)->p_lock
);
523 ASSERT(retthreadp
== NULL
||
524 MUTEX_HELD(&(ttoproc(retthreadp
)->p_lock
)));
528 if (retthreadp
!= NULL
)
530 mutex_exit(&(ttoproc(retthreadp
)->p_lock
));
531 ASSERT(MUTEX_NOT_HELD(&(curproc
)->p_lock
));
532 return (set_errno(error
));
535 * dotoprocs() ignores the init process if it is
536 * in the set, unless it was the only process found.
537 * Since we are getting parameters here rather than
538 * setting them, we want to make sure init is not
539 * excluded if it is in the set.
541 if (initpp
!= NULL
&& retthreadp
!= NULL
&&
542 ttoproc(retthreadp
) != initpp
) {
543 mutex_enter(&initpp
->p_lock
);
544 if (procinset(initpp
, &procset
)) {
545 mutex_exit(&initpp
->p_lock
);
546 (void) proccmp(initpp
, &pcmpargs
);
548 mutex_exit(&initpp
->p_lock
);
553 * If dotoprocs returned success it found at least
554 * one thread in the set. If proccmp() failed to
555 * select a thread it is because the user specified
556 * a class and none of the threads in the set
557 * belonged to that class, or because the process
558 * specified was in the middle of exiting and had
559 * cleared its thread list.
561 if (retthreadp
== NULL
) {
563 * Might be here and still holding p_lock
564 * if we did a dotolwp on an lwp that
565 * existed but was in the wrong class.
567 if (MUTEX_HELD(&(curproc
)->p_lock
))
568 mutex_exit(&(curproc
)->p_lock
);
569 return (set_errno(ESRCH
));
573 * User can only use PC_CLNULL with one thread in set.
575 if (clnullflag
&& count
> 1) {
576 if (retthreadp
!= NULL
)
578 &(ttoproc(retthreadp
)->p_lock
));
579 ASSERT(MUTEX_NOT_HELD(&(curproc
)->p_lock
));
580 return (set_errno(EINVAL
));
584 ASSERT(retthreadp
== NULL
||
585 MUTEX_HELD(&(ttoproc(retthreadp
)->p_lock
)));
587 * It is possible to have retthreadp == NULL. Proccmp()
588 * in the rare case (p_tlist == NULL) could return without
589 * setting a value for retthreadp.
591 if (retthreadp
== NULL
) {
592 ASSERT(MUTEX_NOT_HELD(&(curproc
)->p_lock
));
593 return (set_errno(ESRCH
));
596 * We've selected a thread so now get the parameters.
598 parmsget(retthreadp
, &pcparms
);
601 * Prepare to return parameters to the user
603 error
= parmsout(&pcparms
,
604 (cmd
== PC_GETPARMS
? NULL
: &vaparms
));
607 * Save pid of selected thread before dropping p_lock.
609 saved_pid
= ttoproc(retthreadp
)->p_pid
;
610 mutex_exit(&(ttoproc(retthreadp
)->p_lock
));
611 ASSERT(MUTEX_NOT_HELD(&curproc
->p_lock
));
614 return (set_errno(error
));
616 if (cmd
== PC_GETPARMS
) {
617 if ((*copyoutfn
)(&pcparms
, arg
, sizeof (pcparms
)))
618 return (set_errno(EFAULT
));
619 } else if ((error
= vaparmsout(arg
, &pcparms
, &vaparms
,
621 return (set_errno(error
));
624 * And finally, return the pid of the selected thread.
630 if (get_udatamodel() == DATAMODEL_NATIVE
) {
631 if ((*copyinfn
)(arg
, &pcadmin
, sizeof (pcadmin_t
)))
632 return (set_errno(EFAULT
));
633 #ifdef _SYSCALL32_IMPL
635 /* pcadmin struct from ILP32 callers */
636 pcadmin32_t pcadmin32
;
638 if ((*copyinfn
)(arg
, &pcadmin32
, sizeof (pcadmin32_t
)))
639 return (set_errno(EFAULT
));
640 pcadmin
.pc_cid
= pcadmin32
.pc_cid
;
641 pcadmin
.pc_cladmin
= (caddr_t
)(uintptr_t)
642 pcadmin32
.pc_cladmin
;
643 #endif /* _SYSCALL32_IMPL */
646 if (pcadmin
.pc_cid
>= loaded_classes
||
648 return (set_errno(EINVAL
));
651 * Have the class do whatever the user is requesting.
653 mutex_enter(&ualock
);
654 error
= CL_ADMIN(&sclass
[pcadmin
.pc_cid
], pcadmin
.pc_cladmin
,
660 if ((*copyinfn
)(arg
, &pcpri
, sizeof (pcpri_t
)))
661 return (set_errno(EFAULT
));
663 if (pcpri
.pc_cid
>= loaded_classes
|| pcpri
.pc_cid
< 0)
664 return (set_errno(EINVAL
));
666 error
= CL_GETCLPRI(&sclass
[pcpri
.pc_cid
], &pcpri
);
668 if ((*copyoutfn
)(&pcpri
, arg
, sizeof (pcpri
)))
669 return (set_errno(EFAULT
));
675 * Get pcnice and procset structures from the user.
677 if ((*copyinfn
)(arg
, &pcnice
, sizeof (pcnice
)) ||
678 (*copyinfn
)(psp
, &procset
, sizeof (procset
)))
679 return (set_errno(EFAULT
));
681 error
= donice(&procset
, &pcnice
);
683 if (!error
&& (pcnice
.pc_op
== PC_GETNICE
)) {
684 if ((*copyoutfn
)(&pcnice
, arg
, sizeof (pcnice
)))
685 return (set_errno(EFAULT
));
691 * Get pcprio and procset structures from the user.
693 if ((*copyinfn
)(arg
, &pcprio
, sizeof (pcprio
)) ||
694 (*copyinfn
)(psp
, &procset
, sizeof (procset
)))
695 return (set_errno(EFAULT
));
697 error
= doprio(&procset
, &pcprio
);
699 if (!error
&& (pcprio
.pc_op
== PC_GETPRIO
)) {
700 if ((*copyoutfn
)(&pcprio
, arg
, sizeof (pcprio
)))
701 return (set_errno(EFAULT
));
706 if (secpolicy_dispadm(CRED()) != 0)
707 return (set_errno(EPERM
));
709 if (copyin(arg
, (caddr_t
)clname
, PC_CLNMSZ
) != 0)
710 return (set_errno(EFAULT
));
711 clname
[PC_CLNMSZ
-1] = '\0';
713 if (getcid(clname
, &classid
) != 0)
714 return (set_errno(EINVAL
));
715 if (CLASS_KERNEL(classid
))
716 return (set_errno(EINVAL
));
717 defaultcid
= classid
;
718 ASSERT(defaultcid
> 0 && defaultcid
< loaded_classes
);
722 mutex_enter(&class_lock
);
724 if (defaultcid
>= loaded_classes
)
727 outstr
= sclass
[defaultcid
].cl_name
;
728 size
= strlen(outstr
) + 1;
730 if ((*copyoutfn
)(outstr
, arg
, size
) != 0)
733 mutex_exit(&class_lock
);
740 return (error
? (set_errno(error
)) : rv
);
744 priocntlsys(int pc_version
, procset_t
*psp
, int cmd
, caddr_t arg
, caddr_t arg2
)
746 return (priocntl_common(pc_version
, psp
, cmd
, arg
, arg2
,
751 * The proccmp() function is part of the implementation of the
752 * PC_GETPARMS command of the priocntl system call. This function works
753 * with the system call code and with the class specific cl_globpri()
754 * function to select one thread from a specified procset based on class
755 * specific criteria. proccmp() is called indirectly from the priocntl
756 * code through the dotoprocs function. Basic strategy is dotoprocs()
757 * calls us once for each thread in the set. We in turn call the class
758 * specific function to compare the current thread from dotoprocs to the
759 * "best" (according to the class criteria) found so far. We keep the
760 * "best" thread in *pcmp_retthreadp.
763 proccmp(proc_t
*pp
, struct pcmpargs
*argp
)
771 mutex_enter(&pp
->p_lock
);
773 if (pp
->p_tlist
== NULL
) {
774 mutex_exit(&pp
->p_lock
);
777 (*argp
->pcmp_cntp
)++; /* Increment count of procs in the set */
779 if (*argp
->pcmp_cidp
== PC_CLNULL
) {
781 * If no cid is specified, then lets just pick the first one.
782 * It doesn't matter because if the number of processes in the
783 * set are more than 1, then we return EINVAL in priocntlsys.
785 *argp
->pcmp_cidp
= pp
->p_tlist
->t_cid
;
787 ty
= tx
= pp
->p_tlist
;
789 if (tx
->t_cid
== *argp
->pcmp_cidp
) {
791 * We found one which matches the required cid.
794 if ((tx_pri
= CL_GLOBPRI(tx
)) > last_pri
) {
799 } while ((tx
= tx
->t_forw
) != pp
->p_tlist
);
801 if (*argp
->pcmp_retthreadp
== NULL
) {
803 * First time through for this set.
804 * keep the mutex held. It might be the one!
806 *argp
->pcmp_retthreadp
= ty
;
808 tx
= *argp
->pcmp_retthreadp
;
809 if (CL_GLOBPRI(ty
) <= CL_GLOBPRI(tx
)) {
810 mutex_exit(&pp
->p_lock
);
812 mutex_exit(&(ttoproc(tx
)->p_lock
));
813 *argp
->pcmp_retthreadp
= ty
;
818 * We actually didn't find anything of the same cid in
821 mutex_exit(&pp
->p_lock
);
828 threadcmp(struct pcmpargs
*argp
, kthread_t
*tp
)
833 ASSERT(MUTEX_HELD(&(ttoproc(tp
))->p_lock
));
835 (*argp
->pcmp_cntp
)++; /* Increment count of procs in the set */
836 if (*argp
->pcmp_cidp
== PC_CLNULL
) {
838 * If no cid is specified, then lets just pick the first one.
839 * It doesn't matter because if the number of threads in the
840 * set are more than 1, then we return EINVAL in priocntlsys.
842 *argp
->pcmp_cidp
= tp
->t_cid
;
844 if (tp
->t_cid
== *argp
->pcmp_cidp
) {
845 if (*argp
->pcmp_retthreadp
== NULL
) {
847 * First time through for this set.
849 *argp
->pcmp_retthreadp
= tp
;
851 tx
= *argp
->pcmp_retthreadp
;
852 if (CL_GLOBPRI(tp
) > CL_GLOBPRI(tx
)) {
854 * Unlike proccmp(), we don't release the
855 * p_lock of the ttoproc(tp) if tp's global
856 * priority is less than tx's. We need to go
857 * through the entire list before we can do
858 * that. The p_lock is released by the caller
862 ASSERT(MUTEX_HELD(&pp
->p_lock
));
864 mutex_exit(&pp
->p_lock
);
866 *argp
->pcmp_retthreadp
= tp
;
875 * The setparms() function is called indirectly by priocntlsys()
876 * through the dotoprocs() function. setparms() acts as an
877 * intermediary between dotoprocs() and the parmsset() function,
878 * calling parmsset() for each thread in the set and handling
879 * the error returns on their way back up to dotoprocs().
882 setparms(proc_t
*targpp
, struct stprmargs
*stprmp
)
888 mutex_enter(&targpp
->p_lock
);
889 if ((t
= targpp
->p_tlist
) == NULL
) {
890 mutex_exit(&targpp
->p_lock
);
894 err
= parmsset(stprmp
->stp_parmsp
, t
);
897 } while ((t
= t
->t_forw
) != targpp
->p_tlist
);
898 mutex_exit(&targpp
->p_lock
);
900 if (error
== EPERM
) {
901 stprmp
->stp_error
= EPERM
;
911 setthreadnice(pcnice_t
*pcnice
, kthread_t
*tp
)
918 ASSERT(MUTEX_HELD(&pidlock
));
919 ASSERT(MUTEX_HELD(&(ttoproc(tp
)->p_lock
)));
922 * The XPG5 standard requires that any realtime process or thread
923 * must be unaffected by a call to setpriority().
925 error
= getcidbyname("RT", &rtcid
);
926 if (error
== 0 && tp
->t_cid
== rtcid
) {
927 if (pcnice
->pc_op
== PC_SETNICE
)
931 if ((error
= CL_DONICE(tp
, CRED(), 0, &nice
)) != 0)
934 if (pcnice
->pc_op
== PC_GETNICE
) {
936 * If there is no change to priority, we should return the
937 * highest priority (lowest numerical value) pertaining to
938 * any of the specified threads.
940 if (nice
< pcnice
->pc_val
)
941 pcnice
->pc_val
= nice
;
943 ASSERT(pcnice
->pc_op
== PC_SETNICE
);
945 * Try to change the nice value of the thread.
947 inc
= pcnice
->pc_val
- nice
;
949 error
= CL_DONICE(tp
, CRED(), inc
, &inc
);
950 schedctl_set_cidpri(tp
);
957 setprocnice(proc_t
*pp
, pcnice_t
*pcnice
)
963 ASSERT(MUTEX_HELD(&pidlock
));
964 mutex_enter(&pp
->p_lock
);
966 if ((tp
= pp
->p_tlist
) == NULL
) {
967 mutex_exit(&pp
->p_lock
);
972 * Check permissions before changing the nice value.
974 if (pcnice
->pc_op
== PC_SETNICE
) {
975 if (!prochasprocperm(pp
, curproc
, CRED())) {
976 mutex_exit(&pp
->p_lock
);
982 error
= setthreadnice(pcnice
, tp
);
985 } while ((tp
= tp
->t_forw
) != pp
->p_tlist
);
987 mutex_exit(&pp
->p_lock
);
992 * Update the nice value of the specified LWP or set of processes.
995 donice(procset_t
*procset
, pcnice_t
*pcnice
)
1004 if (pcnice
->pc_op
!= PC_GETNICE
&& pcnice
->pc_op
!= PC_SETNICE
)
1008 * If it is PC_GETNICE operation then set pc_val to the largest
1009 * possible nice value to help us find the lowest nice value
1010 * pertaining to any of the specified processes.
1012 if (pcnice
->pc_op
== PC_GETNICE
)
1013 pcnice
->pc_val
= NZERO
;
1015 if (procset
->p_lidtype
!= P_LWPID
||
1016 procset
->p_ridtype
!= P_LWPID
)
1017 err_proc
= dotoprocs(procset
, setprocnice
, (char *)pcnice
);
1019 if (procset
->p_lidtype
== P_LWPID
|| procset
->p_ridtype
== P_LWPID
) {
1020 err_thread
= dotolwp(procset
, setthreadnice
, (char *)pcnice
);
1022 * dotolwp() can return with p_lock held. This is required
1023 * for the priocntl GETPARMS case. So, here we just release
1026 if (MUTEX_HELD(&curproc
->p_lock
))
1027 mutex_exit(&curproc
->p_lock
);
1030 * If we were called for a single LWP, then ignore ESRCH
1031 * returned by the previous dotoprocs() call.
1033 if (err_proc
== ESRCH
)
1038 * dotoprocs() ignores the init process if it is in the set, unless
1039 * it was the only process found. We want to make sure init is not
1040 * excluded if we're going PC_GETNICE operation.
1042 if (pcnice
->pc_op
== PC_GETNICE
) {
1045 mutex_enter(&pidlock
);
1046 if ((initpp
= prfind(P_INITPID
)) != NULL
) {
1047 mutex_enter(&initpp
->p_lock
);
1048 if (procinset(initpp
, procset
)) {
1049 mutex_exit(&initpp
->p_lock
);
1050 err
= setprocnice(initpp
, pcnice
);
1052 mutex_exit(&initpp
->p_lock
);
1055 mutex_exit(&pidlock
);
1059 * We're returning the latest error here that we've got back from
1060 * the setthreadnice() or setprocnice(). That is, err_thread and/or
1061 * err_proc can be replaced by err.
1064 err
= err_thread
? err_thread
: err_proc
;
1070 setthreadprio(pcprio_t
*pcprio
, kthread_t
*tp
)
1076 ASSERT(MUTEX_HELD(&pidlock
));
1077 ASSERT(MUTEX_HELD(&(ttoproc(tp
)->p_lock
)));
1079 if (pcprio
->pc_op
== PC_SETPRIO
&& pcprio
->pc_cid
!= tp
->t_cid
) {
1081 * Target thread must change to new class.
1082 * See comments in parmsset(), from where this code was copied.
1085 caddr_t clprocp
= (caddr_t
)tp
->t_cldata
;
1086 id_t oldcid
= tp
->t_cid
;
1088 error
= CL_CANEXIT(tp
, NULL
);
1091 if (CL_ALLOC(&bufp
, pcprio
->pc_cid
, KM_NOSLEEP
) != 0)
1093 error
= CL_ENTERCLASS(tp
, pcprio
->pc_cid
, NULL
, CRED(), bufp
);
1095 CL_FREE(pcprio
->pc_cid
, bufp
);
1098 CL_EXITCLASS(oldcid
, clprocp
);
1099 schedctl_set_cidpri(tp
);
1102 if ((error
= CL_DOPRIO(tp
, CRED(), 0, &prio
)) != 0)
1105 if (pcprio
->pc_op
== PC_GETPRIO
) {
1107 * If we are not setting the priority, we should return the
1108 * highest priority pertaining to any of the specified threads.
1110 if (prio
> pcprio
->pc_val
) {
1111 pcprio
->pc_cid
= tp
->t_cid
;
1112 pcprio
->pc_val
= prio
;
1114 } else if (prio
!= pcprio
->pc_val
) {
1116 * Try to change the priority of the thread.
1118 incr
= pcprio
->pc_val
- prio
;
1119 error
= CL_DOPRIO(tp
, CRED(), incr
, &prio
);
1120 schedctl_set_cidpri(tp
);
1127 setprocprio(proc_t
*pp
, pcprio_t
*pcprio
)
1133 ASSERT(MUTEX_HELD(&pidlock
));
1134 mutex_enter(&pp
->p_lock
);
1136 if ((tp
= pp
->p_tlist
) == NULL
) {
1137 mutex_exit(&pp
->p_lock
);
1142 * Check permissions before changing the prio value.
1144 if (pcprio
->pc_op
== PC_SETPRIO
) {
1145 if (!prochasprocperm(pp
, curproc
, CRED())) {
1146 mutex_exit(&pp
->p_lock
);
1152 error
= setthreadprio(pcprio
, tp
);
1155 } while ((tp
= tp
->t_forw
) != pp
->p_tlist
);
1157 mutex_exit(&pp
->p_lock
);
1162 * Set the class and priority of the specified LWP or set of processes.
1165 doprio(procset_t
*procset
, pcprio_t
*pcprio
)
1174 if (pcprio
->pc_op
!= PC_GETPRIO
&& pcprio
->pc_op
!= PC_SETPRIO
)
1176 if (pcprio
->pc_op
== PC_SETPRIO
&&
1177 (pcprio
->pc_cid
>= loaded_classes
|| pcprio
->pc_cid
< 1))
1181 * If it is a PC_GETPRIO operation then set pc_val to the smallest
1182 * possible prio value to help us find the highest priority
1183 * pertaining to any of the specified processes.
1185 if (pcprio
->pc_op
== PC_GETPRIO
)
1186 pcprio
->pc_val
= SHRT_MIN
;
1188 if (procset
->p_lidtype
!= P_LWPID
||
1189 procset
->p_ridtype
!= P_LWPID
)
1190 err_proc
= dotoprocs(procset
, setprocprio
, (char *)pcprio
);
1192 if (procset
->p_lidtype
== P_LWPID
|| procset
->p_ridtype
== P_LWPID
) {
1193 err_thread
= dotolwp(procset
, setthreadprio
, (char *)pcprio
);
1195 * dotolwp() can return with p_lock held. This is required
1196 * for the priocntl GETPARMS case. So, here we just release
1199 if (MUTEX_HELD(&curproc
->p_lock
))
1200 mutex_exit(&curproc
->p_lock
);
1203 * If we were called for a single LWP, then ignore ESRCH
1204 * returned by the previous dotoprocs() call.
1206 if (err_proc
== ESRCH
)
1211 * dotoprocs() ignores the init process if it is in the set, unless
1212 * it was the only process found. We want to make sure init is not
1213 * excluded if we're going PC_GETPRIO operation.
1215 if (pcprio
->pc_op
== PC_GETPRIO
) {
1218 mutex_enter(&pidlock
);
1219 if ((initpp
= prfind(P_INITPID
)) != NULL
) {
1220 mutex_enter(&initpp
->p_lock
);
1221 if (procinset(initpp
, procset
)) {
1222 mutex_exit(&initpp
->p_lock
);
1223 err
= setprocprio(initpp
, pcprio
);
1225 mutex_exit(&initpp
->p_lock
);
1228 mutex_exit(&pidlock
);
1232 * We're returning the latest error here that we've got back from
1233 * the setthreadprio() or setprocprio(). That is, err_thread and/or
1234 * err_proc can be replaced by err.
1237 err
= err_thread
? err_thread
: err_proc
;