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 }