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