Print this page
    
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/disp/fx.c
          +++ new/usr/src/uts/common/disp/fx.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.
  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 (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
  24   24   * Copyright 2015, Joyent, Inc.
  25   25   */
  26   26  
  27   27  #include <sys/types.h>
  28   28  #include <sys/param.h>
  29   29  #include <sys/sysmacros.h>
  30   30  #include <sys/cred.h>
  31   31  #include <sys/proc.h>
  32   32  #include <sys/session.h>
  33   33  #include <sys/strsubr.h>
  34   34  #include <sys/user.h>
  35   35  #include <sys/priocntl.h>
  36   36  #include <sys/class.h>
  37   37  #include <sys/disp.h>
  38   38  #include <sys/procset.h>
  39   39  #include <sys/debug.h>
  40   40  #include <sys/kmem.h>
  41   41  #include <sys/errno.h>
  42   42  #include <sys/fx.h>
  43   43  #include <sys/fxpriocntl.h>
  44   44  #include <sys/cpuvar.h>
  45   45  #include <sys/systm.h>
  46   46  #include <sys/vtrace.h>
  47   47  #include <sys/schedctl.h>
  48   48  #include <sys/tnf_probe.h>
  49   49  #include <sys/sunddi.h>
  50   50  #include <sys/spl.h>
  51   51  #include <sys/modctl.h>
  52   52  #include <sys/policy.h>
  53   53  #include <sys/sdt.h>
  54   54  #include <sys/cpupart.h>
  55   55  #include <sys/cpucaps.h>
  56   56  
  57   57  static pri_t fx_init(id_t, int, classfuncs_t **);
  58   58  
  59   59  static struct sclass csw = {
  60   60          "FX",
  61   61          fx_init,
  62   62          0
  63   63  };
  64   64  
  65   65  static struct modlsched modlsched = {
  66   66          &mod_schedops, "Fixed priority sched class", &csw
  67   67  };
  68   68  
  69   69  static struct modlinkage modlinkage = {
  70   70          MODREV_1, (void *)&modlsched, NULL
  71   71  };
  72   72  
  73   73  
  74   74  #define FX_MAX_UNPRIV_PRI       0       /* maximum unpriviledge priority */
  75   75  
  76   76  /*
  77   77   * The fxproc_t structures that have a registered callback vector,
  78   78   * are also kept in an array of circular doubly linked lists. A hash on
  79   79   * the thread id (from ddi_get_kt_did()) is used to determine which list
  80   80   * each of such fxproc structures should be placed. Each list has a dummy
  81   81   * "head" which is never removed, so the list is never empty.
  82   82   */
  83   83  
  84   84  #define FX_CB_LISTS 16          /* number of lists, must be power of 2 */
  85   85  #define FX_CB_LIST_HASH(ktid)   ((uint_t)ktid & (FX_CB_LISTS - 1))
  86   86  
  87   87  /* Insert fxproc into callback list */
  88   88  #define FX_CB_LIST_INSERT(fxpp)                                         \
  89   89  {                                                                       \
  90   90          int index = FX_CB_LIST_HASH(fxpp->fx_ktid);                     \
  91   91          kmutex_t *lockp = &fx_cb_list_lock[index];                      \
  92   92          fxproc_t *headp = &fx_cb_plisthead[index];                      \
  93   93          mutex_enter(lockp);                                             \
  94   94          fxpp->fx_cb_next = headp->fx_cb_next;                           \
  95   95          fxpp->fx_cb_prev = headp;                                       \
  96   96          headp->fx_cb_next->fx_cb_prev = fxpp;                           \
  97   97          headp->fx_cb_next = fxpp;                                       \
  98   98          mutex_exit(lockp);                                              \
  99   99  }
 100  100  
 101  101  /*
 102  102   * Remove thread from callback list.
 103  103   */
 104  104  #define FX_CB_LIST_DELETE(fxpp)                                         \
 105  105  {                                                                       \
 106  106          int index = FX_CB_LIST_HASH(fxpp->fx_ktid);                     \
 107  107          kmutex_t *lockp = &fx_cb_list_lock[index];                      \
 108  108          mutex_enter(lockp);                                             \
 109  109          fxpp->fx_cb_prev->fx_cb_next = fxpp->fx_cb_next;                \
 110  110          fxpp->fx_cb_next->fx_cb_prev = fxpp->fx_cb_prev;                \
 111  111          mutex_exit(lockp);                                              \
 112  112  }
 113  113  
 114  114  #define FX_HAS_CB(fxpp) (fxpp->fx_callback != NULL)
 115  115  
 116  116  /* adjust x to be between 0 and fx_maxumdpri */
 117  117  
 118  118  #define FX_ADJUST_PRI(pri)                                              \
 119  119  {                                                                       \
 120  120          if (pri < 0)                                                    \
 121  121                  pri = 0;                                                \
 122  122          else if (pri > fx_maxumdpri)                                    \
 123  123                  pri = fx_maxumdpri;                                     \
 124  124  }
 125  125  
 126  126  #define FX_ADJUST_QUANTUM(q)                                            \
 127  127  {                                                                       \
 128  128          if (q > INT_MAX)                                                \
 129  129                  q = INT_MAX;                                            \
 130  130          else if (q <= 0)                                                \
 131  131                  q = FX_TQINF;                                           \
 132  132  }
 133  133  
 134  134  #define FX_ISVALID(pri, quantum) \
 135  135          (((pri >= 0) || (pri == FX_CB_NOCHANGE)) &&                     \
 136  136              ((quantum >= 0) || (quantum == FX_NOCHANGE) ||              \
 137  137                  (quantum == FX_TQDEF) || (quantum == FX_TQINF)))
 138  138  
 139  139  
 140  140  static id_t     fx_cid;         /* fixed priority class ID */
 141  141  static fxdpent_t *fx_dptbl;     /* fixed priority disp parameter table */
 142  142  
 143  143  static pri_t    fx_maxupri = FXMAXUPRI;
 144  144  static pri_t    fx_maxumdpri;   /* max user mode fixed priority */
 145  145  
 146  146  static pri_t    fx_maxglobpri;  /* maximum global priority used by fx class */
 147  147  static kmutex_t fx_dptblock;    /* protects fixed priority dispatch table */
 148  148  
 149  149  
 150  150  static kmutex_t fx_cb_list_lock[FX_CB_LISTS];   /* protects list of fxprocs */
 151  151                                                  /* that have callbacks */
 152  152  static fxproc_t fx_cb_plisthead[FX_CB_LISTS];   /* dummy fxproc at head of */
 153  153                                                  /* list of fxprocs with */
 154  154                                                  /* callbacks */
 155  155  
 156  156  static int      fx_admin(caddr_t, cred_t *);
 157  157  static int      fx_getclinfo(void *);
 158  158  static int      fx_parmsin(void *);
 159  159  static int      fx_parmsout(void *, pc_vaparms_t *);
 160  160  static int      fx_vaparmsin(void *, pc_vaparms_t *);
 161  161  static int      fx_vaparmsout(void *, pc_vaparms_t *);
 162  162  static int      fx_getclpri(pcpri_t *);
 163  163  static int      fx_alloc(void **, int);
 164  164  static void     fx_free(void *);
 165  165  static int      fx_enterclass(kthread_t *, id_t, void *, cred_t *, void *);
 166  166  static void     fx_exitclass(void *);
 167  167  static int      fx_canexit(kthread_t *, cred_t *);
 168  168  static int      fx_fork(kthread_t *, kthread_t *, void *);
 169  169  static void     fx_forkret(kthread_t *, kthread_t *);
 170  170  static void     fx_parmsget(kthread_t *, void *);
 171  171  static int      fx_parmsset(kthread_t *, void *, id_t, cred_t *);
 172  172  static void     fx_stop(kthread_t *, int, int);
 173  173  static void     fx_exit(kthread_t *);
 174  174  static pri_t    fx_swapin(kthread_t *, int);
 175  175  static pri_t    fx_swapout(kthread_t *, int);
 176  176  static void     fx_trapret(kthread_t *);
 177  177  static void     fx_preempt(kthread_t *);
 178  178  static void     fx_setrun(kthread_t *);
 179  179  static void     fx_sleep(kthread_t *);
 180  180  static void     fx_tick(kthread_t *);
 181  181  static void     fx_wakeup(kthread_t *);
 182  182  static int      fx_donice(kthread_t *, cred_t *, int, int *);
 183  183  static int      fx_doprio(kthread_t *, cred_t *, int, int *);
 184  184  static pri_t    fx_globpri(kthread_t *);
 185  185  static void     fx_yield(kthread_t *);
 186  186  static void     fx_nullsys();
 187  187  
 188  188  extern fxdpent_t *fx_getdptbl(void);
 189  189  
 190  190  static void     fx_change_priority(kthread_t *, fxproc_t *);
 191  191  static fxproc_t *fx_list_lookup(kt_did_t);
 192  192  static void fx_list_release(fxproc_t *);
 193  193  
 194  194  
 195  195  static struct classfuncs fx_classfuncs = {
 196  196          /* class functions */
 197  197          fx_admin,
 198  198          fx_getclinfo,
 199  199          fx_parmsin,
 200  200          fx_parmsout,
 201  201          fx_vaparmsin,
 202  202          fx_vaparmsout,
 203  203          fx_getclpri,
 204  204          fx_alloc,
 205  205          fx_free,
 206  206  
 207  207          /* thread functions */
 208  208          fx_enterclass,
 209  209          fx_exitclass,
 210  210          fx_canexit,
 211  211          fx_fork,
 212  212          fx_forkret,
 213  213          fx_parmsget,
 214  214          fx_parmsset,
 215  215          fx_stop,
 216  216          fx_exit,
 217  217          fx_nullsys,     /* active */
 218  218          fx_nullsys,     /* inactive */
 219  219          fx_swapin,
 220  220          fx_swapout,
 221  221          fx_trapret,
 222  222          fx_preempt,
 223  223          fx_setrun,
 224  224          fx_sleep,
 225  225          fx_tick,
 226  226          fx_wakeup,
 227  227          fx_donice,
 228  228          fx_globpri,
 229  229          fx_nullsys,     /* set_process_group */
 230  230          fx_yield,
 231  231          fx_doprio,
 232  232  };
 233  233  
 234  234  
 235  235  int
 236  236  _init()
 237  237  {
 238  238          return (mod_install(&modlinkage));
 239  239  }
 240  240  
 241  241  int
 242  242  _fini()
 243  243  {
 244  244          return (EBUSY);
 245  245  }
 246  246  
 247  247  int
 248  248  _info(struct modinfo *modinfop)
 249  249  {
 250  250          return (mod_info(&modlinkage, modinfop));
 251  251  }
 252  252  
 253  253  /*
 254  254   * Fixed priority class initialization. Called by dispinit() at boot time.
 255  255   * We can ignore the clparmsz argument since we know that the smallest
 256  256   * possible parameter buffer is big enough for us.
 257  257   */
 258  258  /* ARGSUSED */
 259  259  static pri_t
 260  260  fx_init(id_t cid, int clparmsz, classfuncs_t **clfuncspp)
 261  261  {
 262  262          int i;
 263  263          extern pri_t fx_getmaxumdpri(void);
 264  264  
 265  265          fx_dptbl = fx_getdptbl();
 266  266          fx_maxumdpri = fx_getmaxumdpri();
 267  267          fx_maxglobpri = fx_dptbl[fx_maxumdpri].fx_globpri;
 268  268  
 269  269          fx_cid = cid;           /* Record our class ID */
 270  270  
 271  271          /*
 272  272           * Initialize the hash table for fxprocs with callbacks
 273  273           */
 274  274          for (i = 0; i < FX_CB_LISTS; i++) {
 275  275                  fx_cb_plisthead[i].fx_cb_next = fx_cb_plisthead[i].fx_cb_prev =
 276  276                      &fx_cb_plisthead[i];
 277  277          }
 278  278  
 279  279          /*
 280  280           * We're required to return a pointer to our classfuncs
 281  281           * structure and the highest global priority value we use.
 282  282           */
 283  283          *clfuncspp = &fx_classfuncs;
 284  284          return (fx_maxglobpri);
 285  285  }
 286  286  
 287  287  /*
 288  288   * Get or reset the fx_dptbl values per the user's request.
 289  289   */
 290  290  static int
 291  291  fx_admin(caddr_t uaddr, cred_t *reqpcredp)
 292  292  {
 293  293          fxadmin_t       fxadmin;
 294  294          fxdpent_t       *tmpdpp;
 295  295          int             userdpsz;
 296  296          int             i;
 297  297          size_t          fxdpsz;
 298  298  
 299  299          if (get_udatamodel() == DATAMODEL_NATIVE) {
 300  300                  if (copyin(uaddr, &fxadmin, sizeof (fxadmin_t)))
 301  301                          return (EFAULT);
 302  302          }
 303  303  #ifdef _SYSCALL32_IMPL
 304  304          else {
 305  305                  /* get fxadmin struct from ILP32 caller */
 306  306                  fxadmin32_t fxadmin32;
 307  307                  if (copyin(uaddr, &fxadmin32, sizeof (fxadmin32_t)))
 308  308                          return (EFAULT);
 309  309                  fxadmin.fx_dpents =
 310  310                      (struct fxdpent *)(uintptr_t)fxadmin32.fx_dpents;
 311  311                  fxadmin.fx_ndpents = fxadmin32.fx_ndpents;
 312  312                  fxadmin.fx_cmd = fxadmin32.fx_cmd;
 313  313          }
 314  314  #endif /* _SYSCALL32_IMPL */
 315  315  
 316  316          fxdpsz = (fx_maxumdpri + 1) * sizeof (fxdpent_t);
 317  317  
 318  318          switch (fxadmin.fx_cmd) {
 319  319          case FX_GETDPSIZE:
 320  320                  fxadmin.fx_ndpents = fx_maxumdpri + 1;
 321  321  
 322  322                  if (get_udatamodel() == DATAMODEL_NATIVE) {
 323  323                          if (copyout(&fxadmin, uaddr, sizeof (fxadmin_t)))
 324  324                                  return (EFAULT);
 325  325                  }
 326  326  #ifdef _SYSCALL32_IMPL
 327  327                  else {
 328  328                          /* return fxadmin struct to ILP32 caller */
 329  329                          fxadmin32_t fxadmin32;
 330  330                          fxadmin32.fx_dpents =
 331  331                              (caddr32_t)(uintptr_t)fxadmin.fx_dpents;
 332  332                          fxadmin32.fx_ndpents = fxadmin.fx_ndpents;
 333  333                          fxadmin32.fx_cmd = fxadmin.fx_cmd;
 334  334                          if (copyout(&fxadmin32, uaddr, sizeof (fxadmin32_t)))
 335  335                                  return (EFAULT);
 336  336                  }
 337  337  #endif /* _SYSCALL32_IMPL */
 338  338                  break;
 339  339  
 340  340          case FX_GETDPTBL:
 341  341                  userdpsz = MIN(fxadmin.fx_ndpents * sizeof (fxdpent_t),
 342  342                      fxdpsz);
 343  343                  if (copyout(fx_dptbl, fxadmin.fx_dpents, userdpsz))
 344  344                          return (EFAULT);
 345  345  
 346  346                  fxadmin.fx_ndpents = userdpsz / sizeof (fxdpent_t);
 347  347  
 348  348                  if (get_udatamodel() == DATAMODEL_NATIVE) {
 349  349                          if (copyout(&fxadmin, uaddr, sizeof (fxadmin_t)))
 350  350                                  return (EFAULT);
 351  351                  }
 352  352  #ifdef _SYSCALL32_IMPL
 353  353                  else {
 354  354                          /* return fxadmin struct to ILP32 callers */
 355  355                          fxadmin32_t fxadmin32;
 356  356                          fxadmin32.fx_dpents =
 357  357                              (caddr32_t)(uintptr_t)fxadmin.fx_dpents;
 358  358                          fxadmin32.fx_ndpents = fxadmin.fx_ndpents;
 359  359                          fxadmin32.fx_cmd = fxadmin.fx_cmd;
 360  360                          if (copyout(&fxadmin32, uaddr, sizeof (fxadmin32_t)))
 361  361                                  return (EFAULT);
 362  362                  }
 363  363  #endif /* _SYSCALL32_IMPL */
 364  364                  break;
 365  365  
 366  366          case FX_SETDPTBL:
 367  367                  /*
 368  368                   * We require that the requesting process has sufficient
 369  369                   * privileges. We also require that the table supplied by
 370  370                   * the user exactly match the current fx_dptbl in size.
 371  371                   */
 372  372                  if (secpolicy_dispadm(reqpcredp) != 0) {
 373  373                          return (EPERM);
 374  374                  }
 375  375                  if (fxadmin.fx_ndpents * sizeof (fxdpent_t) != fxdpsz) {
 376  376                          return (EINVAL);
 377  377                  }
 378  378  
 379  379                  /*
 380  380                   * We read the user supplied table into a temporary buffer
 381  381                   * where it is validated before being copied over the
 382  382                   * fx_dptbl.
 383  383                   */
 384  384                  tmpdpp = kmem_alloc(fxdpsz, KM_SLEEP);
 385  385                  if (copyin(fxadmin.fx_dpents, tmpdpp, fxdpsz)) {
 386  386                          kmem_free(tmpdpp, fxdpsz);
 387  387                          return (EFAULT);
 388  388                  }
 389  389                  for (i = 0; i < fxadmin.fx_ndpents; i++) {
 390  390  
 391  391                          /*
 392  392                           * Validate the user supplied values. All we are doing
 393  393                           * here is verifying that the values are within their
 394  394                           * allowable ranges and will not panic the system. We
 395  395                           * make no attempt to ensure that the resulting
 396  396                           * configuration makes sense or results in reasonable
 397  397                           * performance.
 398  398                           */
 399  399                          if (tmpdpp[i].fx_quantum <= 0 &&
 400  400                              tmpdpp[i].fx_quantum != FX_TQINF) {
 401  401                                  kmem_free(tmpdpp, fxdpsz);
 402  402                                  return (EINVAL);
 403  403                          }
 404  404                  }
 405  405  
 406  406                  /*
 407  407                   * Copy the user supplied values over the current fx_dptbl
 408  408                   * values. The fx_globpri member is read-only so we don't
 409  409                   * overwrite it.
 410  410                   */
 411  411                  mutex_enter(&fx_dptblock);
 412  412                  for (i = 0; i < fxadmin.fx_ndpents; i++) {
 413  413                          fx_dptbl[i].fx_quantum = tmpdpp[i].fx_quantum;
 414  414                  }
 415  415                  mutex_exit(&fx_dptblock);
 416  416                  kmem_free(tmpdpp, fxdpsz);
 417  417                  break;
 418  418  
 419  419          default:
 420  420                  return (EINVAL);
 421  421          }
 422  422          return (0);
 423  423  }
 424  424  
 425  425  /*
 426  426   * Allocate a fixed priority class specific thread structure and
 427  427   * initialize it with the parameters supplied. Also move the thread
 428  428   * to specified priority.
 429  429   */
 430  430  static int
 431  431  fx_enterclass(kthread_t *t, id_t cid, void *parmsp, cred_t *reqpcredp,
 432  432      void *bufp)
 433  433  {
 434  434          fxkparms_t      *fxkparmsp = (fxkparms_t *)parmsp;
 435  435          fxproc_t        *fxpp;
 436  436          pri_t           reqfxupri;
 437  437          pri_t           reqfxuprilim;
 438  438  
 439  439          fxpp = (fxproc_t *)bufp;
 440  440          ASSERT(fxpp != NULL);
 441  441  
 442  442          /*
 443  443           * Initialize the fxproc structure.
 444  444           */
 445  445          fxpp->fx_flags = 0;
 446  446          fxpp->fx_callback = NULL;
 447  447          fxpp->fx_cookie = NULL;
 448  448  
 449  449          if (fxkparmsp == NULL) {
 450  450                  /*
 451  451                   * Use default values.
 452  452                   */
 453  453                  fxpp->fx_pri = fxpp->fx_uprilim = 0;
 454  454                  fxpp->fx_pquantum = fx_dptbl[fxpp->fx_pri].fx_quantum;
 455  455                  fxpp->fx_nice =  NZERO;
 456  456          } else {
 457  457                  /*
 458  458                   * Use supplied values.
 459  459                   */
 460  460  
 461  461                  if ((fxkparmsp->fx_cflags & FX_DOUPRILIM) == 0) {
 462  462                          reqfxuprilim = 0;
 463  463                  } else {
 464  464                          if (fxkparmsp->fx_uprilim > FX_MAX_UNPRIV_PRI &&
 465  465                              secpolicy_setpriority(reqpcredp) != 0)
 466  466                                  return (EPERM);
 467  467                          reqfxuprilim = fxkparmsp->fx_uprilim;
 468  468                          FX_ADJUST_PRI(reqfxuprilim);
 469  469                  }
 470  470  
 471  471                  if ((fxkparmsp->fx_cflags & FX_DOUPRI) == 0) {
 472  472                          reqfxupri = reqfxuprilim;
 473  473                  } else {
 474  474                          if (fxkparmsp->fx_upri > FX_MAX_UNPRIV_PRI &&
 475  475                              secpolicy_setpriority(reqpcredp) != 0)
 476  476                                  return (EPERM);
 477  477                          /*
 478  478                           * Set the user priority to the requested value
 479  479                           * or the upri limit, whichever is lower.
 480  480                           */
 481  481                          reqfxupri = fxkparmsp->fx_upri;
 482  482                          FX_ADJUST_PRI(reqfxupri);
 483  483  
 484  484                          if (reqfxupri > reqfxuprilim)
 485  485                                  reqfxupri = reqfxuprilim;
 486  486                  }
 487  487  
 488  488  
 489  489                  fxpp->fx_uprilim = reqfxuprilim;
 490  490                  fxpp->fx_pri = reqfxupri;
 491  491  
 492  492                  fxpp->fx_nice = NZERO - (NZERO * reqfxupri) / fx_maxupri;
 493  493  
 494  494                  if (((fxkparmsp->fx_cflags & FX_DOTQ) == 0) ||
 495  495                      (fxkparmsp->fx_tqntm == FX_TQDEF)) {
 496  496                          fxpp->fx_pquantum = fx_dptbl[fxpp->fx_pri].fx_quantum;
 497  497                  } else {
 498  498                          if (secpolicy_setpriority(reqpcredp) != 0)
 499  499                                  return (EPERM);
 500  500  
 501  501                          if (fxkparmsp->fx_tqntm == FX_TQINF)
 502  502                                  fxpp->fx_pquantum = FX_TQINF;
 503  503                          else {
 504  504                                  fxpp->fx_pquantum = fxkparmsp->fx_tqntm;
 505  505                          }
 506  506                  }
 507  507  
 508  508          }
 509  509  
 510  510          fxpp->fx_timeleft = fxpp->fx_pquantum;
 511  511          cpucaps_sc_init(&fxpp->fx_caps);
 512  512          fxpp->fx_tp = t;
 513  513  
 514  514          thread_lock(t);                 /* get dispatcher lock on thread */
 515  515          t->t_clfuncs = &(sclass[cid].cl_funcs->thread);
 516  516          t->t_cid = cid;
 517  517          t->t_cldata = (void *)fxpp;
 518  518          t->t_schedflag &= ~TS_RUNQMATCH;
 519  519          fx_change_priority(t, fxpp);
 520  520          thread_unlock(t);
 521  521  
 522  522          return (0);
 523  523  }
 524  524  
 525  525  /*
 526  526   * The thread is exiting.
 527  527   */
 528  528  static void
 529  529  fx_exit(kthread_t *t)
 530  530  {
 531  531          fxproc_t *fxpp;
 532  532  
 533  533          thread_lock(t);
 534  534          fxpp = (fxproc_t *)(t->t_cldata);
 535  535  
 536  536          /*
 537  537           * A thread could be exiting in between clock ticks, so we need to
 538  538           * calculate how much CPU time it used since it was charged last time.
 539  539           *
 540  540           * CPU caps are not enforced on exiting processes - it is usually
 541  541           * desirable to exit as soon as possible to free resources.
 542  542           */
 543  543          (void) CPUCAPS_CHARGE(t, &fxpp->fx_caps, CPUCAPS_CHARGE_ONLY);
 544  544  
 545  545          if (FX_HAS_CB(fxpp)) {
 546  546                  FX_CB_EXIT(FX_CALLB(fxpp), fxpp->fx_cookie);
 547  547                  fxpp->fx_callback = NULL;
 548  548                  fxpp->fx_cookie = NULL;
 549  549                  thread_unlock(t);
 550  550                  FX_CB_LIST_DELETE(fxpp);
 551  551                  return;
 552  552          }
 553  553  
 554  554          thread_unlock(t);
 555  555  }
 556  556  
 557  557  /*
 558  558   * Exiting the class. Free fxproc structure of thread.
 559  559   */
 560  560  static void
 561  561  fx_exitclass(void *procp)
 562  562  {
 563  563          fxproc_t *fxpp = (fxproc_t *)procp;
 564  564  
 565  565          thread_lock(fxpp->fx_tp);
 566  566          if (FX_HAS_CB(fxpp)) {
 567  567  
 568  568                  FX_CB_EXIT(FX_CALLB(fxpp), fxpp->fx_cookie);
 569  569  
 570  570                  fxpp->fx_callback = NULL;
 571  571                  fxpp->fx_cookie = NULL;
 572  572                  thread_unlock(fxpp->fx_tp);
 573  573                  FX_CB_LIST_DELETE(fxpp);
 574  574          } else
 575  575                  thread_unlock(fxpp->fx_tp);
 576  576  
 577  577          kmem_free(fxpp, sizeof (fxproc_t));
 578  578  }
 579  579  
 580  580  /* ARGSUSED */
 581  581  static int
 582  582  fx_canexit(kthread_t *t, cred_t *cred)
 583  583  {
 584  584          /*
 585  585           * A thread can always leave the FX class
 586  586           */
 587  587          return (0);
 588  588  }
 589  589  
 590  590  /*
 591  591   * Initialize fixed-priority class specific proc structure for a child.
 592  592   * callbacks are not inherited upon fork.
 593  593   */
 594  594  static int
 595  595  fx_fork(kthread_t *t, kthread_t *ct, void *bufp)
 596  596  {
 597  597          fxproc_t        *pfxpp;         /* ptr to parent's fxproc structure */
 598  598          fxproc_t        *cfxpp;         /* ptr to child's fxproc structure */
 599  599  
 600  600          ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
 601  601  
 602  602          cfxpp = (fxproc_t *)bufp;
 603  603          ASSERT(cfxpp != NULL);
 604  604          thread_lock(t);
 605  605          pfxpp = (fxproc_t *)t->t_cldata;
 606  606          /*
 607  607           * Initialize child's fxproc structure.
 608  608           */
 609  609          cfxpp->fx_timeleft = cfxpp->fx_pquantum = pfxpp->fx_pquantum;
 610  610          cfxpp->fx_pri = pfxpp->fx_pri;
 611  611          cfxpp->fx_uprilim = pfxpp->fx_uprilim;
 612  612          cfxpp->fx_nice = pfxpp->fx_nice;
 613  613          cfxpp->fx_callback = NULL;
 614  614          cfxpp->fx_cookie = NULL;
 615  615          cfxpp->fx_flags = pfxpp->fx_flags & ~(FXBACKQ);
 616  616          cpucaps_sc_init(&cfxpp->fx_caps);
 617  617  
 618  618          cfxpp->fx_tp = ct;
 619  619          ct->t_cldata = (void *)cfxpp;
 620  620          thread_unlock(t);
 621  621  
 622  622          /*
 623  623           * Link new structure into fxproc list.
 624  624           */
 625  625          return (0);
 626  626  }
 627  627  
 628  628  
 629  629  /*
 630  630   * Child is placed at back of dispatcher queue and parent gives
 631  631   * up processor so that the child runs first after the fork.
 632  632   * This allows the child immediately execing to break the multiple
 633  633   * use of copy on write pages with no disk home. The parent will
 634  634   * get to steal them back rather than uselessly copying them.
 635  635   */
 636  636  static void
 637  637  fx_forkret(kthread_t *t, kthread_t *ct)
 638  638  {
 639  639          proc_t  *pp = ttoproc(t);
 640  640          proc_t  *cp = ttoproc(ct);
 641  641          fxproc_t *fxpp;
 642  642  
 643  643          ASSERT(t == curthread);
 644  644          ASSERT(MUTEX_HELD(&pidlock));
 645  645  
 646  646          /*
 647  647           * Grab the child's p_lock before dropping pidlock to ensure
 648  648           * the process does not disappear before we set it running.
 649  649           */
 650  650          mutex_enter(&cp->p_lock);
 651  651          continuelwps(cp);
 652  652          mutex_exit(&cp->p_lock);
 653  653  
 654  654          mutex_enter(&pp->p_lock);
 655  655          mutex_exit(&pidlock);
 656  656          continuelwps(pp);
 657  657  
 658  658          thread_lock(t);
 659  659          fxpp = (fxproc_t *)(t->t_cldata);
 660  660          t->t_pri = fx_dptbl[fxpp->fx_pri].fx_globpri;
 661  661          ASSERT(t->t_pri >= 0 && t->t_pri <= fx_maxglobpri);
 662  662          THREAD_TRANSITION(t);
 663  663          fx_setrun(t);
 664  664          thread_unlock(t);
 665  665          /*
 666  666           * Safe to drop p_lock now since it is safe to change
 667  667           * the scheduling class after this point.
 668  668           */
 669  669          mutex_exit(&pp->p_lock);
 670  670  
 671  671          swtch();
 672  672  }
 673  673  
 674  674  
 675  675  /*
 676  676   * Get information about the fixed-priority class into the buffer
 677  677   * pointed to by fxinfop. The maximum configured user priority
 678  678   * is the only information we supply.
 679  679   */
 680  680  static int
 681  681  fx_getclinfo(void *infop)
 682  682  {
 683  683          fxinfo_t *fxinfop = (fxinfo_t *)infop;
 684  684          fxinfop->fx_maxupri = fx_maxupri;
 685  685          return (0);
 686  686  }
 687  687  
 688  688  
 689  689  
 690  690  /*
 691  691   * Return the user mode scheduling priority range.
 692  692   */
 693  693  static int
 694  694  fx_getclpri(pcpri_t *pcprip)
 695  695  {
 696  696          pcprip->pc_clpmax = fx_maxupri;
 697  697          pcprip->pc_clpmin = 0;
 698  698          return (0);
 699  699  }
 700  700  
 701  701  
 702  702  static void
 703  703  fx_nullsys()
 704  704  {}
 705  705  
 706  706  
 707  707  /*
 708  708   * Get the fixed-priority parameters of the thread pointed to by
 709  709   * fxprocp into the buffer pointed to by fxparmsp.
 710  710   */
 711  711  static void
 712  712  fx_parmsget(kthread_t *t, void *parmsp)
 713  713  {
 714  714          fxproc_t *fxpp = (fxproc_t *)t->t_cldata;
 715  715          fxkparms_t *fxkparmsp = (fxkparms_t *)parmsp;
 716  716  
 717  717          fxkparmsp->fx_upri = fxpp->fx_pri;
 718  718          fxkparmsp->fx_uprilim = fxpp->fx_uprilim;
 719  719          fxkparmsp->fx_tqntm = fxpp->fx_pquantum;
 720  720  }
 721  721  
 722  722  
 723  723  
 724  724  /*
 725  725   * Check the validity of the fixed-priority parameters in the buffer
 726  726   * pointed to by fxparmsp.
 727  727   */
 728  728  static int
 729  729  fx_parmsin(void *parmsp)
 730  730  {
 731  731          fxparms_t       *fxparmsp = (fxparms_t *)parmsp;
 732  732          uint_t          cflags;
 733  733          longlong_t      ticks;
 734  734          /*
 735  735           * Check validity of parameters.
 736  736           */
 737  737  
 738  738          if ((fxparmsp->fx_uprilim > fx_maxupri ||
 739  739              fxparmsp->fx_uprilim < 0) &&
 740  740              fxparmsp->fx_uprilim != FX_NOCHANGE)
 741  741                  return (EINVAL);
 742  742  
 743  743          if ((fxparmsp->fx_upri > fx_maxupri ||
 744  744              fxparmsp->fx_upri < 0) &&
 745  745              fxparmsp->fx_upri != FX_NOCHANGE)
 746  746                  return (EINVAL);
 747  747  
 748  748          if ((fxparmsp->fx_tqsecs == 0 && fxparmsp->fx_tqnsecs == 0) ||
 749  749              fxparmsp->fx_tqnsecs >= NANOSEC)
 750  750                  return (EINVAL);
 751  751  
 752  752          cflags = (fxparmsp->fx_upri != FX_NOCHANGE ? FX_DOUPRI : 0);
 753  753  
 754  754          if (fxparmsp->fx_uprilim != FX_NOCHANGE) {
 755  755                  cflags |= FX_DOUPRILIM;
 756  756          }
 757  757  
 758  758          if (fxparmsp->fx_tqnsecs != FX_NOCHANGE)
 759  759                  cflags |= FX_DOTQ;
 760  760  
 761  761          /*
 762  762           * convert the buffer to kernel format.
 763  763           */
 764  764  
 765  765          if (fxparmsp->fx_tqnsecs >= 0) {
 766  766                  if ((ticks = SEC_TO_TICK((longlong_t)fxparmsp->fx_tqsecs) +
 767  767                      NSEC_TO_TICK_ROUNDUP(fxparmsp->fx_tqnsecs)) > INT_MAX)
 768  768                          return (ERANGE);
 769  769  
 770  770                  ((fxkparms_t *)fxparmsp)->fx_tqntm = (int)ticks;
 771  771          } else {
 772  772                  if ((fxparmsp->fx_tqnsecs != FX_NOCHANGE) &&
 773  773                      (fxparmsp->fx_tqnsecs != FX_TQINF) &&
 774  774                      (fxparmsp->fx_tqnsecs != FX_TQDEF))
 775  775                          return (EINVAL);
 776  776                  ((fxkparms_t *)fxparmsp)->fx_tqntm = fxparmsp->fx_tqnsecs;
 777  777          }
 778  778  
 779  779          ((fxkparms_t *)fxparmsp)->fx_cflags = cflags;
 780  780  
 781  781          return (0);
 782  782  }
 783  783  
 784  784  
 785  785  /*
 786  786   * Check the validity of the fixed-priority parameters in the pc_vaparms_t
 787  787   * structure vaparmsp and put them in the buffer pointed to by fxprmsp.
 788  788   * pc_vaparms_t contains (key, value) pairs of parameter.
 789  789   */
 790  790  static int
 791  791  fx_vaparmsin(void *prmsp, pc_vaparms_t *vaparmsp)
 792  792  {
 793  793          uint_t          secs = 0;
 794  794          uint_t          cnt;
 795  795          int             nsecs = 0;
 796  796          int             priflag, secflag, nsecflag, limflag;
 797  797          longlong_t      ticks;
 798  798          fxkparms_t      *fxprmsp = (fxkparms_t *)prmsp;
 799  799          pc_vaparm_t     *vpp = &vaparmsp->pc_parms[0];
 800  800  
 801  801  
 802  802          /*
 803  803           * First check the validity of parameters and convert them
 804  804           * from the user supplied format to the internal format.
 805  805           */
 806  806          priflag = secflag = nsecflag = limflag = 0;
 807  807  
 808  808          fxprmsp->fx_cflags = 0;
 809  809  
 810  810          if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
 811  811                  return (EINVAL);
 812  812  
 813  813          for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
 814  814  
 815  815                  switch (vpp->pc_key) {
 816  816                  case FX_KY_UPRILIM:
 817  817                          if (limflag++)
 818  818                                  return (EINVAL);
 819  819                          fxprmsp->fx_cflags |= FX_DOUPRILIM;
 820  820                          fxprmsp->fx_uprilim = (pri_t)vpp->pc_parm;
 821  821                          if (fxprmsp->fx_uprilim > fx_maxupri ||
 822  822                              fxprmsp->fx_uprilim < 0)
 823  823                                  return (EINVAL);
 824  824                          break;
 825  825  
 826  826                  case FX_KY_UPRI:
 827  827                          if (priflag++)
 828  828                                  return (EINVAL);
 829  829                          fxprmsp->fx_cflags |= FX_DOUPRI;
 830  830                          fxprmsp->fx_upri = (pri_t)vpp->pc_parm;
 831  831                          if (fxprmsp->fx_upri > fx_maxupri ||
 832  832                              fxprmsp->fx_upri < 0)
 833  833                                  return (EINVAL);
 834  834                          break;
 835  835  
 836  836                  case FX_KY_TQSECS:
 837  837                          if (secflag++)
 838  838                                  return (EINVAL);
 839  839                          fxprmsp->fx_cflags |= FX_DOTQ;
 840  840                          secs = (uint_t)vpp->pc_parm;
 841  841                          break;
 842  842  
 843  843                  case FX_KY_TQNSECS:
 844  844                          if (nsecflag++)
 845  845                                  return (EINVAL);
 846  846                          fxprmsp->fx_cflags |= FX_DOTQ;
 847  847                          nsecs = (int)vpp->pc_parm;
 848  848                          break;
 849  849  
 850  850                  default:
 851  851                          return (EINVAL);
 852  852                  }
 853  853          }
 854  854  
 855  855          if (vaparmsp->pc_vaparmscnt == 0) {
 856  856                  /*
 857  857                   * Use default parameters.
 858  858                   */
 859  859                  fxprmsp->fx_upri = 0;
 860  860                  fxprmsp->fx_uprilim = 0;
 861  861                  fxprmsp->fx_tqntm = FX_TQDEF;
 862  862                  fxprmsp->fx_cflags = FX_DOUPRI | FX_DOUPRILIM | FX_DOTQ;
 863  863          } else if ((fxprmsp->fx_cflags & FX_DOTQ) != 0) {
 864  864                  if ((secs == 0 && nsecs == 0) || nsecs >= NANOSEC)
 865  865                          return (EINVAL);
 866  866  
 867  867                  if (nsecs >= 0) {
 868  868                          if ((ticks = SEC_TO_TICK((longlong_t)secs) +
 869  869                              NSEC_TO_TICK_ROUNDUP(nsecs)) > INT_MAX)
 870  870                                  return (ERANGE);
 871  871  
 872  872                          fxprmsp->fx_tqntm = (int)ticks;
 873  873                  } else {
 874  874                          if (nsecs != FX_TQINF && nsecs != FX_TQDEF)
 875  875                                  return (EINVAL);
 876  876                          fxprmsp->fx_tqntm = nsecs;
 877  877                  }
 878  878          }
 879  879  
 880  880          return (0);
 881  881  }
 882  882  
 883  883  
 884  884  /*
 885  885   * Nothing to do here but return success.
 886  886   */
 887  887  /* ARGSUSED */
 888  888  static int
 889  889  fx_parmsout(void *parmsp, pc_vaparms_t *vaparmsp)
 890  890  {
 891  891          register fxkparms_t     *fxkprmsp = (fxkparms_t *)parmsp;
 892  892  
 893  893          if (vaparmsp != NULL)
 894  894                  return (0);
 895  895  
 896  896          if (fxkprmsp->fx_tqntm < 0) {
 897  897                  /*
 898  898                   * Quantum field set to special value (e.g. FX_TQINF)
 899  899                   */
 900  900                  ((fxparms_t *)fxkprmsp)->fx_tqnsecs = fxkprmsp->fx_tqntm;
 901  901                  ((fxparms_t *)fxkprmsp)->fx_tqsecs = 0;
 902  902  
 903  903          } else {
 904  904                  /* Convert quantum from ticks to seconds-nanoseconds */
 905  905  
 906  906                  timestruc_t ts;
 907  907                  TICK_TO_TIMESTRUC(fxkprmsp->fx_tqntm, &ts);
 908  908                  ((fxparms_t *)fxkprmsp)->fx_tqsecs = ts.tv_sec;
 909  909                  ((fxparms_t *)fxkprmsp)->fx_tqnsecs = ts.tv_nsec;
 910  910          }
 911  911  
 912  912          return (0);
 913  913  }
 914  914  
 915  915  
 916  916  /*
 917  917   * Copy all selected fixed-priority class parameters to the user.
 918  918   * The parameters are specified by a key.
 919  919   */
 920  920  static int
 921  921  fx_vaparmsout(void *prmsp, pc_vaparms_t *vaparmsp)
 922  922  {
 923  923          fxkparms_t      *fxkprmsp = (fxkparms_t *)prmsp;
 924  924          timestruc_t     ts;
 925  925          uint_t          cnt;
 926  926          uint_t          secs;
 927  927          int             nsecs;
 928  928          int             priflag, secflag, nsecflag, limflag;
 929  929          pc_vaparm_t     *vpp = &vaparmsp->pc_parms[0];
 930  930  
 931  931          ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
 932  932  
 933  933          priflag = secflag = nsecflag = limflag = 0;
 934  934  
 935  935          if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
 936  936                  return (EINVAL);
 937  937  
 938  938          if (fxkprmsp->fx_tqntm < 0) {
 939  939                  /*
 940  940                   * Quantum field set to special value (e.g. FX_TQINF).
 941  941                   */
 942  942                  secs = 0;
 943  943                  nsecs = fxkprmsp->fx_tqntm;
 944  944          } else {
 945  945                  /*
 946  946                   * Convert quantum from ticks to seconds-nanoseconds.
 947  947                   */
 948  948                  TICK_TO_TIMESTRUC(fxkprmsp->fx_tqntm, &ts);
 949  949                  secs = ts.tv_sec;
 950  950                  nsecs = ts.tv_nsec;
 951  951          }
 952  952  
 953  953  
 954  954          for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
 955  955  
 956  956                  switch (vpp->pc_key) {
 957  957                  case FX_KY_UPRILIM:
 958  958                          if (limflag++)
 959  959                                  return (EINVAL);
 960  960                          if (copyout(&fxkprmsp->fx_uprilim,
 961  961                              (void *)(uintptr_t)vpp->pc_parm, sizeof (pri_t)))
 962  962                                  return (EFAULT);
 963  963                          break;
 964  964  
 965  965                  case FX_KY_UPRI:
 966  966                          if (priflag++)
 967  967                                  return (EINVAL);
 968  968                          if (copyout(&fxkprmsp->fx_upri,
 969  969                              (void *)(uintptr_t)vpp->pc_parm, sizeof (pri_t)))
 970  970                                  return (EFAULT);
 971  971                          break;
 972  972  
 973  973                  case FX_KY_TQSECS:
 974  974                          if (secflag++)
 975  975                                  return (EINVAL);
 976  976                          if (copyout(&secs,
 977  977                              (void *)(uintptr_t)vpp->pc_parm, sizeof (uint_t)))
 978  978                                  return (EFAULT);
 979  979                          break;
 980  980  
 981  981                  case FX_KY_TQNSECS:
 982  982                          if (nsecflag++)
 983  983                                  return (EINVAL);
 984  984                          if (copyout(&nsecs,
 985  985                              (void *)(uintptr_t)vpp->pc_parm, sizeof (int)))
 986  986                                  return (EFAULT);
 987  987                          break;
 988  988  
 989  989                  default:
 990  990                          return (EINVAL);
 991  991                  }
 992  992          }
 993  993  
 994  994          return (0);
 995  995  }
 996  996  
 997  997  /*
 998  998   * Set the scheduling parameters of the thread pointed to by fxprocp
 999  999   * to those specified in the buffer pointed to by fxparmsp.
1000 1000   */
1001 1001  /* ARGSUSED */
1002 1002  static int
1003 1003  fx_parmsset(kthread_t *tx, void *parmsp, id_t reqpcid, cred_t *reqpcredp)
1004 1004  {
1005 1005          char            nice;
1006 1006          pri_t           reqfxuprilim;
1007 1007          pri_t           reqfxupri;
1008 1008          fxkparms_t      *fxkparmsp = (fxkparms_t *)parmsp;
1009 1009          fxproc_t        *fxpp;
1010 1010  
1011 1011  
1012 1012          ASSERT(MUTEX_HELD(&(ttoproc(tx))->p_lock));
1013 1013  
1014 1014          thread_lock(tx);
1015 1015          fxpp = (fxproc_t *)tx->t_cldata;
1016 1016  
1017 1017          if ((fxkparmsp->fx_cflags & FX_DOUPRILIM) == 0)
1018 1018                  reqfxuprilim = fxpp->fx_uprilim;
1019 1019          else
1020 1020                  reqfxuprilim = fxkparmsp->fx_uprilim;
1021 1021  
1022 1022          /*
1023 1023           * Basic permissions enforced by generic kernel code
1024 1024           * for all classes require that a thread attempting
1025 1025           * to change the scheduling parameters of a target
1026 1026           * thread be privileged or have a real or effective
1027 1027           * UID matching that of the target thread. We are not
1028 1028           * called unless these basic permission checks have
1029 1029           * already passed. The fixed priority class requires in
1030 1030           * addition that the calling thread be privileged if it
1031 1031           * is attempting to raise the pri above its current
1032 1032           * value This may have been checked previously but if our
1033 1033           * caller passed us a non-NULL credential pointer we assume
1034 1034           * it hasn't and we check it here.
1035 1035           */
1036 1036  
1037 1037          if ((reqpcredp != NULL) &&
1038 1038              (reqfxuprilim > fxpp->fx_uprilim ||
1039 1039              ((fxkparmsp->fx_cflags & FX_DOTQ) != 0)) &&
1040 1040              secpolicy_raisepriority(reqpcredp) != 0) {
1041 1041                  thread_unlock(tx);
1042 1042                  return (EPERM);
1043 1043          }
1044 1044  
1045 1045          FX_ADJUST_PRI(reqfxuprilim);
1046 1046  
1047 1047          if ((fxkparmsp->fx_cflags & FX_DOUPRI) == 0)
1048 1048                  reqfxupri = fxpp->fx_pri;
1049 1049          else
1050 1050                  reqfxupri = fxkparmsp->fx_upri;
1051 1051  
1052 1052  
1053 1053          /*
1054 1054           * Make sure the user priority doesn't exceed the upri limit.
1055 1055           */
1056 1056          if (reqfxupri > reqfxuprilim)
1057 1057                  reqfxupri = reqfxuprilim;
1058 1058  
1059 1059          /*
1060 1060           * Set fx_nice to the nice value corresponding to the user
1061 1061           * priority we are setting.  Note that setting the nice field
1062 1062           * of the parameter struct won't affect upri or nice.
1063 1063           */
1064 1064  
1065 1065          nice = NZERO - (reqfxupri * NZERO) / fx_maxupri;
1066 1066  
1067 1067          if (nice > NZERO)
1068 1068                  nice = NZERO;
1069 1069  
1070 1070          fxpp->fx_uprilim = reqfxuprilim;
1071 1071          fxpp->fx_pri = reqfxupri;
1072 1072  
1073 1073          if (fxkparmsp->fx_tqntm == FX_TQINF)
1074 1074                  fxpp->fx_pquantum = FX_TQINF;
1075 1075          else if (fxkparmsp->fx_tqntm == FX_TQDEF)
1076 1076                  fxpp->fx_pquantum = fx_dptbl[fxpp->fx_pri].fx_quantum;
1077 1077          else if ((fxkparmsp->fx_cflags & FX_DOTQ) != 0)
1078 1078                  fxpp->fx_pquantum = fxkparmsp->fx_tqntm;
1079 1079  
1080 1080          fxpp->fx_nice = nice;
1081 1081  
1082 1082          fx_change_priority(tx, fxpp);
1083 1083          thread_unlock(tx);
1084 1084          return (0);
1085 1085  }
1086 1086  
1087 1087  
1088 1088  /*
1089 1089   * Return the global scheduling priority that would be assigned
1090 1090   * to a thread entering the fixed-priority class with the fx_upri.
1091 1091   */
1092 1092  static pri_t
1093 1093  fx_globpri(kthread_t *t)
1094 1094  {
1095 1095          fxproc_t *fxpp;
1096 1096  
1097 1097          ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
1098 1098  
1099 1099          fxpp = (fxproc_t *)t->t_cldata;
1100 1100          return (fx_dptbl[fxpp->fx_pri].fx_globpri);
1101 1101  
1102 1102  }
1103 1103  
1104 1104  /*
1105 1105   * Arrange for thread to be placed in appropriate location
1106 1106   * on dispatcher queue.
1107 1107   *
1108 1108   * This is called with the current thread in TS_ONPROC and locked.
1109 1109   */
1110 1110  static void
1111 1111  fx_preempt(kthread_t *t)
1112 1112  {
1113 1113          fxproc_t        *fxpp = (fxproc_t *)(t->t_cldata);
1114 1114  
1115 1115          ASSERT(t == curthread);
1116 1116          ASSERT(THREAD_LOCK_HELD(curthread));
1117 1117  
1118 1118          (void) CPUCAPS_CHARGE(t, &fxpp->fx_caps, CPUCAPS_CHARGE_ENFORCE);
1119 1119  
1120 1120          /*
1121 1121           * Check to see if we're doing "preemption control" here.  If
1122 1122           * we are, and if the user has requested that this thread not
1123 1123           * be preempted, and if preemptions haven't been put off for
1124 1124           * too long, let the preemption happen here but try to make
1125 1125           * sure the thread is rescheduled as soon as possible.  We do
1126 1126           * this by putting it on the front of the highest priority run
1127 1127           * queue in the FX class.  If the preemption has been put off
1128 1128           * for too long, clear the "nopreempt" bit and let the thread
1129 1129           * be preempted.
1130 1130           */
1131 1131          if (t->t_schedctl && schedctl_get_nopreempt(t)) {
1132 1132                  if (fxpp->fx_pquantum == FX_TQINF ||
1133 1133                      fxpp->fx_timeleft > -SC_MAX_TICKS) {
1134 1134                          DTRACE_SCHED1(schedctl__nopreempt, kthread_t *, t);
1135 1135                          schedctl_set_yield(t, 1);
1136 1136                          setfrontdq(t);
1137 1137                          return;
1138 1138                  } else {
1139 1139                          schedctl_set_nopreempt(t, 0);
1140 1140                          DTRACE_SCHED1(schedctl__preempt, kthread_t *, t);
1141 1141                          TNF_PROBE_2(schedctl_preempt, "schedctl FX fx_preempt",
1142 1142                              /* CSTYLED */, tnf_pid, pid, ttoproc(t)->p_pid,
1143 1143                              tnf_lwpid, lwpid, t->t_tid);
1144 1144                          /*
1145 1145                           * Fall through and be preempted below.
1146 1146                           */
1147 1147                  }
1148 1148          }
1149 1149  
1150 1150          if (FX_HAS_CB(fxpp)) {
1151 1151                  clock_t new_quantum =  (clock_t)fxpp->fx_pquantum;
1152 1152                  pri_t   newpri = fxpp->fx_pri;
1153 1153                  FX_CB_PREEMPT(FX_CALLB(fxpp), fxpp->fx_cookie,
1154 1154                      &new_quantum, &newpri);
1155 1155                  FX_ADJUST_QUANTUM(new_quantum);
1156 1156                  if ((int)new_quantum != fxpp->fx_pquantum) {
1157 1157                          fxpp->fx_pquantum = (int)new_quantum;
1158 1158                          fxpp->fx_timeleft = fxpp->fx_pquantum;
1159 1159                  }
1160 1160                  FX_ADJUST_PRI(newpri);
1161 1161                  fxpp->fx_pri = newpri;
1162 1162                  THREAD_CHANGE_PRI(t, fx_dptbl[fxpp->fx_pri].fx_globpri);
1163 1163          }
1164 1164  
1165 1165          /*
1166 1166           * This thread may be placed on wait queue by CPU Caps. In this case we
1167 1167           * do not need to do anything until it is removed from the wait queue.
1168 1168           */
1169 1169          if (CPUCAPS_ENFORCE(t)) {
1170 1170                  return;
1171 1171          }
1172 1172  
1173 1173          if ((fxpp->fx_flags & (FXBACKQ)) == FXBACKQ) {
1174 1174                  fxpp->fx_timeleft = fxpp->fx_pquantum;
1175 1175                  fxpp->fx_flags &= ~FXBACKQ;
1176 1176                  setbackdq(t);
1177 1177          } else {
1178 1178                  setfrontdq(t);
1179 1179          }
1180 1180  }
1181 1181  
1182 1182  static void
1183 1183  fx_setrun(kthread_t *t)
1184 1184  {
1185 1185          fxproc_t *fxpp = (fxproc_t *)(t->t_cldata);
1186 1186  
1187 1187          ASSERT(THREAD_LOCK_HELD(t));    /* t should be in transition */
1188 1188          fxpp->fx_flags &= ~FXBACKQ;
1189 1189  
1190 1190          if (t->t_disp_time != ddi_get_lbolt())
1191 1191                  setbackdq(t);
1192 1192          else
1193 1193                  setfrontdq(t);
1194 1194  }
1195 1195  
1196 1196  
1197 1197  /*
1198 1198   * Prepare thread for sleep. We reset the thread priority so it will
1199 1199   * run at the kernel priority level when it wakes up.
1200 1200   */
1201 1201  static void
1202 1202  fx_sleep(kthread_t *t)
1203 1203  {
1204 1204          fxproc_t        *fxpp = (fxproc_t *)(t->t_cldata);
1205 1205  
1206 1206          ASSERT(t == curthread);
1207 1207          ASSERT(THREAD_LOCK_HELD(t));
1208 1208  
1209 1209          /*
1210 1210           * Account for time spent on CPU before going to sleep.
1211 1211           */
1212 1212          (void) CPUCAPS_CHARGE(t, &fxpp->fx_caps, CPUCAPS_CHARGE_ENFORCE);
1213 1213  
1214 1214          if (FX_HAS_CB(fxpp)) {
1215 1215                  FX_CB_SLEEP(FX_CALLB(fxpp), fxpp->fx_cookie);
1216 1216          }
1217 1217          t->t_stime = ddi_get_lbolt();           /* time stamp for the swapper */
1218 1218  }
1219 1219  
1220 1220  
1221 1221  /*
1222 1222   * Return Values:
1223 1223   *
1224 1224   *      -1 if the thread is loaded or is not eligible to be swapped in.
1225 1225   *
1226 1226   * FX and RT threads are designed so that they don't swapout; however,
1227 1227   * it is possible that while the thread is swapped out and in another class, it
1228 1228   * can be changed to FX or RT.  Since these threads should be swapped in
1229 1229   * as soon as they're runnable, rt_swapin returns SHRT_MAX, and fx_swapin
1230 1230   * returns SHRT_MAX - 1, so that it gives deference to any swapped out
1231 1231   * RT threads.
1232 1232   */
1233 1233  /* ARGSUSED */
1234 1234  static pri_t
1235 1235  fx_swapin(kthread_t *t, int flags)
1236 1236  {
1237 1237          pri_t   tpri = -1;
1238 1238  
1239 1239          ASSERT(THREAD_LOCK_HELD(t));
1240 1240  
1241 1241          if (t->t_state == TS_RUN && (t->t_schedflag & TS_LOAD) == 0) {
1242 1242                  tpri = (pri_t)SHRT_MAX - 1;
1243 1243          }
1244 1244  
1245 1245          return (tpri);
1246 1246  }
1247 1247  
1248 1248  /*
1249 1249   * Return Values
1250 1250   *      -1 if the thread isn't loaded or is not eligible to be swapped out.
1251 1251   */
1252 1252  /* ARGSUSED */
1253 1253  static pri_t
1254 1254  fx_swapout(kthread_t *t, int flags)
1255 1255  {
1256 1256          ASSERT(THREAD_LOCK_HELD(t));
1257 1257  
1258 1258          return (-1);
1259 1259  
1260 1260  }
1261 1261  
1262 1262  /* ARGSUSED */
1263 1263  static void
1264 1264  fx_stop(kthread_t *t, int why, int what)
1265 1265  {
1266 1266          fxproc_t *fxpp = (fxproc_t *)(t->t_cldata);
1267 1267  
1268 1268          ASSERT(THREAD_LOCK_HELD(t));
1269 1269  
1270 1270          if (FX_HAS_CB(fxpp)) {
1271 1271                  FX_CB_STOP(FX_CALLB(fxpp), fxpp->fx_cookie);
1272 1272          }
1273 1273  }
1274 1274  
1275 1275  /*
1276 1276   * Check for time slice expiration.  If time slice has expired
1277 1277   * set runrun to cause preemption.
1278 1278   */
1279 1279  static void
1280 1280  fx_tick(kthread_t *t)
1281 1281  {
1282 1282          boolean_t call_cpu_surrender = B_FALSE;
1283 1283          fxproc_t *fxpp;
1284 1284  
1285 1285          ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock));
1286 1286  
1287 1287          thread_lock(t);
1288 1288  
1289 1289          fxpp = (fxproc_t *)(t->t_cldata);
1290 1290  
1291 1291          if (FX_HAS_CB(fxpp)) {
1292 1292                  clock_t new_quantum =  (clock_t)fxpp->fx_pquantum;
1293 1293                  pri_t   newpri = fxpp->fx_pri;
1294 1294                  FX_CB_TICK(FX_CALLB(fxpp), fxpp->fx_cookie,
1295 1295                      &new_quantum, &newpri);
1296 1296                  FX_ADJUST_QUANTUM(new_quantum);
1297 1297                  if ((int)new_quantum != fxpp->fx_pquantum) {
1298 1298                          fxpp->fx_pquantum = (int)new_quantum;
1299 1299                          fxpp->fx_timeleft = fxpp->fx_pquantum;
1300 1300                  }
1301 1301                  FX_ADJUST_PRI(newpri);
1302 1302                  if (newpri != fxpp->fx_pri) {
1303 1303                          fxpp->fx_pri = newpri;
1304 1304                          fx_change_priority(t, fxpp);
1305 1305                  }
1306 1306          }
1307 1307  
1308 1308          /*
1309 1309           * Keep track of thread's project CPU usage.  Note that projects
1310 1310           * get charged even when threads are running in the kernel.
1311 1311           */
1312 1312          call_cpu_surrender =  CPUCAPS_CHARGE(t, &fxpp->fx_caps,
1313 1313              CPUCAPS_CHARGE_ENFORCE);
1314 1314  
1315 1315          if ((fxpp->fx_pquantum != FX_TQINF) &&
1316 1316              (--fxpp->fx_timeleft <= 0)) {
1317 1317                  pri_t   new_pri;
1318 1318  
1319 1319                  /*
1320 1320                   * If we're doing preemption control and trying to
1321 1321                   * avoid preempting this thread, just note that
1322 1322                   * the thread should yield soon and let it keep
1323 1323                   * running (unless it's been a while).
1324 1324                   */
1325 1325                  if (t->t_schedctl && schedctl_get_nopreempt(t)) {
1326 1326                          if (fxpp->fx_timeleft > -SC_MAX_TICKS) {
1327 1327                                  DTRACE_SCHED1(schedctl__nopreempt,
1328 1328                                      kthread_t *, t);
1329 1329                                  schedctl_set_yield(t, 1);
1330 1330                                  thread_unlock_nopreempt(t);
1331 1331                                  return;
1332 1332                          }
1333 1333                          TNF_PROBE_2(schedctl_failsafe,
1334 1334                              "schedctl FX fx_tick", /* CSTYLED */,
1335 1335                              tnf_pid, pid, ttoproc(t)->p_pid,
1336 1336                              tnf_lwpid, lwpid, t->t_tid);
1337 1337                  }
1338 1338                  new_pri = fx_dptbl[fxpp->fx_pri].fx_globpri;
1339 1339                  ASSERT(new_pri >= 0 && new_pri <= fx_maxglobpri);
1340 1340                  /*
1341 1341                   * When the priority of a thread is changed,
1342 1342                   * it may be necessary to adjust its position
1343 1343                   * on a sleep queue or dispatch queue. Even
1344 1344                   * when the priority is not changed, we need
1345 1345                   * to preserve round robin on dispatch queue.
1346 1346                   * The function thread_change_pri accomplishes
1347 1347                   * this.
1348 1348                   */
1349 1349                  if (thread_change_pri(t, new_pri, 0)) {
1350 1350                          fxpp->fx_timeleft = fxpp->fx_pquantum;
1351 1351                  } else {
1352 1352                          call_cpu_surrender = B_TRUE;
1353 1353                  }
1354 1354          } else if (t->t_state == TS_ONPROC &&
1355 1355              t->t_pri < t->t_disp_queue->disp_maxrunpri) {
1356 1356                  call_cpu_surrender = B_TRUE;
1357 1357          }
1358 1358  
1359 1359          if (call_cpu_surrender) {
1360 1360                  fxpp->fx_flags |= FXBACKQ;
1361 1361                  cpu_surrender(t);
1362 1362          }
1363 1363          thread_unlock_nopreempt(t);     /* clock thread can't be preempted */
1364 1364  }
1365 1365  
1366 1366  
1367 1367  static void
1368 1368  fx_trapret(kthread_t *t)
1369 1369  {
1370 1370          cpu_t           *cp = CPU;
1371 1371  
1372 1372          ASSERT(THREAD_LOCK_HELD(t));
1373 1373          ASSERT(t == curthread);
1374 1374          ASSERT(cp->cpu_dispthread == t);
1375 1375          ASSERT(t->t_state == TS_ONPROC);
1376 1376  }
1377 1377  
1378 1378  
1379 1379  /*
1380 1380   * Processes waking up go to the back of their queue.
1381 1381   */
1382 1382  static void
1383 1383  fx_wakeup(kthread_t *t)
1384 1384  {
1385 1385          fxproc_t        *fxpp = (fxproc_t *)(t->t_cldata);
1386 1386  
1387 1387          ASSERT(THREAD_LOCK_HELD(t));
1388 1388  
1389 1389          t->t_stime = ddi_get_lbolt();           /* time stamp for the swapper */
1390 1390          if (FX_HAS_CB(fxpp)) {
1391 1391                  clock_t new_quantum =  (clock_t)fxpp->fx_pquantum;
1392 1392                  pri_t   newpri = fxpp->fx_pri;
1393 1393                  FX_CB_WAKEUP(FX_CALLB(fxpp), fxpp->fx_cookie,
1394 1394                      &new_quantum, &newpri);
1395 1395                  FX_ADJUST_QUANTUM(new_quantum);
1396 1396                  if ((int)new_quantum != fxpp->fx_pquantum) {
1397 1397                          fxpp->fx_pquantum = (int)new_quantum;
1398 1398                          fxpp->fx_timeleft = fxpp->fx_pquantum;
1399 1399                  }
1400 1400  
1401 1401                  FX_ADJUST_PRI(newpri);
1402 1402                  if (newpri != fxpp->fx_pri) {
1403 1403                          fxpp->fx_pri = newpri;
1404 1404                          THREAD_CHANGE_PRI(t, fx_dptbl[fxpp->fx_pri].fx_globpri);
1405 1405                  }
1406 1406          }
1407 1407  
1408 1408          fxpp->fx_flags &= ~FXBACKQ;
1409 1409  
1410 1410          if (t->t_disp_time != ddi_get_lbolt())
1411 1411                  setbackdq(t);
1412 1412          else
1413 1413                  setfrontdq(t);
1414 1414  }
1415 1415  
1416 1416  
1417 1417  /*
1418 1418   * When a thread yields, put it on the back of the run queue.
1419 1419   */
1420 1420  static void
1421 1421  fx_yield(kthread_t *t)
1422 1422  {
1423 1423          fxproc_t        *fxpp = (fxproc_t *)(t->t_cldata);
1424 1424  
1425 1425          ASSERT(t == curthread);
1426 1426          ASSERT(THREAD_LOCK_HELD(t));
1427 1427  
1428 1428          /*
1429 1429           * Collect CPU usage spent before yielding CPU.
1430 1430           */
1431 1431          (void) CPUCAPS_CHARGE(t, &fxpp->fx_caps, CPUCAPS_CHARGE_ENFORCE);
1432 1432  
1433 1433          if (FX_HAS_CB(fxpp))  {
1434 1434                  clock_t new_quantum =  (clock_t)fxpp->fx_pquantum;
1435 1435                  pri_t   newpri = fxpp->fx_pri;
1436 1436                  FX_CB_PREEMPT(FX_CALLB(fxpp), fxpp->fx_cookie,
1437 1437                      &new_quantum, &newpri);
1438 1438                  FX_ADJUST_QUANTUM(new_quantum);
1439 1439                  if ((int)new_quantum != fxpp->fx_pquantum) {
1440 1440                          fxpp->fx_pquantum = (int)new_quantum;
1441 1441                          fxpp->fx_timeleft = fxpp->fx_pquantum;
1442 1442                  }
1443 1443                  FX_ADJUST_PRI(newpri);
1444 1444                  fxpp->fx_pri = newpri;
1445 1445                  THREAD_CHANGE_PRI(t, fx_dptbl[fxpp->fx_pri].fx_globpri);
1446 1446          }
1447 1447  
1448 1448          /*
1449 1449           * Clear the preemption control "yield" bit since the user is
1450 1450           * doing a yield.
1451 1451           */
1452 1452          if (t->t_schedctl)
1453 1453                  schedctl_set_yield(t, 0);
1454 1454  
1455 1455          if (fxpp->fx_timeleft <= 0) {
1456 1456                  /*
1457 1457                   * Time slice was artificially extended to avoid
1458 1458                   * preemption, so pretend we're preempting it now.
1459 1459                   */
1460 1460                  DTRACE_SCHED1(schedctl__yield, int, -fxpp->fx_timeleft);
1461 1461                  fxpp->fx_timeleft = fxpp->fx_pquantum;
1462 1462                  THREAD_CHANGE_PRI(t, fx_dptbl[fxpp->fx_pri].fx_globpri);
1463 1463                  ASSERT(t->t_pri >= 0 && t->t_pri <= fx_maxglobpri);
1464 1464          }
1465 1465  
1466 1466          fxpp->fx_flags &= ~FXBACKQ;
1467 1467          setbackdq(t);
1468 1468  }
1469 1469  
1470 1470  /*
1471 1471   * Increment the nice value of the specified thread by incr and
1472 1472   * return the new value in *retvalp.
1473 1473   */
1474 1474  static int
1475 1475  fx_donice(kthread_t *t, cred_t *cr, int incr, int *retvalp)
1476 1476  {
1477 1477          int             newnice;
1478 1478          fxproc_t        *fxpp = (fxproc_t *)(t->t_cldata);
1479 1479          fxkparms_t      fxkparms;
1480 1480  
1481 1481          ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock));
1482 1482  
1483 1483          /* If there's no change to priority, just return current setting */
1484 1484          if (incr == 0) {
1485 1485                  if (retvalp) {
1486 1486                          *retvalp = fxpp->fx_nice - NZERO;
1487 1487                  }
1488 1488                  return (0);
1489 1489          }
1490 1490  
1491 1491          if ((incr < 0 || incr > 2 * NZERO) &&
1492 1492              secpolicy_raisepriority(cr) != 0)
1493 1493                  return (EPERM);
1494 1494  
1495 1495          /*
1496 1496           * Specifying a nice increment greater than the upper limit of
1497 1497           * 2 * NZERO - 1 will result in the thread's nice value being
1498 1498           * set to the upper limit.  We check for this before computing
1499 1499           * the new value because otherwise we could get overflow
1500 1500           * if a privileged user specified some ridiculous increment.
1501 1501           */
1502 1502          if (incr > 2 * NZERO - 1)
1503 1503                  incr = 2 * NZERO - 1;
1504 1504  
1505 1505          newnice = fxpp->fx_nice + incr;
1506 1506          if (newnice > NZERO)
1507 1507                  newnice = NZERO;
1508 1508          else if (newnice < 0)
1509 1509                  newnice = 0;
1510 1510  
1511 1511          fxkparms.fx_uprilim = fxkparms.fx_upri =
1512 1512              -((newnice - NZERO) * fx_maxupri) / NZERO;
1513 1513  
1514 1514          fxkparms.fx_cflags = FX_DOUPRILIM | FX_DOUPRI;
1515 1515  
1516 1516          fxkparms.fx_tqntm = FX_TQDEF;
1517 1517  
1518 1518          /*
1519 1519           * Reset the uprilim and upri values of the thread. Adjust
1520 1520           * time quantum accordingly.
1521 1521           */
1522 1522  
1523 1523          (void) fx_parmsset(t, (void *)&fxkparms, (id_t)0, (cred_t *)NULL);
1524 1524  
1525 1525          /*
1526 1526           * Although fx_parmsset already reset fx_nice it may
1527 1527           * not have been set to precisely the value calculated above
1528 1528           * because fx_parmsset determines the nice value from the
1529 1529           * user priority and we may have truncated during the integer
1530 1530           * conversion from nice value to user priority and back.
1531 1531           * We reset fx_nice to the value we calculated above.
1532 1532           */
1533 1533          fxpp->fx_nice = (char)newnice;
1534 1534  
1535 1535          if (retvalp)
1536 1536                  *retvalp = newnice - NZERO;
1537 1537  
1538 1538          return (0);
1539 1539  }
1540 1540  
1541 1541  /*
1542 1542   * Increment the priority of the specified thread by incr and
1543 1543   * return the new value in *retvalp.
1544 1544   */
1545 1545  static int
1546 1546  fx_doprio(kthread_t *t, cred_t *cr, int incr, int *retvalp)
1547 1547  {
1548 1548          int             newpri;
1549 1549          fxproc_t        *fxpp = (fxproc_t *)(t->t_cldata);
1550 1550          fxkparms_t      fxkparms;
1551 1551  
1552 1552          ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock));
1553 1553  
1554 1554          /* If there's no change to priority, just return current setting */
1555 1555          if (incr == 0) {
1556 1556                  *retvalp = fxpp->fx_pri;
1557 1557                  return (0);
1558 1558          }
1559 1559  
1560 1560          newpri = fxpp->fx_pri + incr;
1561 1561          if (newpri > fx_maxupri || newpri < 0)
1562 1562                  return (EINVAL);
1563 1563  
1564 1564          *retvalp = newpri;
1565 1565          fxkparms.fx_uprilim = fxkparms.fx_upri = newpri;
1566 1566          fxkparms.fx_tqntm = FX_NOCHANGE;
1567 1567          fxkparms.fx_cflags = FX_DOUPRILIM | FX_DOUPRI;
1568 1568  
1569 1569          /*
1570 1570           * Reset the uprilim and upri values of the thread.
1571 1571           */
1572 1572          return (fx_parmsset(t, (void *)&fxkparms, (id_t)0, cr));
1573 1573  }
1574 1574  
1575 1575  static void
1576 1576  fx_change_priority(kthread_t *t, fxproc_t *fxpp)
1577 1577  {
1578 1578          pri_t   new_pri;
1579 1579  
1580 1580          ASSERT(THREAD_LOCK_HELD(t));
1581 1581          new_pri = fx_dptbl[fxpp->fx_pri].fx_globpri;
1582 1582          ASSERT(new_pri >= 0 && new_pri <= fx_maxglobpri);
1583 1583          t->t_cpri = fxpp->fx_pri;
1584 1584          if (t == curthread || t->t_state == TS_ONPROC) {
1585 1585                  /* curthread is always onproc */
1586 1586                  cpu_t   *cp = t->t_disp_queue->disp_cpu;
1587 1587                  THREAD_CHANGE_PRI(t, new_pri);
1588 1588                  if (t == cp->cpu_dispthread)
1589 1589                          cp->cpu_dispatch_pri = DISP_PRIO(t);
1590 1590                  if (DISP_MUST_SURRENDER(t)) {
1591 1591                          fxpp->fx_flags |= FXBACKQ;
1592 1592                          cpu_surrender(t);
1593 1593                  } else {
1594 1594                          fxpp->fx_timeleft = fxpp->fx_pquantum;
1595 1595                  }
1596 1596          } else {
1597 1597                  /*
1598 1598                   * When the priority of a thread is changed,
1599 1599                   * it may be necessary to adjust its position
1600 1600                   * on a sleep queue or dispatch queue.
1601 1601                   * The function thread_change_pri accomplishes
1602 1602                   * this.
1603 1603                   */
1604 1604                  if (thread_change_pri(t, new_pri, 0)) {
1605 1605                          /*
1606 1606                           * The thread was on a run queue. Reset
1607 1607                           * its CPU timeleft from the quantum
1608 1608                           * associated with the new priority.
1609 1609                           */
1610 1610                          fxpp->fx_timeleft = fxpp->fx_pquantum;
1611 1611                  } else {
1612 1612                          fxpp->fx_flags |= FXBACKQ;
1613 1613                  }
1614 1614          }
1615 1615  }
1616 1616  
1617 1617  static int
1618 1618  fx_alloc(void **p, int flag)
1619 1619  {
1620 1620          void *bufp;
1621 1621  
1622 1622          bufp = kmem_alloc(sizeof (fxproc_t), flag);
1623 1623          if (bufp == NULL) {
1624 1624                  return (ENOMEM);
1625 1625          } else {
1626 1626                  *p = bufp;
1627 1627                  return (0);
1628 1628          }
1629 1629  }
1630 1630  
1631 1631  static void
1632 1632  fx_free(void *bufp)
1633 1633  {
1634 1634          if (bufp)
1635 1635                  kmem_free(bufp, sizeof (fxproc_t));
1636 1636  }
1637 1637  
1638 1638  /*
1639 1639   * Release the callback list mutex after successful lookup
1640 1640   */
1641 1641  void
1642 1642  fx_list_release(fxproc_t *fxpp)
1643 1643  {
1644 1644          int index = FX_CB_LIST_HASH(fxpp->fx_ktid);
1645 1645          kmutex_t *lockp = &fx_cb_list_lock[index];
1646 1646          mutex_exit(lockp);
1647 1647  }
1648 1648  
1649 1649  fxproc_t *
1650 1650  fx_list_lookup(kt_did_t ktid)
1651 1651  {
1652 1652          int index = FX_CB_LIST_HASH(ktid);
1653 1653          kmutex_t *lockp = &fx_cb_list_lock[index];
1654 1654          fxproc_t *fxpp;
1655 1655  
1656 1656          mutex_enter(lockp);
1657 1657  
1658 1658          for (fxpp = fx_cb_plisthead[index].fx_cb_next;
1659 1659              fxpp != &fx_cb_plisthead[index]; fxpp = fxpp->fx_cb_next) {
1660 1660                  if (fxpp->fx_tp->t_cid == fx_cid && fxpp->fx_ktid == ktid &&
1661 1661                      fxpp->fx_callback != NULL) {
1662 1662                          /*
1663 1663                           * The caller is responsible for calling
1664 1664                           * fx_list_release to drop the lock upon
1665 1665                           * successful lookup
1666 1666                           */
1667 1667                          return (fxpp);
1668 1668                  }
1669 1669          }
1670 1670          mutex_exit(lockp);
1671 1671          return ((fxproc_t *)NULL);
1672 1672  }
1673 1673  
1674 1674  
1675 1675  /*
1676 1676   * register a callback set of routines for current thread
1677 1677   * thread should already be in FX class
1678 1678   */
1679 1679  int
1680 1680  fx_register_callbacks(fx_callbacks_t *fx_callback, fx_cookie_t cookie,
1681 1681          pri_t pri, clock_t quantum)
1682 1682  {
1683 1683  
1684 1684          fxproc_t        *fxpp;
1685 1685  
1686 1686          if (fx_callback == NULL)
1687 1687                  return (EINVAL);
1688 1688  
1689 1689          if (secpolicy_dispadm(CRED()) != 0)
1690 1690                  return (EPERM);
1691 1691  
1692 1692          if (FX_CB_VERSION(fx_callback) != FX_CALLB_REV)
1693 1693                  return (EINVAL);
1694 1694  
1695 1695          if (!FX_ISVALID(pri, quantum))
1696 1696                  return (EINVAL);
1697 1697  
1698 1698          thread_lock(curthread);         /* get dispatcher lock on thread */
1699 1699  
1700 1700          if (curthread->t_cid != fx_cid) {
1701 1701                  thread_unlock(curthread);
1702 1702                  return (EINVAL);
1703 1703          }
1704 1704  
1705 1705          fxpp = (fxproc_t *)(curthread->t_cldata);
1706 1706          ASSERT(fxpp != NULL);
1707 1707          if (FX_HAS_CB(fxpp)) {
1708 1708                  thread_unlock(curthread);
1709 1709                  return (EINVAL);
1710 1710          }
1711 1711  
1712 1712          fxpp->fx_callback = fx_callback;
1713 1713          fxpp->fx_cookie = cookie;
1714 1714  
1715 1715          if (pri != FX_CB_NOCHANGE) {
1716 1716                  fxpp->fx_pri = pri;
1717 1717                  FX_ADJUST_PRI(fxpp->fx_pri);
1718 1718                  if (quantum == FX_TQDEF) {
1719 1719                          fxpp->fx_pquantum = fx_dptbl[fxpp->fx_pri].fx_quantum;
1720 1720                  } else if (quantum == FX_TQINF) {
1721 1721                          fxpp->fx_pquantum = FX_TQINF;
1722 1722                  } else if (quantum != FX_NOCHANGE) {
1723 1723                          FX_ADJUST_QUANTUM(quantum);
1724 1724                          fxpp->fx_pquantum = quantum;
1725 1725                  }
1726 1726          } else if (quantum != FX_NOCHANGE && quantum != FX_TQDEF) {
1727 1727                  if (quantum == FX_TQINF)
1728 1728                          fxpp->fx_pquantum = FX_TQINF;
1729 1729                  else {
1730 1730                          FX_ADJUST_QUANTUM(quantum);
1731 1731                          fxpp->fx_pquantum = quantum;
1732 1732                  }
1733 1733          }
1734 1734  
1735 1735          fxpp->fx_ktid = ddi_get_kt_did();
1736 1736  
1737 1737          fx_change_priority(curthread, fxpp);
1738 1738  
1739 1739          thread_unlock(curthread);
1740 1740  
1741 1741          /*
1742 1742           * Link new structure into fxproc list.
1743 1743           */
1744 1744          FX_CB_LIST_INSERT(fxpp);
1745 1745          return (0);
1746 1746  }
1747 1747  
1748 1748  /* unregister a callback set of routines for current thread */
1749 1749  int
1750 1750  fx_unregister_callbacks()
1751 1751  {
1752 1752          fxproc_t        *fxpp;
1753 1753  
1754 1754          if ((fxpp = fx_list_lookup(ddi_get_kt_did())) == NULL) {
1755 1755                  /*
1756 1756                   * did not have a registered callback;
1757 1757                   */
1758 1758                  return (EINVAL);
1759 1759          }
1760 1760  
1761 1761          thread_lock(fxpp->fx_tp);
1762 1762          fxpp->fx_callback = NULL;
1763 1763          fxpp->fx_cookie = NULL;
1764 1764          thread_unlock(fxpp->fx_tp);
1765 1765          fx_list_release(fxpp);
1766 1766  
1767 1767          FX_CB_LIST_DELETE(fxpp);
1768 1768          return (0);
1769 1769  }
1770 1770  
1771 1771  /*
1772 1772   * modify priority and/or quantum value of a thread with callback
1773 1773   */
1774 1774  int
1775 1775  fx_modify_priority(kt_did_t ktid, clock_t quantum, pri_t pri)
1776 1776  {
1777 1777          fxproc_t        *fxpp;
1778 1778  
1779 1779          if (!FX_ISVALID(pri, quantum))
1780 1780                  return (EINVAL);
1781 1781  
1782 1782          if ((fxpp = fx_list_lookup(ktid)) == NULL) {
1783 1783                  /*
1784 1784                   * either thread had exited or did not have a registered
1785 1785                   * callback;
1786 1786                   */
1787 1787                  return (ESRCH);
1788 1788          }
1789 1789  
1790 1790          thread_lock(fxpp->fx_tp);
1791 1791  
1792 1792          if (pri != FX_CB_NOCHANGE) {
1793 1793                  fxpp->fx_pri = pri;
1794 1794                  FX_ADJUST_PRI(fxpp->fx_pri);
1795 1795                  if (quantum == FX_TQDEF) {
1796 1796                          fxpp->fx_pquantum = fx_dptbl[fxpp->fx_pri].fx_quantum;
1797 1797                  } else if (quantum == FX_TQINF) {
1798 1798                          fxpp->fx_pquantum = FX_TQINF;
1799 1799                  } else if (quantum != FX_NOCHANGE) {
1800 1800                          FX_ADJUST_QUANTUM(quantum);
1801 1801                          fxpp->fx_pquantum = quantum;
1802 1802                  }
1803 1803          } else if (quantum != FX_NOCHANGE && quantum != FX_TQDEF) {
1804 1804                  if (quantum == FX_TQINF) {
1805 1805                          fxpp->fx_pquantum = FX_TQINF;
1806 1806                  } else {
1807 1807                          FX_ADJUST_QUANTUM(quantum);
1808 1808                          fxpp->fx_pquantum = quantum;
1809 1809                  }
1810 1810          }
1811 1811  
1812 1812          fx_change_priority(fxpp->fx_tp, fxpp);
1813 1813  
1814 1814          thread_unlock(fxpp->fx_tp);
1815 1815          fx_list_release(fxpp);
1816 1816          return (0);
1817 1817  }
1818 1818  
1819 1819  
1820 1820  /*
1821 1821   * return an iblock cookie for mutex initialization to be used in callbacks
1822 1822   */
1823 1823  void *
1824 1824  fx_get_mutex_cookie()
1825 1825  {
1826 1826          return ((void *)(uintptr_t)__ipltospl(DISP_LEVEL));
1827 1827  }
1828 1828  
1829 1829  /*
1830 1830   * return maximum relative priority
1831 1831   */
1832 1832  pri_t
1833 1833  fx_get_maxpri()
1834 1834  {
1835 1835          return (fx_maxumdpri);
1836 1836  }
  
    | 
      ↓ open down ↓ | 
    1836 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX