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