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