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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 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. 12 * 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] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 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 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include <sys/types.h> 33 #include <sys/param.h> 34 #include <sys/sysmacros.h> 35 #include <sys/cred.h> 36 #include <sys/proc.h> 37 #include <sys/pcb.h> 38 #include <sys/signal.h> 39 #include <sys/user.h> 40 #include <sys/priocntl.h> 41 #include <sys/class.h> 42 #include <sys/disp.h> 43 #include <sys/procset.h> 44 #include <sys/cmn_err.h> 45 #include <sys/debug.h> 46 #include <sys/rt.h> 47 #include <sys/rtpriocntl.h> 48 #include <sys/kmem.h> 49 #include <sys/systm.h> 50 #include <sys/schedctl.h> 51 #include <sys/errno.h> 52 #include <sys/cpuvar.h> 53 #include <sys/vmsystm.h> 54 #include <sys/time.h> 55 #include <sys/policy.h> 56 #include <sys/sdt.h> 57 #include <sys/cpupart.h> 58 #include <sys/modctl.h> 59 60 static pri_t rt_init(id_t, int, classfuncs_t **); 61 62 static struct sclass csw = { 63 "RT", 64 rt_init, 65 0 66 }; 67 68 static struct modlsched modlsched = { 69 &mod_schedops, "realtime scheduling class", &csw 70 }; 71 72 static struct modlinkage modlinkage = { 73 MODREV_1, (void *)&modlsched, NULL 74 }; 75 76 int 77 _init() 78 { 79 return (mod_install(&modlinkage)); 80 } 81 82 int 83 _fini() 84 { 85 return (EBUSY); /* don't remove RT for now */ 86 } 87 88 int 89 _info(struct modinfo *modinfop) 90 { 91 return (mod_info(&modlinkage, modinfop)); 92 } 93 94 95 /* 96 * Class specific code for the real-time class 97 */ 98 99 /* 100 * Extern declarations for variables defined in the rt master file 101 */ 102 #define RTMAXPRI 59 103 104 pri_t rt_maxpri = RTMAXPRI; /* maximum real-time priority */ 105 rtdpent_t *rt_dptbl; /* real-time dispatcher parameter table */ 106 107 /* 108 * control flags (kparms->rt_cflags). 109 */ 110 #define RT_DOPRI 0x01 /* change priority */ 111 #define RT_DOTQ 0x02 /* change RT time quantum */ 112 #define RT_DOSIG 0x04 /* change RT time quantum signal */ 113 114 static int rt_admin(caddr_t, cred_t *); 115 static int rt_enterclass(kthread_t *, id_t, void *, cred_t *, void *); 116 static int rt_fork(kthread_t *, kthread_t *, void *); 117 static int rt_getclinfo(void *); 118 static int rt_getclpri(pcpri_t *); 119 static int rt_parmsin(void *); 120 static int rt_parmsout(void *, pc_vaparms_t *); 121 static int rt_vaparmsin(void *, pc_vaparms_t *); 122 static int rt_vaparmsout(void *, pc_vaparms_t *); 123 static int rt_parmsset(kthread_t *, void *, id_t, cred_t *); 124 static int rt_donice(kthread_t *, cred_t *, int, int *); 125 static int rt_doprio(kthread_t *, cred_t *, int, int *); 126 static void rt_exitclass(void *); 127 static int rt_canexit(kthread_t *, cred_t *); 128 static void rt_forkret(kthread_t *, kthread_t *); 129 static void rt_nullsys(); 130 static void rt_parmsget(kthread_t *, void *); 131 static void rt_preempt(kthread_t *); 132 static void rt_setrun(kthread_t *); 133 static void rt_tick(kthread_t *); 134 static void rt_wakeup(kthread_t *); 135 static pri_t rt_swapin(kthread_t *, int); 136 static pri_t rt_swapout(kthread_t *, int); 137 static pri_t rt_globpri(kthread_t *); 138 static void rt_yield(kthread_t *); 139 static int rt_alloc(void **, int); 140 static void rt_free(void *); 141 142 static void rt_change_priority(kthread_t *, rtproc_t *); 143 144 static id_t rt_cid; /* real-time class ID */ 145 static rtproc_t rt_plisthead; /* dummy rtproc at head of rtproc list */ 146 static kmutex_t rt_dptblock; /* protects realtime dispatch table */ 147 static kmutex_t rt_list_lock; /* protects RT thread list */ 148 149 extern rtdpent_t *rt_getdptbl(void); 150 151 static struct classfuncs rt_classfuncs = { 152 /* class ops */ 153 rt_admin, 154 rt_getclinfo, 155 rt_parmsin, 156 rt_parmsout, 157 rt_vaparmsin, 158 rt_vaparmsout, 159 rt_getclpri, 160 rt_alloc, 161 rt_free, 162 /* thread ops */ 163 rt_enterclass, 164 rt_exitclass, 165 rt_canexit, 166 rt_fork, 167 rt_forkret, 168 rt_parmsget, 169 rt_parmsset, 170 rt_nullsys, /* stop */ 171 rt_nullsys, /* exit */ 172 rt_nullsys, /* active */ 173 rt_nullsys, /* inactive */ 174 rt_swapin, 175 rt_swapout, 176 rt_nullsys, /* trapret */ 177 rt_preempt, 178 rt_setrun, 179 rt_nullsys, /* sleep */ 180 rt_tick, 181 rt_wakeup, 182 rt_donice, 183 rt_globpri, 184 rt_nullsys, /* set_process_group */ 185 rt_yield, 186 rt_doprio, 187 }; 188 189 /* 190 * Real-time class initialization. Called by dispinit() at boot time. 191 * We can ignore the clparmsz argument since we know that the smallest 192 * possible parameter buffer is big enough for us. 193 */ 194 /* ARGSUSED */ 195 pri_t 196 rt_init(id_t cid, int clparmsz, classfuncs_t **clfuncspp) 197 { 198 rt_dptbl = rt_getdptbl(); 199 rt_cid = cid; /* Record our class ID */ 200 201 /* 202 * Initialize the rtproc list. 203 */ 204 rt_plisthead.rt_next = rt_plisthead.rt_prev = &rt_plisthead; 205 206 /* 207 * We're required to return a pointer to our classfuncs 208 * structure and the highest global priority value we use. 209 */ 210 *clfuncspp = &rt_classfuncs; 211 mutex_init(&rt_dptblock, NULL, MUTEX_DEFAULT, NULL); 212 mutex_init(&rt_list_lock, NULL, MUTEX_DEFAULT, NULL); 213 return (rt_dptbl[rt_maxpri].rt_globpri); 214 } 215 216 /* 217 * Get or reset the rt_dptbl values per the user's request. 218 */ 219 /* ARGSUSED */ 220 static int 221 rt_admin(caddr_t uaddr, cred_t *reqpcredp) 222 { 223 rtadmin_t rtadmin; 224 rtdpent_t *tmpdpp; 225 size_t userdpsz; 226 size_t rtdpsz; 227 int i; 228 229 if (get_udatamodel() == DATAMODEL_NATIVE) { 230 if (copyin(uaddr, &rtadmin, sizeof (rtadmin_t))) 231 return (EFAULT); 232 } 233 #ifdef _SYSCALL32_IMPL 234 else { 235 /* rtadmin struct from ILP32 callers */ 236 rtadmin32_t rtadmin32; 237 if (copyin(uaddr, &rtadmin32, sizeof (rtadmin32_t))) 238 return (EFAULT); 239 rtadmin.rt_dpents = 240 (struct rtdpent *)(uintptr_t)rtadmin32.rt_dpents; 241 rtadmin.rt_ndpents = rtadmin32.rt_ndpents; 242 rtadmin.rt_cmd = rtadmin32.rt_cmd; 243 } 244 #endif /* _SYSCALL32_IMPL */ 245 246 rtdpsz = (rt_maxpri + 1) * sizeof (rtdpent_t); 247 248 switch (rtadmin.rt_cmd) { 249 250 case RT_GETDPSIZE: 251 rtadmin.rt_ndpents = rt_maxpri + 1; 252 253 if (get_udatamodel() == DATAMODEL_NATIVE) { 254 if (copyout(&rtadmin, uaddr, sizeof (rtadmin_t))) 255 return (EFAULT); 256 } 257 #ifdef _SYSCALL32_IMPL 258 else { 259 /* return rtadmin struct to ILP32 callers */ 260 rtadmin32_t rtadmin32; 261 rtadmin32.rt_dpents = 262 (caddr32_t)(uintptr_t)rtadmin.rt_dpents; 263 rtadmin32.rt_ndpents = rtadmin.rt_ndpents; 264 rtadmin32.rt_cmd = rtadmin.rt_cmd; 265 if (copyout(&rtadmin32, uaddr, sizeof (rtadmin32_t))) 266 return (EFAULT); 267 } 268 #endif /* _SYSCALL32_IMPL */ 269 270 break; 271 272 case RT_GETDPTBL: 273 userdpsz = MIN(rtadmin.rt_ndpents * sizeof (rtdpent_t), 274 rtdpsz); 275 if (copyout(rt_dptbl, rtadmin.rt_dpents, userdpsz)) 276 return (EFAULT); 277 rtadmin.rt_ndpents = userdpsz / sizeof (rtdpent_t); 278 279 if (get_udatamodel() == DATAMODEL_NATIVE) { 280 if (copyout(&rtadmin, uaddr, sizeof (rtadmin_t))) 281 return (EFAULT); 282 } 283 #ifdef _SYSCALL32_IMPL 284 else { 285 /* return rtadmin struct to ILP32 callers */ 286 rtadmin32_t rtadmin32; 287 rtadmin32.rt_dpents = 288 (caddr32_t)(uintptr_t)rtadmin.rt_dpents; 289 rtadmin32.rt_ndpents = rtadmin.rt_ndpents; 290 rtadmin32.rt_cmd = rtadmin.rt_cmd; 291 if (copyout(&rtadmin32, uaddr, sizeof (rtadmin32_t))) 292 return (EFAULT); 293 } 294 #endif /* _SYSCALL32_IMPL */ 295 break; 296 297 case RT_SETDPTBL: 298 /* 299 * We require that the requesting process has sufficient 300 * priveleges. We also require that the table supplied by 301 * the user exactly match the current rt_dptbl in size. 302 */ 303 if (secpolicy_dispadm(reqpcredp) != 0) 304 return (EPERM); 305 if (rtadmin.rt_ndpents * sizeof (rtdpent_t) != rtdpsz) 306 return (EINVAL); 307 308 /* 309 * We read the user supplied table into a temporary buffer 310 * where the time quantum values are validated before 311 * being copied to the rt_dptbl. 312 */ 313 tmpdpp = kmem_alloc(rtdpsz, KM_SLEEP); 314 if (copyin(rtadmin.rt_dpents, tmpdpp, rtdpsz)) { 315 kmem_free(tmpdpp, rtdpsz); 316 return (EFAULT); 317 } 318 for (i = 0; i < rtadmin.rt_ndpents; i++) { 319 320 /* 321 * Validate the user supplied time quantum values. 322 */ 323 if (tmpdpp[i].rt_quantum <= 0 && 324 tmpdpp[i].rt_quantum != RT_TQINF) { 325 kmem_free(tmpdpp, rtdpsz); 326 return (EINVAL); 327 } 328 } 329 330 /* 331 * Copy the user supplied values over the current rt_dptbl 332 * values. The rt_globpri member is read-only so we don't 333 * overwrite it. 334 */ 335 mutex_enter(&rt_dptblock); 336 for (i = 0; i < rtadmin.rt_ndpents; i++) 337 rt_dptbl[i].rt_quantum = tmpdpp[i].rt_quantum; 338 mutex_exit(&rt_dptblock); 339 kmem_free(tmpdpp, rtdpsz); 340 break; 341 342 default: 343 return (EINVAL); 344 } 345 return (0); 346 } 347 348 349 /* 350 * Allocate a real-time class specific proc structure and 351 * initialize it with the parameters supplied. Also move thread 352 * to specified real-time priority. 353 */ 354 /* ARGSUSED */ 355 static int 356 rt_enterclass(kthread_t *t, id_t cid, void *parmsp, cred_t *reqpcredp, 357 void *bufp) 358 { 359 rtkparms_t *rtkparmsp = (rtkparms_t *)parmsp; 360 rtproc_t *rtpp; 361 362 /* 363 * For a thread to enter the real-time class the thread 364 * which initiates the request must be privileged. 365 * This may have been checked previously but if our 366 * caller passed us a credential structure we assume it 367 * hasn't and we check it here. 368 */ 369 if (reqpcredp != NULL && secpolicy_setpriority(reqpcredp) != 0) 370 return (EPERM); 371 372 rtpp = (rtproc_t *)bufp; 373 ASSERT(rtpp != NULL); 374 375 /* 376 * If this thread's lwp is swapped out, it will be brought in 377 * when it is put onto the runqueue. 378 * 379 * Now, Initialize the rtproc structure. 380 */ 381 if (rtkparmsp == NULL) { 382 /* 383 * Use default values 384 */ 385 rtpp->rt_pri = 0; 386 rtpp->rt_pquantum = rt_dptbl[0].rt_quantum; 387 rtpp->rt_tqsignal = 0; 388 } else { 389 /* 390 * Use supplied values 391 */ 392 if ((rtkparmsp->rt_cflags & RT_DOPRI) == 0) 393 rtpp->rt_pri = 0; 394 else 395 rtpp->rt_pri = rtkparmsp->rt_pri; 396 397 if (rtkparmsp->rt_tqntm == RT_TQINF) 398 rtpp->rt_pquantum = RT_TQINF; 399 else if (rtkparmsp->rt_tqntm == RT_TQDEF || 400 (rtkparmsp->rt_cflags & RT_DOTQ) == 0) 401 rtpp->rt_pquantum = rt_dptbl[rtpp->rt_pri].rt_quantum; 402 else 403 rtpp->rt_pquantum = rtkparmsp->rt_tqntm; 404 405 if ((rtkparmsp->rt_cflags & RT_DOSIG) == 0) 406 rtpp->rt_tqsignal = 0; 407 else 408 rtpp->rt_tqsignal = rtkparmsp->rt_tqsig; 409 } 410 rtpp->rt_flags = 0; 411 rtpp->rt_tp = t; 412 /* 413 * Reset thread priority 414 */ 415 thread_lock(t); 416 t->t_clfuncs = &(sclass[cid].cl_funcs->thread); 417 t->t_cid = cid; 418 t->t_cldata = (void *)rtpp; 419 t->t_schedflag &= ~TS_RUNQMATCH; 420 rt_change_priority(t, rtpp); 421 thread_unlock(t); 422 /* 423 * Link new structure into rtproc list 424 */ 425 mutex_enter(&rt_list_lock); 426 rtpp->rt_next = rt_plisthead.rt_next; 427 rtpp->rt_prev = &rt_plisthead; 428 rt_plisthead.rt_next->rt_prev = rtpp; 429 rt_plisthead.rt_next = rtpp; 430 mutex_exit(&rt_list_lock); 431 return (0); 432 } 433 434 435 /* 436 * Free rtproc structure of thread. 437 */ 438 static void 439 rt_exitclass(void *procp) 440 { 441 rtproc_t *rtprocp = (rtproc_t *)procp; 442 443 mutex_enter(&rt_list_lock); 444 rtprocp->rt_prev->rt_next = rtprocp->rt_next; 445 rtprocp->rt_next->rt_prev = rtprocp->rt_prev; 446 mutex_exit(&rt_list_lock); 447 kmem_free(rtprocp, sizeof (rtproc_t)); 448 } 449 450 451 /* 452 * Allocate and initialize real-time class specific 453 * proc structure for child. 454 */ 455 /* ARGSUSED */ 456 static int 457 rt_fork(kthread_t *t, kthread_t *ct, void *bufp) 458 { 459 rtproc_t *prtpp; 460 rtproc_t *crtpp; 461 462 ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock)); 463 464 /* 465 * Initialize child's rtproc structure 466 */ 467 crtpp = (rtproc_t *)bufp; 468 ASSERT(crtpp != NULL); 469 prtpp = (rtproc_t *)t->t_cldata; 470 thread_lock(t); 471 crtpp->rt_timeleft = crtpp->rt_pquantum = prtpp->rt_pquantum; 472 crtpp->rt_pri = prtpp->rt_pri; 473 crtpp->rt_flags = prtpp->rt_flags & ~RTBACKQ; 474 crtpp->rt_tqsignal = prtpp->rt_tqsignal; 475 476 crtpp->rt_tp = ct; 477 thread_unlock(t); 478 479 /* 480 * Link new structure into rtproc list 481 */ 482 ct->t_cldata = (void *)crtpp; 483 mutex_enter(&rt_list_lock); 484 crtpp->rt_next = rt_plisthead.rt_next; 485 crtpp->rt_prev = &rt_plisthead; 486 rt_plisthead.rt_next->rt_prev = crtpp; 487 rt_plisthead.rt_next = crtpp; 488 mutex_exit(&rt_list_lock); 489 return (0); 490 } 491 492 493 /* 494 * The child goes to the back of its dispatcher queue while the 495 * parent continues to run after a real time thread forks. 496 */ 497 /* ARGSUSED */ 498 static void 499 rt_forkret(kthread_t *t, kthread_t *ct) 500 { 501 proc_t *pp = ttoproc(t); 502 proc_t *cp = ttoproc(ct); 503 504 ASSERT(t == curthread); 505 ASSERT(MUTEX_HELD(&pidlock)); 506 507 /* 508 * Grab the child's p_lock before dropping pidlock to ensure 509 * the process does not disappear before we set it running. 510 */ 511 mutex_enter(&cp->p_lock); 512 mutex_exit(&pidlock); 513 continuelwps(cp); 514 mutex_exit(&cp->p_lock); 515 516 mutex_enter(&pp->p_lock); 517 continuelwps(pp); 518 mutex_exit(&pp->p_lock); 519 } 520 521 522 /* 523 * Get information about the real-time class into the buffer 524 * pointed to by rtinfop. The maximum configured real-time 525 * priority is the only information we supply. We ignore the 526 * class and credential arguments because anyone can have this 527 * information. 528 */ 529 /* ARGSUSED */ 530 static int 531 rt_getclinfo(void *infop) 532 { 533 rtinfo_t *rtinfop = (rtinfo_t *)infop; 534 rtinfop->rt_maxpri = rt_maxpri; 535 return (0); 536 } 537 538 /* 539 * Return the user mode scheduling priority range. 540 */ 541 static int 542 rt_getclpri(pcpri_t *pcprip) 543 { 544 pcprip->pc_clpmax = rt_maxpri; 545 pcprip->pc_clpmin = 0; 546 return (0); 547 } 548 549 static void 550 rt_nullsys() 551 { 552 } 553 554 /* ARGSUSED */ 555 static int 556 rt_canexit(kthread_t *t, cred_t *cred) 557 { 558 /* 559 * Thread can always leave RT class 560 */ 561 return (0); 562 } 563 564 /* 565 * Get the real-time scheduling parameters of the thread pointed to by 566 * rtprocp into the buffer pointed to by rtkparmsp. 567 */ 568 static void 569 rt_parmsget(kthread_t *t, void *parmsp) 570 { 571 rtproc_t *rtprocp = (rtproc_t *)t->t_cldata; 572 rtkparms_t *rtkparmsp = (rtkparms_t *)parmsp; 573 574 rtkparmsp->rt_pri = rtprocp->rt_pri; 575 rtkparmsp->rt_tqntm = rtprocp->rt_pquantum; 576 rtkparmsp->rt_tqsig = rtprocp->rt_tqsignal; 577 } 578 579 580 581 /* 582 * Check the validity of the real-time parameters in the buffer 583 * pointed to by rtprmsp. 584 * We convert the rtparms buffer from the user supplied format to 585 * our internal format (i.e. time quantum expressed in ticks). 586 */ 587 static int 588 rt_parmsin(void *prmsp) 589 { 590 rtparms_t *rtprmsp = (rtparms_t *)prmsp; 591 longlong_t ticks; 592 uint_t cflags; 593 594 /* 595 * First check the validity of parameters and convert 596 * the buffer to kernel format. 597 */ 598 if ((rtprmsp->rt_pri < 0 || rtprmsp->rt_pri > rt_maxpri) && 599 rtprmsp->rt_pri != RT_NOCHANGE) 600 return (EINVAL); 601 602 cflags = (rtprmsp->rt_pri != RT_NOCHANGE ? RT_DOPRI : 0); 603 604 if ((rtprmsp->rt_tqsecs == 0 && rtprmsp->rt_tqnsecs == 0) || 605 rtprmsp->rt_tqnsecs >= NANOSEC) 606 return (EINVAL); 607 608 if (rtprmsp->rt_tqnsecs != RT_NOCHANGE) 609 cflags |= RT_DOTQ; 610 611 if (rtprmsp->rt_tqnsecs >= 0) { 612 if ((ticks = SEC_TO_TICK((longlong_t)rtprmsp->rt_tqsecs) + 613 NSEC_TO_TICK_ROUNDUP(rtprmsp->rt_tqnsecs)) > INT_MAX) 614 return (ERANGE); 615 616 ((rtkparms_t *)rtprmsp)->rt_tqntm = (int)ticks; 617 } else { 618 if (rtprmsp->rt_tqnsecs != RT_NOCHANGE && 619 rtprmsp->rt_tqnsecs != RT_TQINF && 620 rtprmsp->rt_tqnsecs != RT_TQDEF) 621 return (EINVAL); 622 623 ((rtkparms_t *)rtprmsp)->rt_tqntm = rtprmsp->rt_tqnsecs; 624 } 625 ((rtkparms_t *)rtprmsp)->rt_cflags = cflags; 626 627 return (0); 628 } 629 630 631 /* 632 * Check the validity of the real-time parameters in the pc_vaparms_t 633 * structure vaparmsp and put them in the buffer pointed to by rtprmsp. 634 * pc_vaparms_t contains (key, value) pairs of parameter. 635 * rt_vaparmsin() is the variable parameter version of rt_parmsin(). 636 */ 637 static int 638 rt_vaparmsin(void *prmsp, pc_vaparms_t *vaparmsp) 639 { 640 uint_t secs = 0; 641 uint_t cnt; 642 int nsecs = 0; 643 int priflag, secflag, nsecflag, sigflag; 644 longlong_t ticks; 645 rtkparms_t *rtprmsp = (rtkparms_t *)prmsp; 646 pc_vaparm_t *vpp = &vaparmsp->pc_parms[0]; 647 648 649 /* 650 * First check the validity of parameters and convert them 651 * from the user supplied format to the internal format. 652 */ 653 priflag = secflag = nsecflag = sigflag = 0; 654 rtprmsp->rt_cflags = 0; 655 656 if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT) 657 return (EINVAL); 658 659 for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) { 660 661 switch (vpp->pc_key) { 662 case RT_KY_PRI: 663 if (priflag++) 664 return (EINVAL); 665 rtprmsp->rt_cflags |= RT_DOPRI; 666 rtprmsp->rt_pri = (pri_t)vpp->pc_parm; 667 if (rtprmsp->rt_pri < 0 || rtprmsp->rt_pri > rt_maxpri) 668 return (EINVAL); 669 break; 670 671 case RT_KY_TQSECS: 672 if (secflag++) 673 return (EINVAL); 674 rtprmsp->rt_cflags |= RT_DOTQ; 675 secs = (uint_t)vpp->pc_parm; 676 break; 677 678 case RT_KY_TQNSECS: 679 if (nsecflag++) 680 return (EINVAL); 681 rtprmsp->rt_cflags |= RT_DOTQ; 682 nsecs = (int)vpp->pc_parm; 683 break; 684 685 case RT_KY_TQSIG: 686 if (sigflag++) 687 return (EINVAL); 688 rtprmsp->rt_cflags |= RT_DOSIG; 689 rtprmsp->rt_tqsig = (int)vpp->pc_parm; 690 if (rtprmsp->rt_tqsig < 0 || rtprmsp->rt_tqsig >= NSIG) 691 return (EINVAL); 692 break; 693 694 default: 695 return (EINVAL); 696 } 697 } 698 699 if (vaparmsp->pc_vaparmscnt == 0) { 700 /* 701 * Use default parameters. 702 */ 703 rtprmsp->rt_pri = 0; 704 rtprmsp->rt_tqntm = RT_TQDEF; 705 rtprmsp->rt_tqsig = 0; 706 rtprmsp->rt_cflags = RT_DOPRI | RT_DOTQ | RT_DOSIG; 707 } else if ((rtprmsp->rt_cflags & RT_DOTQ) != 0) { 708 if ((secs == 0 && nsecs == 0) || nsecs >= NANOSEC) 709 return (EINVAL); 710 711 if (nsecs >= 0) { 712 if ((ticks = SEC_TO_TICK((longlong_t)secs) + 713 NSEC_TO_TICK_ROUNDUP(nsecs)) > INT_MAX) 714 return (ERANGE); 715 716 rtprmsp->rt_tqntm = (int)ticks; 717 } else { 718 if (nsecs != RT_TQINF && nsecs != RT_TQDEF) 719 return (EINVAL); 720 rtprmsp->rt_tqntm = nsecs; 721 } 722 } 723 724 return (0); 725 } 726 727 /* 728 * Do required processing on the real-time parameter buffer 729 * before it is copied out to the user. 730 * All we have to do is convert the buffer from kernel to user format 731 * (i.e. convert time quantum from ticks to seconds-nanoseconds). 732 */ 733 /* ARGSUSED */ 734 static int 735 rt_parmsout(void *prmsp, pc_vaparms_t *vaparmsp) 736 { 737 rtkparms_t *rtkprmsp = (rtkparms_t *)prmsp; 738 739 if (vaparmsp != NULL) 740 return (0); 741 742 if (rtkprmsp->rt_tqntm < 0) { 743 /* 744 * Quantum field set to special value (e.g. RT_TQINF) 745 */ 746 ((rtparms_t *)rtkprmsp)->rt_tqnsecs = rtkprmsp->rt_tqntm; 747 ((rtparms_t *)rtkprmsp)->rt_tqsecs = 0; 748 } else { 749 /* Convert quantum from ticks to seconds-nanoseconds */ 750 751 timestruc_t ts; 752 TICK_TO_TIMESTRUC(rtkprmsp->rt_tqntm, &ts); 753 ((rtparms_t *)rtkprmsp)->rt_tqsecs = ts.tv_sec; 754 ((rtparms_t *)rtkprmsp)->rt_tqnsecs = ts.tv_nsec; 755 } 756 757 return (0); 758 } 759 760 761 /* 762 * Copy all selected real-time class parameters to the user. 763 * The parameters are specified by a key. 764 */ 765 static int 766 rt_vaparmsout(void *prmsp, pc_vaparms_t *vaparmsp) 767 { 768 rtkparms_t *rtkprmsp = (rtkparms_t *)prmsp; 769 timestruc_t ts; 770 uint_t cnt; 771 uint_t secs; 772 int nsecs; 773 int priflag, secflag, nsecflag, sigflag; 774 pc_vaparm_t *vpp = &vaparmsp->pc_parms[0]; 775 776 ASSERT(MUTEX_NOT_HELD(&curproc->p_lock)); 777 778 priflag = secflag = nsecflag = sigflag = 0; 779 780 if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT) 781 return (EINVAL); 782 783 if (rtkprmsp->rt_tqntm < 0) { 784 /* 785 * Quantum field set to special value (e.g. RT_TQINF). 786 */ 787 secs = 0; 788 nsecs = rtkprmsp->rt_tqntm; 789 } else { 790 /* 791 * Convert quantum from ticks to seconds-nanoseconds. 792 */ 793 TICK_TO_TIMESTRUC(rtkprmsp->rt_tqntm, &ts); 794 secs = ts.tv_sec; 795 nsecs = ts.tv_nsec; 796 } 797 798 799 for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) { 800 801 switch (vpp->pc_key) { 802 case RT_KY_PRI: 803 if (priflag++) 804 return (EINVAL); 805 if (copyout(&rtkprmsp->rt_pri, 806 (caddr_t)(uintptr_t)vpp->pc_parm, sizeof (pri_t))) 807 return (EFAULT); 808 break; 809 810 case RT_KY_TQSECS: 811 if (secflag++) 812 return (EINVAL); 813 if (copyout(&secs, (caddr_t)(uintptr_t)vpp->pc_parm, 814 sizeof (uint_t))) 815 return (EFAULT); 816 break; 817 818 case RT_KY_TQNSECS: 819 if (nsecflag++) 820 return (EINVAL); 821 if (copyout(&nsecs, (caddr_t)(uintptr_t)vpp->pc_parm, 822 sizeof (int))) 823 return (EFAULT); 824 break; 825 826 case RT_KY_TQSIG: 827 if (sigflag++) 828 return (EINVAL); 829 if (copyout(&rtkprmsp->rt_tqsig, 830 (caddr_t)(uintptr_t)vpp->pc_parm, sizeof (int))) 831 return (EFAULT); 832 break; 833 834 default: 835 return (EINVAL); 836 } 837 } 838 839 return (0); 840 } 841 842 843 /* 844 * Set the scheduling parameters of the thread pointed to by rtprocp 845 * to those specified in the buffer pointed to by rtkprmsp. 846 * Note that the parameters are expected to be in kernel format 847 * (i.e. time quantm expressed in ticks). Real time parameters copied 848 * in from the user should be processed by rt_parmsin() before they are 849 * passed to this function. 850 */ 851 static int 852 rt_parmsset(kthread_t *tx, void *prmsp, id_t reqpcid, cred_t *reqpcredp) 853 { 854 rtkparms_t *rtkprmsp = (rtkparms_t *)prmsp; 855 rtproc_t *rtpp = (rtproc_t *)tx->t_cldata; 856 857 ASSERT(MUTEX_HELD(&(ttoproc(tx))->p_lock)); 858 859 /* 860 * Basic permissions enforced by generic kernel code 861 * for all classes require that a thread attempting 862 * to change the scheduling parameters of a target thread 863 * be privileged or have a real or effective UID 864 * matching that of the target thread. We are not 865 * called unless these basic permission checks have 866 * already passed. The real-time class requires in addition 867 * that the requesting thread be real-time unless it is privileged. 868 * This may also have been checked previously but if our caller 869 * passes us a credential structure we assume it hasn't and 870 * we check it here. 871 */ 872 if (reqpcredp != NULL && reqpcid != rt_cid && 873 secpolicy_setpriority(reqpcredp) != 0) 874 return (EPERM); 875 876 thread_lock(tx); 877 if ((rtkprmsp->rt_cflags & RT_DOPRI) != 0) { 878 rtpp->rt_pri = rtkprmsp->rt_pri; 879 rt_change_priority(tx, rtpp); 880 } 881 if (rtkprmsp->rt_tqntm == RT_TQINF) 882 rtpp->rt_pquantum = RT_TQINF; 883 else if (rtkprmsp->rt_tqntm == RT_TQDEF) 884 rtpp->rt_timeleft = rtpp->rt_pquantum = 885 rt_dptbl[rtpp->rt_pri].rt_quantum; 886 else if ((rtkprmsp->rt_cflags & RT_DOTQ) != 0) 887 rtpp->rt_timeleft = rtpp->rt_pquantum = rtkprmsp->rt_tqntm; 888 889 if ((rtkprmsp->rt_cflags & RT_DOSIG) != 0) 890 rtpp->rt_tqsignal = rtkprmsp->rt_tqsig; 891 892 thread_unlock(tx); 893 return (0); 894 } 895 896 897 /* 898 * Arrange for thread to be placed in appropriate location 899 * on dispatcher queue. Runs at splhi() since the clock 900 * interrupt can cause RTBACKQ to be set. 901 */ 902 static void 903 rt_preempt(kthread_t *t) 904 { 905 rtproc_t *rtpp = (rtproc_t *)(t->t_cldata); 906 klwp_t *lwp; 907 908 ASSERT(THREAD_LOCK_HELD(t)); 909 910 /* 911 * If the state is user I allow swapping because I know I won't 912 * be holding any locks. 913 */ 914 if ((lwp = curthread->t_lwp) != NULL && lwp->lwp_state == LWP_USER) 915 t->t_schedflag &= ~TS_DONT_SWAP; 916 if ((rtpp->rt_flags & RTBACKQ) != 0) { 917 rtpp->rt_timeleft = rtpp->rt_pquantum; 918 rtpp->rt_flags &= ~RTBACKQ; 919 setbackdq(t); 920 } else 921 setfrontdq(t); 922 923 } 924 925 /* 926 * Return the global priority associated with this rt_pri. 927 */ 928 static pri_t 929 rt_globpri(kthread_t *t) 930 { 931 rtproc_t *rtprocp = (rtproc_t *)t->t_cldata; 932 return (rt_dptbl[rtprocp->rt_pri].rt_globpri); 933 } 934 935 static void 936 rt_setrun(kthread_t *t) 937 { 938 rtproc_t *rtpp = (rtproc_t *)(t->t_cldata); 939 940 ASSERT(THREAD_LOCK_HELD(t)); 941 942 rtpp->rt_timeleft = rtpp->rt_pquantum; 943 rtpp->rt_flags &= ~RTBACKQ; 944 setbackdq(t); 945 } 946 947 /* 948 * Returns the priority of the thread, -1 if the thread is loaded or ineligible 949 * for swapin. 950 * 951 * FX and RT threads are designed so that they don't swapout; however, it 952 * is possible that while the thread is swapped out and in another class, it 953 * can be changed to FX or RT. Since these threads should be swapped in as 954 * soon as they're runnable, rt_swapin returns SHRT_MAX, and fx_swapin 955 * returns SHRT_MAX - 1, so that it gives deference to any swapped out RT 956 * threads. 957 */ 958 /* ARGSUSED */ 959 static pri_t 960 rt_swapin(kthread_t *t, int flags) 961 { 962 pri_t tpri = -1; 963 964 ASSERT(THREAD_LOCK_HELD(t)); 965 966 if (t->t_state == TS_RUN && (t->t_schedflag & TS_LOAD) == 0) { 967 tpri = (pri_t)SHRT_MAX; 968 } 969 970 return (tpri); 971 } 972 973 /* 974 * Return an effective priority for swapout. 975 */ 976 /* ARGSUSED */ 977 static pri_t 978 rt_swapout(kthread_t *t, int flags) 979 { 980 ASSERT(THREAD_LOCK_HELD(t)); 981 982 return (-1); 983 } 984 985 /* 986 * Check for time slice expiration (unless thread has infinite time 987 * slice). If time slice has expired arrange for thread to be preempted 988 * and placed on back of queue. 989 */ 990 static void 991 rt_tick(kthread_t *t) 992 { 993 rtproc_t *rtpp = (rtproc_t *)(t->t_cldata); 994 995 ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock)); 996 997 thread_lock(t); 998 if ((rtpp->rt_pquantum != RT_TQINF && --rtpp->rt_timeleft == 0) || 999 (t->t_state == TS_ONPROC && DISP_MUST_SURRENDER(t))) { 1000 if (rtpp->rt_timeleft == 0 && rtpp->rt_tqsignal) { 1001 thread_unlock(t); 1002 sigtoproc(ttoproc(t), t, rtpp->rt_tqsignal); 1003 thread_lock(t); 1004 } 1005 rtpp->rt_flags |= RTBACKQ; 1006 cpu_surrender(t); 1007 } 1008 thread_unlock(t); 1009 } 1010 1011 1012 /* 1013 * Place the thread waking up on the dispatcher queue. 1014 */ 1015 static void 1016 rt_wakeup(kthread_t *t) 1017 { 1018 rtproc_t *rtpp = (rtproc_t *)(t->t_cldata); 1019 1020 ASSERT(THREAD_LOCK_HELD(t)); 1021 1022 rtpp->rt_timeleft = rtpp->rt_pquantum; 1023 rtpp->rt_flags &= ~RTBACKQ; 1024 setbackdq(t); 1025 } 1026 1027 static void 1028 rt_yield(kthread_t *t) 1029 { 1030 rtproc_t *rtpp = (rtproc_t *)(t->t_cldata); 1031 1032 ASSERT(t == curthread); 1033 ASSERT(THREAD_LOCK_HELD(t)); 1034 1035 rtpp->rt_flags &= ~RTBACKQ; 1036 setbackdq(t); 1037 } 1038 1039 /* ARGSUSED */ 1040 static int 1041 rt_donice(kthread_t *t, cred_t *cr, int incr, int *retvalp) 1042 { 1043 return (EINVAL); 1044 } 1045 1046 /* 1047 * Increment the priority of the specified thread by incr and 1048 * return the new value in *retvalp. 1049 */ 1050 static int 1051 rt_doprio(kthread_t *t, cred_t *cr, int incr, int *retvalp) 1052 { 1053 int newpri; 1054 rtproc_t *rtpp = (rtproc_t *)(t->t_cldata); 1055 rtkparms_t rtkparms; 1056 1057 /* If there's no change to the priority, just return current setting */ 1058 if (incr == 0) { 1059 *retvalp = rtpp->rt_pri; 1060 return (0); 1061 } 1062 1063 newpri = rtpp->rt_pri + incr; 1064 if (newpri > rt_maxpri || newpri < 0) 1065 return (EINVAL); 1066 1067 *retvalp = newpri; 1068 rtkparms.rt_pri = newpri; 1069 rtkparms.rt_tqntm = RT_NOCHANGE; 1070 rtkparms.rt_tqsig = 0; 1071 rtkparms.rt_cflags = RT_DOPRI; 1072 return (rt_parmsset(t, &rtkparms, rt_cid, cr)); 1073 } 1074 1075 static int 1076 rt_alloc(void **p, int flag) 1077 { 1078 void *bufp; 1079 bufp = kmem_alloc(sizeof (rtproc_t), flag); 1080 if (bufp == NULL) { 1081 return (ENOMEM); 1082 } else { 1083 *p = bufp; 1084 return (0); 1085 } 1086 } 1087 1088 static void 1089 rt_free(void *bufp) 1090 { 1091 if (bufp) 1092 kmem_free(bufp, sizeof (rtproc_t)); 1093 } 1094 1095 static void 1096 rt_change_priority(kthread_t *t, rtproc_t *rtpp) 1097 { 1098 pri_t new_pri; 1099 1100 ASSERT(THREAD_LOCK_HELD(t)); 1101 1102 new_pri = rt_dptbl[rtpp->rt_pri].rt_globpri; 1103 1104 t->t_cpri = rtpp->rt_pri; 1105 if (t == curthread || t->t_state == TS_ONPROC) { 1106 cpu_t *cp = t->t_disp_queue->disp_cpu; 1107 THREAD_CHANGE_PRI(t, new_pri); 1108 if (t == cp->cpu_dispthread) 1109 cp->cpu_dispatch_pri = DISP_PRIO(t); 1110 if (DISP_MUST_SURRENDER(t)) { 1111 rtpp->rt_flags |= RTBACKQ; 1112 cpu_surrender(t); 1113 } else { 1114 rtpp->rt_timeleft = rtpp->rt_pquantum; 1115 } 1116 } else { 1117 /* 1118 * When the priority of a thread is changed, 1119 * it may be necessary to adjust its position 1120 * on a sleep queue or dispatch queue. The 1121 * function thread_change_pri() accomplishes this. 1122 */ 1123 if (thread_change_pri(t, new_pri, 0)) { 1124 /* 1125 * The thread was on a run queue. 1126 * Reset its CPU timeleft. 1127 */ 1128 rtpp->rt_timeleft = rtpp->rt_pquantum; 1129 } else { 1130 rtpp->rt_flags |= RTBACKQ; 1131 } 1132 } 1133 } 1134