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