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