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