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