Home | History | Annotate | Download | only in disp
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
     28 /*	  All Rights Reserved  	*/
     29 
     30 #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* from SVr4.0 1.23 */
     31 
     32 #include <sys/types.h>
     33 #include <sys/param.h>
     34 #include <sys/sysmacros.h>
     35 #include <sys/cred.h>
     36 #include <sys/proc.h>
     37 #include <sys/session.h>
     38 #include <sys/strsubr.h>
     39 #include <sys/signal.h>
     40 #include <sys/user.h>
     41 #include <sys/priocntl.h>
     42 #include <sys/class.h>
     43 #include <sys/disp.h>
     44 #include <sys/procset.h>
     45 #include <sys/debug.h>
     46 #include <sys/ts.h>
     47 #include <sys/tspriocntl.h>
     48 #include <sys/iapriocntl.h>
     49 #include <sys/kmem.h>
     50 #include <sys/errno.h>
     51 #include <sys/cpuvar.h>
     52 #include <sys/systm.h>		/* for lbolt */
     53 #include <sys/vtrace.h>
     54 #include <sys/vmsystm.h>
     55 #include <sys/schedctl.h>
     56 #include <sys/tnf_probe.h>
     57 #include <sys/atomic.h>
     58 #include <sys/policy.h>
     59 #include <sys/sdt.h>
     60 #include <sys/cpupart.h>
     61 #include <vm/rm.h>
     62 #include <vm/seg_kmem.h>
     63 #include <sys/modctl.h>
     64 #include <sys/cpucaps.h>
     65 
     66 static pri_t ts_init(id_t, int, classfuncs_t **);
     67 
     68 static struct sclass csw = {
     69 	"TS",
     70 	ts_init,
     71 	0
     72 };
     73 
     74 static struct modlsched modlsched = {
     75 	&mod_schedops, "time sharing sched class", &csw
     76 };
     77 
     78 static struct modlinkage modlinkage = {
     79 	MODREV_1, (void *)&modlsched, NULL
     80 };
     81 
     82 int
     83 _init()
     84 {
     85 	return (mod_install(&modlinkage));
     86 }
     87 
     88 int
     89 _fini()
     90 {
     91 	return (EBUSY);		/* don't remove TS for now */
     92 }
     93 
     94 int
     95 _info(struct modinfo *modinfop)
     96 {
     97 	return (mod_info(&modlinkage, modinfop));
     98 }
     99 
    100 /*
    101  * Class specific code for the time-sharing class
    102  */
    103 
    104 
    105 /*
    106  * Extern declarations for variables defined in the ts master file
    107  */
    108 #define	TSMAXUPRI 60
    109 
    110 pri_t	ts_maxupri = TSMAXUPRI;	/* max time-sharing user priority */
    111 pri_t	ts_maxumdpri;		/* maximum user mode ts priority */
    112 
    113 pri_t	ia_maxupri = IAMAXUPRI;	/* max interactive user priority */
    114 pri_t	ia_boost = IA_BOOST;	/* boost value for interactive */
    115 
    116 tsdpent_t  *ts_dptbl;	/* time-sharing disp parameter table */
    117 pri_t	*ts_kmdpris;	/* array of global pris used by ts procs when */
    118 			/*  sleeping or running in kernel after sleep */
    119 
    120 static id_t ia_cid;
    121 
    122 int ts_sleep_promote = 1;
    123 
    124 #define	tsmedumdpri	(ts_maxumdpri >> 1)
    125 
    126 #define	TS_NEWUMDPRI(tspp) \
    127 { \
    128 	pri_t pri; \
    129 	pri = (tspp)->ts_cpupri + (tspp)->ts_upri + (tspp)->ts_boost; \
    130 	if (pri > ts_maxumdpri) \
    131 		(tspp)->ts_umdpri = ts_maxumdpri; \
    132 	else if (pri < 0) \
    133 		(tspp)->ts_umdpri = 0; \
    134 	else \
    135 		(tspp)->ts_umdpri = pri; \
    136 	ASSERT((tspp)->ts_umdpri >= 0 && (tspp)->ts_umdpri <= ts_maxumdpri); \
    137 }
    138 
    139 /*
    140  * The tsproc_t structures are kept in an array of circular doubly linked
    141  * lists.  A hash on the thread pointer is used to determine which list
    142  * each thread should be placed.  Each list has a dummy "head" which is
    143  * never removed, so the list is never empty.  ts_update traverses these
    144  * lists to update the priorities of threads that have been waiting on
    145  * the run queue.
    146  */
    147 
    148 #define	TS_LISTS 16		/* number of lists, must be power of 2 */
    149 
    150 /* hash function, argument is a thread pointer */
    151 #define	TS_LIST_HASH(tp)	(((uintptr_t)(tp) >> 9) & (TS_LISTS - 1))
    152 
    153 /* iterate to the next list */
    154 #define	TS_LIST_NEXT(i)		(((i) + 1) & (TS_LISTS - 1))
    155 
    156 /*
    157  * Insert thread into the appropriate tsproc list.
    158  */
    159 #define	TS_LIST_INSERT(tspp)				\
    160 {							\
    161 	int index = TS_LIST_HASH(tspp->ts_tp);		\
    162 	kmutex_t *lockp = &ts_list_lock[index];		\
    163 	tsproc_t *headp = &ts_plisthead[index];		\
    164 	mutex_enter(lockp);				\
    165 	tspp->ts_next = headp->ts_next;			\
    166 	tspp->ts_prev = headp;				\
    167 	headp->ts_next->ts_prev = tspp;			\
    168 	headp->ts_next = tspp;				\
    169 	mutex_exit(lockp);				\
    170 }
    171 
    172 /*
    173  * Remove thread from tsproc list.
    174  */
    175 #define	TS_LIST_DELETE(tspp)				\
    176 {							\
    177 	int index = TS_LIST_HASH(tspp->ts_tp);		\
    178 	kmutex_t *lockp = &ts_list_lock[index];		\
    179 	mutex_enter(lockp);				\
    180 	tspp->ts_prev->ts_next = tspp->ts_next;		\
    181 	tspp->ts_next->ts_prev = tspp->ts_prev;		\
    182 	mutex_exit(lockp);				\
    183 }
    184 
    185 
    186 static int	ts_admin(caddr_t, cred_t *);
    187 static int	ts_enterclass(kthread_t *, id_t, void *, cred_t *, void *);
    188 static int	ts_fork(kthread_t *, kthread_t *, void *);
    189 static int	ts_getclinfo(void *);
    190 static int	ts_getclpri(pcpri_t *);
    191 static int	ts_parmsin(void *);
    192 static int	ts_parmsout(void *, pc_vaparms_t *);
    193 static int	ts_vaparmsin(void *, pc_vaparms_t *);
    194 static int	ts_vaparmsout(void *, pc_vaparms_t *);
    195 static int	ts_parmsset(kthread_t *, void *, id_t, cred_t *);
    196 static void	ts_exit(kthread_t *);
    197 static int	ts_donice(kthread_t *, cred_t *, int, int *);
    198 static int	ts_doprio(kthread_t *, cred_t *, int, int *);
    199 static void	ts_exitclass(void *);
    200 static int	ts_canexit(kthread_t *, cred_t *);
    201 static void	ts_forkret(kthread_t *, kthread_t *);
    202 static void	ts_nullsys();
    203 static void	ts_parmsget(kthread_t *, void *);
    204 static void	ts_preempt(kthread_t *);
    205 static void	ts_setrun(kthread_t *);
    206 static void	ts_sleep(kthread_t *);
    207 static pri_t	ts_swapin(kthread_t *, int);
    208 static pri_t	ts_swapout(kthread_t *, int);
    209 static void	ts_tick(kthread_t *);
    210 static void	ts_trapret(kthread_t *);
    211 static void	ts_update(void *);
    212 static int	ts_update_list(int);
    213 static void	ts_wakeup(kthread_t *);
    214 static pri_t	ts_globpri(kthread_t *);
    215 static void	ts_yield(kthread_t *);
    216 extern tsdpent_t *ts_getdptbl(void);
    217 extern pri_t	*ts_getkmdpris(void);
    218 extern pri_t	td_getmaxumdpri(void);
    219 static int	ts_alloc(void **, int);
    220 static void	ts_free(void *);
    221 
    222 pri_t		ia_init(id_t, int, classfuncs_t **);
    223 static int	ia_getclinfo(void *);
    224 static int	ia_getclpri(pcpri_t *);
    225 static int	ia_parmsin(void *);
    226 static int	ia_vaparmsin(void *, pc_vaparms_t *);
    227 static int	ia_vaparmsout(void *, pc_vaparms_t *);
    228 static int	ia_parmsset(kthread_t *, void *, id_t, cred_t *);
    229 static void	ia_parmsget(kthread_t *, void *);
    230 static void	ia_set_process_group(pid_t, pid_t, pid_t);
    231 
    232 static void	ts_change_priority(kthread_t *, tsproc_t *);
    233 
    234 extern pri_t	ts_maxkmdpri;	/* maximum kernel mode ts priority */
    235 static pri_t	ts_maxglobpri;	/* maximum global priority used by ts class */
    236 static kmutex_t	ts_dptblock;	/* protects time sharing dispatch table */
    237 static kmutex_t	ts_list_lock[TS_LISTS];	/* protects tsproc lists */
    238 static tsproc_t	ts_plisthead[TS_LISTS];	/* dummy tsproc at head of lists */
    239 
    240 static gid_t	IA_gid = 0;
    241 
    242 static struct classfuncs ts_classfuncs = {
    243 	/* class functions */
    244 	ts_admin,
    245 	ts_getclinfo,
    246 	ts_parmsin,
    247 	ts_parmsout,
    248 	ts_vaparmsin,
    249 	ts_vaparmsout,
    250 	ts_getclpri,
    251 	ts_alloc,
    252 	ts_free,
    253 
    254 	/* thread functions */
    255 	ts_enterclass,
    256 	ts_exitclass,
    257 	ts_canexit,
    258 	ts_fork,
    259 	ts_forkret,
    260 	ts_parmsget,
    261 	ts_parmsset,
    262 	ts_nullsys,	/* stop */
    263 	ts_exit,
    264 	ts_nullsys,	/* active */
    265 	ts_nullsys,	/* inactive */
    266 	ts_swapin,
    267 	ts_swapout,
    268 	ts_trapret,
    269 	ts_preempt,
    270 	ts_setrun,
    271 	ts_sleep,
    272 	ts_tick,
    273 	ts_wakeup,
    274 	ts_donice,
    275 	ts_globpri,
    276 	ts_nullsys,	/* set_process_group */
    277 	ts_yield,
    278 	ts_doprio,
    279 };
    280 
    281 /*
    282  * ia_classfuncs is used for interactive class threads; IA threads are stored
    283  * on the same class list as TS threads, and most of the class functions are
    284  * identical, but a few have different enough functionality to require their
    285  * own functions.
    286  */
    287 static struct classfuncs ia_classfuncs = {
    288 	/* class functions */
    289 	ts_admin,
    290 	ia_getclinfo,
    291 	ia_parmsin,
    292 	ts_parmsout,
    293 	ia_vaparmsin,
    294 	ia_vaparmsout,
    295 	ia_getclpri,
    296 	ts_alloc,
    297 	ts_free,
    298 
    299 	/* thread functions */
    300 	ts_enterclass,
    301 	ts_exitclass,
    302 	ts_canexit,
    303 	ts_fork,
    304 	ts_forkret,
    305 	ia_parmsget,
    306 	ia_parmsset,
    307 	ts_nullsys,	/* stop */
    308 	ts_exit,
    309 	ts_nullsys,	/* active */
    310 	ts_nullsys,	/* inactive */
    311 	ts_swapin,
    312 	ts_swapout,
    313 	ts_trapret,
    314 	ts_preempt,
    315 	ts_setrun,
    316 	ts_sleep,
    317 	ts_tick,
    318 	ts_wakeup,
    319 	ts_donice,
    320 	ts_globpri,
    321 	ia_set_process_group,
    322 	ts_yield,
    323 	ts_doprio,
    324 };
    325 
    326 
    327 /*
    328  * Time sharing class initialization.  Called by dispinit() at boot time.
    329  * We can ignore the clparmsz argument since we know that the smallest
    330  * possible parameter buffer is big enough for us.
    331  */
    332 /* ARGSUSED */
    333 static pri_t
    334 ts_init(id_t cid, int clparmsz, classfuncs_t **clfuncspp)
    335 {
    336 	int i;
    337 	extern pri_t ts_getmaxumdpri(void);
    338 
    339 	ts_dptbl = ts_getdptbl();
    340 	ts_kmdpris = ts_getkmdpris();
    341 	ts_maxumdpri = ts_getmaxumdpri();
    342 	ts_maxglobpri = MAX(ts_kmdpris[0], ts_dptbl[ts_maxumdpri].ts_globpri);
    343 
    344 	/*
    345 	 * Initialize the tsproc lists.
    346 	 */
    347 	for (i = 0; i < TS_LISTS; i++) {
    348 		ts_plisthead[i].ts_next = ts_plisthead[i].ts_prev =
    349 		    &ts_plisthead[i];
    350 	}
    351 
    352 	/*
    353 	 * We're required to return a pointer to our classfuncs
    354 	 * structure and the highest global priority value we use.
    355 	 */
    356 	*clfuncspp = &ts_classfuncs;
    357 	return (ts_maxglobpri);
    358 }
    359 
    360 
    361 /*
    362  * Interactive class scheduler initialization
    363  */
    364 /* ARGSUSED */
    365 pri_t
    366 ia_init(id_t cid, int clparmsz, classfuncs_t **clfuncspp)
    367 {
    368 	/*
    369 	 * We're required to return a pointer to our classfuncs
    370 	 * structure and the highest global priority value we use.
    371 	 */
    372 	ia_cid = cid;
    373 	*clfuncspp = &ia_classfuncs;
    374 	return (ts_maxglobpri);
    375 }
    376 
    377 
    378 /*
    379  * Get or reset the ts_dptbl values per the user's request.
    380  */
    381 static int
    382 ts_admin(caddr_t uaddr, cred_t *reqpcredp)
    383 {
    384 	tsadmin_t	tsadmin;
    385 	tsdpent_t	*tmpdpp;
    386 	int		userdpsz;
    387 	int		i;
    388 	size_t		tsdpsz;
    389 
    390 	if (get_udatamodel() == DATAMODEL_NATIVE) {
    391 		if (copyin(uaddr, &tsadmin, sizeof (tsadmin_t)))
    392 			return (EFAULT);
    393 	}
    394 #ifdef _SYSCALL32_IMPL
    395 	else {
    396 		/* get tsadmin struct from ILP32 caller */
    397 		tsadmin32_t tsadmin32;
    398 		if (copyin(uaddr, &tsadmin32, sizeof (tsadmin32_t)))
    399 			return (EFAULT);
    400 		tsadmin.ts_dpents =
    401 		    (struct tsdpent *)(uintptr_t)tsadmin32.ts_dpents;
    402 		tsadmin.ts_ndpents = tsadmin32.ts_ndpents;
    403 		tsadmin.ts_cmd = tsadmin32.ts_cmd;
    404 	}
    405 #endif /* _SYSCALL32_IMPL */
    406 
    407 	tsdpsz = (ts_maxumdpri + 1) * sizeof (tsdpent_t);
    408 
    409 	switch (tsadmin.ts_cmd) {
    410 	case TS_GETDPSIZE:
    411 		tsadmin.ts_ndpents = ts_maxumdpri + 1;
    412 
    413 		if (get_udatamodel() == DATAMODEL_NATIVE) {
    414 			if (copyout(&tsadmin, uaddr, sizeof (tsadmin_t)))
    415 				return (EFAULT);
    416 		}
    417 #ifdef _SYSCALL32_IMPL
    418 		else {
    419 			/* return tsadmin struct to ILP32 caller */
    420 			tsadmin32_t tsadmin32;
    421 			tsadmin32.ts_dpents =
    422 			    (caddr32_t)(uintptr_t)tsadmin.ts_dpents;
    423 			tsadmin32.ts_ndpents = tsadmin.ts_ndpents;
    424 			tsadmin32.ts_cmd = tsadmin.ts_cmd;
    425 			if (copyout(&tsadmin32, uaddr, sizeof (tsadmin32_t)))
    426 				return (EFAULT);
    427 		}
    428 #endif /* _SYSCALL32_IMPL */
    429 		break;
    430 
    431 	case TS_GETDPTBL:
    432 		userdpsz = MIN(tsadmin.ts_ndpents * sizeof (tsdpent_t),
    433 		    tsdpsz);
    434 		if (copyout(ts_dptbl, tsadmin.ts_dpents, userdpsz))
    435 			return (EFAULT);
    436 
    437 		tsadmin.ts_ndpents = userdpsz / sizeof (tsdpent_t);
    438 
    439 		if (get_udatamodel() == DATAMODEL_NATIVE) {
    440 			if (copyout(&tsadmin, uaddr, sizeof (tsadmin_t)))
    441 				return (EFAULT);
    442 		}
    443 #ifdef _SYSCALL32_IMPL
    444 		else {
    445 			/* return tsadmin struct to ILP32 callers */
    446 			tsadmin32_t tsadmin32;
    447 			tsadmin32.ts_dpents =
    448 			    (caddr32_t)(uintptr_t)tsadmin.ts_dpents;
    449 			tsadmin32.ts_ndpents = tsadmin.ts_ndpents;
    450 			tsadmin32.ts_cmd = tsadmin.ts_cmd;
    451 			if (copyout(&tsadmin32, uaddr, sizeof (tsadmin32_t)))
    452 				return (EFAULT);
    453 		}
    454 #endif /* _SYSCALL32_IMPL */
    455 		break;
    456 
    457 	case TS_SETDPTBL:
    458 		/*
    459 		 * We require that the requesting process has sufficient
    460 		 * priveleges.  We also require that the table supplied by
    461 		 * the user exactly match the current ts_dptbl in size.
    462 		 */
    463 		if (secpolicy_dispadm(reqpcredp) != 0)
    464 			return (EPERM);
    465 
    466 		if (tsadmin.ts_ndpents * sizeof (tsdpent_t) != tsdpsz) {
    467 			return (EINVAL);
    468 		}
    469 
    470 		/*
    471 		 * We read the user supplied table into a temporary buffer
    472 		 * where it is validated before being copied over the
    473 		 * ts_dptbl.
    474 		 */
    475 		tmpdpp = kmem_alloc(tsdpsz, KM_SLEEP);
    476 		if (copyin((caddr_t)tsadmin.ts_dpents, (caddr_t)tmpdpp,
    477 		    tsdpsz)) {
    478 			kmem_free(tmpdpp, tsdpsz);
    479 			return (EFAULT);
    480 		}
    481 		for (i = 0; i < tsadmin.ts_ndpents; i++) {
    482 
    483 			/*
    484 			 * Validate the user supplied values.  All we are doing
    485 			 * here is verifying that the values are within their
    486 			 * allowable ranges and will not panic the system.  We
    487 			 * make no attempt to ensure that the resulting
    488 			 * configuration makes sense or results in reasonable
    489 			 * performance.
    490 			 */
    491 			if (tmpdpp[i].ts_quantum <= 0) {
    492 				kmem_free(tmpdpp, tsdpsz);
    493 				return (EINVAL);
    494 			}
    495 			if (tmpdpp[i].ts_tqexp > ts_maxumdpri ||
    496 			    tmpdpp[i].ts_tqexp < 0) {
    497 				kmem_free(tmpdpp, tsdpsz);
    498 				return (EINVAL);
    499 			}
    500 			if (tmpdpp[i].ts_slpret > ts_maxumdpri ||
    501 			    tmpdpp[i].ts_slpret < 0) {
    502 				kmem_free(tmpdpp, tsdpsz);
    503 				return (EINVAL);
    504 			}
    505 			if (tmpdpp[i].ts_maxwait < 0) {
    506 				kmem_free(tmpdpp, tsdpsz);
    507 				return (EINVAL);
    508 			}
    509 			if (tmpdpp[i].ts_lwait > ts_maxumdpri ||
    510 			    tmpdpp[i].ts_lwait < 0) {
    511 				kmem_free(tmpdpp, tsdpsz);
    512 				return (EINVAL);
    513 			}
    514 		}
    515 
    516 		/*
    517 		 * Copy the user supplied values over the current ts_dptbl
    518 		 * values.  The ts_globpri member is read-only so we don't
    519 		 * overwrite it.
    520 		 */
    521 		mutex_enter(&ts_dptblock);
    522 		for (i = 0; i < tsadmin.ts_ndpents; i++) {
    523 			ts_dptbl[i].ts_quantum = tmpdpp[i].ts_quantum;
    524 			ts_dptbl[i].ts_tqexp = tmpdpp[i].ts_tqexp;
    525 			ts_dptbl[i].ts_slpret = tmpdpp[i].ts_slpret;
    526 			ts_dptbl[i].ts_maxwait = tmpdpp[i].ts_maxwait;
    527 			ts_dptbl[i].ts_lwait = tmpdpp[i].ts_lwait;
    528 		}
    529 		mutex_exit(&ts_dptblock);
    530 		kmem_free(tmpdpp, tsdpsz);
    531 		break;
    532 
    533 	default:
    534 		return (EINVAL);
    535 	}
    536 	return (0);
    537 }
    538 
    539 
    540 /*
    541  * Allocate a time-sharing class specific thread structure and
    542  * initialize it with the parameters supplied. Also move the thread
    543  * to specified time-sharing priority.
    544  */
    545 static int
    546 ts_enterclass(kthread_t *t, id_t cid, void *parmsp,
    547 	cred_t *reqpcredp, void *bufp)
    548 {
    549 	tsparms_t	*tsparmsp = (tsparms_t *)parmsp;
    550 	tsproc_t	*tspp;
    551 	pri_t		reqtsuprilim;
    552 	pri_t		reqtsupri;
    553 	static uint32_t	tspexists = 0;	/* set on first occurrence of */
    554 					/*   a time-sharing process */
    555 
    556 	tspp = (tsproc_t *)bufp;
    557 	ASSERT(tspp != NULL);
    558 
    559 	/*
    560 	 * Initialize the tsproc structure.
    561 	 */
    562 	tspp->ts_cpupri = tsmedumdpri;
    563 	if (cid == ia_cid) {
    564 		/*
    565 		 * Check to make sure caller is either privileged or the
    566 		 * window system.  When the window system is converted
    567 		 * to using privileges, the second check can go away.
    568 		 */
    569 		if (reqpcredp != NULL && !groupmember(IA_gid, reqpcredp) &&
    570 		    secpolicy_setpriority(reqpcredp) != 0)
    571 			return (EPERM);
    572 		/*
    573 		 * Belongs to IA "class", so set appropriate flags.
    574 		 * Mark as 'on' so it will not be a swap victim
    575 		 * while forking.
    576 		 */
    577 		tspp->ts_flags = TSIA | TSIASET;
    578 		tspp->ts_boost = ia_boost;
    579 	} else {
    580 		tspp->ts_flags = 0;
    581 		tspp->ts_boost = 0;
    582 	}
    583 
    584 	if (tsparmsp == NULL) {
    585 		/*
    586 		 * Use default values.
    587 		 */
    588 		tspp->ts_uprilim = tspp->ts_upri = 0;
    589 		tspp->ts_nice = NZERO;
    590 	} else {
    591 		/*
    592 		 * Use supplied values.
    593 		 */
    594 		if (tsparmsp->ts_uprilim == TS_NOCHANGE)
    595 			reqtsuprilim = 0;
    596 		else {
    597 			if (tsparmsp->ts_uprilim > 0 &&
    598 			    secpolicy_setpriority(reqpcredp) != 0)
    599 				return (EPERM);
    600 			reqtsuprilim = tsparmsp->ts_uprilim;
    601 		}
    602 
    603 		if (tsparmsp->ts_upri == TS_NOCHANGE) {
    604 			reqtsupri = reqtsuprilim;
    605 		} else {
    606 			if (tsparmsp->ts_upri > 0 &&
    607 			    secpolicy_setpriority(reqpcredp) != 0)
    608 				return (EPERM);
    609 			/*
    610 			 * Set the user priority to the requested value
    611 			 * or the upri limit, whichever is lower.
    612 			 */
    613 			reqtsupri = tsparmsp->ts_upri;
    614 			if (reqtsupri > reqtsuprilim)
    615 				reqtsupri = reqtsuprilim;
    616 		}
    617 
    618 
    619 		tspp->ts_uprilim = reqtsuprilim;
    620 		tspp->ts_upri = reqtsupri;
    621 		tspp->ts_nice = NZERO - (NZERO * reqtsupri) / ts_maxupri;
    622 	}
    623 	TS_NEWUMDPRI(tspp);
    624 
    625 	tspp->ts_dispwait = 0;
    626 	tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum;
    627 	tspp->ts_tp = t;
    628 	cpucaps_sc_init(&tspp->ts_caps);
    629 
    630 	/*
    631 	 * Reset priority. Process goes to a "user mode" priority
    632 	 * here regardless of whether or not it has slept since
    633 	 * entering the kernel.
    634 	 */
    635 	thread_lock(t);			/* get dispatcher lock on thread */
    636 	t->t_clfuncs = &(sclass[cid].cl_funcs->thread);
    637 	t->t_cid = cid;
    638 	t->t_cldata = (void *)tspp;
    639 	t->t_schedflag &= ~TS_RUNQMATCH;
    640 	ts_change_priority(t, tspp);
    641 	thread_unlock(t);
    642 
    643 	/*
    644 	 * Link new structure into tsproc list.
    645 	 */
    646 	TS_LIST_INSERT(tspp);
    647 
    648 	/*
    649 	 * If this is the first time-sharing thread to occur since
    650 	 * boot we set up the initial call to ts_update() here.
    651 	 * Use an atomic compare-and-swap since that's easier and
    652 	 * faster than a mutex (but check with an ordinary load first
    653 	 * since most of the time this will already be done).
    654 	 */
    655 	if (tspexists == 0 && cas32(&tspexists, 0, 1) == 0)
    656 		(void) timeout(ts_update, NULL, hz);
    657 
    658 	return (0);
    659 }
    660 
    661 
    662 /*
    663  * Free tsproc structure of thread.
    664  */
    665 static void
    666 ts_exitclass(void *procp)
    667 {
    668 	tsproc_t *tspp = (tsproc_t *)procp;
    669 
    670 	/* Remove tsproc_t structure from list */
    671 	TS_LIST_DELETE(tspp);
    672 	kmem_free(tspp, sizeof (tsproc_t));
    673 }
    674 
    675 /* ARGSUSED */
    676 static int
    677 ts_canexit(kthread_t *t, cred_t *cred)
    678 {
    679 	/*
    680 	 * A thread can always leave a TS/IA class
    681 	 */
    682 	return (0);
    683 }
    684 
    685 static int
    686 ts_fork(kthread_t *t, kthread_t *ct, void *bufp)
    687 {
    688 	tsproc_t	*ptspp;		/* ptr to parent's tsproc structure */
    689 	tsproc_t	*ctspp;		/* ptr to child's tsproc structure */
    690 
    691 	ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
    692 
    693 	ctspp = (tsproc_t *)bufp;
    694 	ASSERT(ctspp != NULL);
    695 	ptspp = (tsproc_t *)t->t_cldata;
    696 	/*
    697 	 * Initialize child's tsproc structure.
    698 	 */
    699 	thread_lock(t);
    700 	ctspp->ts_timeleft = ts_dptbl[ptspp->ts_cpupri].ts_quantum;
    701 	ctspp->ts_cpupri = ptspp->ts_cpupri;
    702 	ctspp->ts_boost = ptspp->ts_boost;
    703 	ctspp->ts_uprilim = ptspp->ts_uprilim;
    704 	ctspp->ts_upri = ptspp->ts_upri;
    705 	TS_NEWUMDPRI(ctspp);
    706 	ctspp->ts_nice = ptspp->ts_nice;
    707 	ctspp->ts_dispwait = 0;
    708 	ctspp->ts_flags = ptspp->ts_flags & ~(TSKPRI | TSBACKQ | TSRESTORE);
    709 	ctspp->ts_tp = ct;
    710 	cpucaps_sc_init(&ctspp->ts_caps);
    711 	thread_unlock(t);
    712 
    713 	/*
    714 	 * Link new structure into tsproc list.
    715 	 */
    716 	ct->t_cldata = (void *)ctspp;
    717 	TS_LIST_INSERT(ctspp);
    718 	return (0);
    719 }
    720 
    721 
    722 /*
    723  * Child is placed at back of dispatcher queue and parent gives
    724  * up processor so that the child runs first after the fork.
    725  * This allows the child immediately execing to break the multiple
    726  * use of copy on write pages with no disk home. The parent will
    727  * get to steal them back rather than uselessly copying them.
    728  */
    729 static void
    730 ts_forkret(kthread_t *t, kthread_t *ct)
    731 {
    732 	proc_t	*pp = ttoproc(t);
    733 	proc_t	*cp = ttoproc(ct);
    734 	tsproc_t *tspp;
    735 
    736 	ASSERT(t == curthread);
    737 	ASSERT(MUTEX_HELD(&pidlock));
    738 
    739 	/*
    740 	 * Grab the child's p_lock before dropping pidlock to ensure
    741 	 * the process does not disappear before we set it running.
    742 	 */
    743 	mutex_enter(&cp->p_lock);
    744 	mutex_exit(&pidlock);
    745 	continuelwps(cp);
    746 	mutex_exit(&cp->p_lock);
    747 
    748 	mutex_enter(&pp->p_lock);
    749 	continuelwps(pp);
    750 	mutex_exit(&pp->p_lock);
    751 
    752 	thread_lock(t);
    753 	tspp = (tsproc_t *)(t->t_cldata);
    754 	tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_tqexp;
    755 	TS_NEWUMDPRI(tspp);
    756 	tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum;
    757 	tspp->ts_dispwait = 0;
    758 	t->t_pri = ts_dptbl[tspp->ts_umdpri].ts_globpri;
    759 	ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri);
    760 	tspp->ts_flags &= ~TSKPRI;
    761 	THREAD_TRANSITION(t);
    762 	ts_setrun(t);
    763 	thread_unlock(t);
    764 
    765 	swtch();
    766 }
    767 
    768 
    769 /*
    770  * Get information about the time-sharing class into the buffer
    771  * pointed to by tsinfop. The maximum configured user priority
    772  * is the only information we supply.  ts_getclinfo() is called
    773  * for TS threads, and ia_getclinfo() is called for IA threads.
    774  */
    775 static int
    776 ts_getclinfo(void *infop)
    777 {
    778 	tsinfo_t *tsinfop = (tsinfo_t *)infop;
    779 	tsinfop->ts_maxupri = ts_maxupri;
    780 	return (0);
    781 }
    782 
    783 static int
    784 ia_getclinfo(void *infop)
    785 {
    786 	iainfo_t *iainfop = (iainfo_t *)infop;
    787 	iainfop->ia_maxupri = ia_maxupri;
    788 	return (0);
    789 }
    790 
    791 
    792 /*
    793  * Return the user mode scheduling priority range.
    794  */
    795 static int
    796 ts_getclpri(pcpri_t *pcprip)
    797 {
    798 	pcprip->pc_clpmax = ts_maxupri;
    799 	pcprip->pc_clpmin = -ts_maxupri;
    800 	return (0);
    801 }
    802 
    803 
    804 static int
    805 ia_getclpri(pcpri_t *pcprip)
    806 {
    807 	pcprip->pc_clpmax = ia_maxupri;
    808 	pcprip->pc_clpmin = -ia_maxupri;
    809 	return (0);
    810 }
    811 
    812 
    813 static void
    814 ts_nullsys()
    815 {}
    816 
    817 
    818 /*
    819  * Get the time-sharing parameters of the thread pointed to by
    820  * tsprocp into the buffer pointed to by tsparmsp.  ts_parmsget()
    821  * is called for TS threads, and ia_parmsget() is called for IA
    822  * threads.
    823  */
    824 static void
    825 ts_parmsget(kthread_t *t, void *parmsp)
    826 {
    827 	tsproc_t *tspp = (tsproc_t *)t->t_cldata;
    828 	tsparms_t *tsparmsp = (tsparms_t *)parmsp;
    829 
    830 	tsparmsp->ts_uprilim = tspp->ts_uprilim;
    831 	tsparmsp->ts_upri = tspp->ts_upri;
    832 }
    833 
    834 static void
    835 ia_parmsget(kthread_t *t, void *parmsp)
    836 {
    837 	tsproc_t *tspp = (tsproc_t *)t->t_cldata;
    838 	iaparms_t *iaparmsp = (iaparms_t *)parmsp;
    839 
    840 	iaparmsp->ia_uprilim = tspp->ts_uprilim;
    841 	iaparmsp->ia_upri = tspp->ts_upri;
    842 	if (tspp->ts_flags & TSIASET)
    843 		iaparmsp->ia_mode = IA_SET_INTERACTIVE;
    844 	else
    845 		iaparmsp->ia_mode = IA_INTERACTIVE_OFF;
    846 }
    847 
    848 
    849 /*
    850  * Check the validity of the time-sharing parameters in the buffer
    851  * pointed to by tsparmsp.
    852  * ts_parmsin() is called for TS threads, and ia_parmsin() is called
    853  * for IA threads.
    854  */
    855 static int
    856 ts_parmsin(void *parmsp)
    857 {
    858 	tsparms_t	*tsparmsp = (tsparms_t *)parmsp;
    859 	/*
    860 	 * Check validity of parameters.
    861 	 */
    862 	if ((tsparmsp->ts_uprilim > ts_maxupri ||
    863 	    tsparmsp->ts_uprilim < -ts_maxupri) &&
    864 	    tsparmsp->ts_uprilim != TS_NOCHANGE)
    865 		return (EINVAL);
    866 
    867 	if ((tsparmsp->ts_upri > ts_maxupri ||
    868 	    tsparmsp->ts_upri < -ts_maxupri) &&
    869 	    tsparmsp->ts_upri != TS_NOCHANGE)
    870 		return (EINVAL);
    871 
    872 	return (0);
    873 }
    874 
    875 static int
    876 ia_parmsin(void *parmsp)
    877 {
    878 	iaparms_t	*iaparmsp = (iaparms_t *)parmsp;
    879 
    880 	if ((iaparmsp->ia_uprilim > ia_maxupri ||
    881 	    iaparmsp->ia_uprilim < -ia_maxupri) &&
    882 	    iaparmsp->ia_uprilim != IA_NOCHANGE) {
    883 		return (EINVAL);
    884 	}
    885 
    886 	if ((iaparmsp->ia_upri > ia_maxupri ||
    887 	    iaparmsp->ia_upri < -ia_maxupri) &&
    888 	    iaparmsp->ia_upri != IA_NOCHANGE) {
    889 		return (EINVAL);
    890 	}
    891 
    892 	return (0);
    893 }
    894 
    895 
    896 /*
    897  * Check the validity of the time-sharing parameters in the pc_vaparms_t
    898  * structure vaparmsp and put them in the buffer pointed to by tsparmsp.
    899  * pc_vaparms_t contains (key, value) pairs of parameter.
    900  * ts_vaparmsin() is called for TS threads, and ia_vaparmsin() is called
    901  * for IA threads. ts_vaparmsin() is the variable parameter version of
    902  * ts_parmsin() and ia_vaparmsin() is the variable parameter version of
    903  * ia_parmsin().
    904  */
    905 static int
    906 ts_vaparmsin(void *parmsp, pc_vaparms_t *vaparmsp)
    907 {
    908 	tsparms_t	*tsparmsp = (tsparms_t *)parmsp;
    909 	int		priflag = 0;
    910 	int		limflag = 0;
    911 	uint_t		cnt;
    912 	pc_vaparm_t	*vpp = &vaparmsp->pc_parms[0];
    913 
    914 
    915 	/*
    916 	 * TS_NOCHANGE (-32768) is outside of the range of values for
    917 	 * ts_uprilim and ts_upri. If the structure tsparms_t is changed,
    918 	 * TS_NOCHANGE should be replaced by a flag word (in the same manner
    919 	 * as in rt.c).
    920 	 */
    921 	tsparmsp->ts_uprilim = TS_NOCHANGE;
    922 	tsparmsp->ts_upri = TS_NOCHANGE;
    923 
    924 	/*
    925 	 * Get the varargs parameter and check validity of parameters.
    926 	 */
    927 	if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
    928 		return (EINVAL);
    929 
    930 	for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
    931 
    932 		switch (vpp->pc_key) {
    933 		case TS_KY_UPRILIM:
    934 			if (limflag++)
    935 				return (EINVAL);
    936 			tsparmsp->ts_uprilim = (pri_t)vpp->pc_parm;
    937 			if (tsparmsp->ts_uprilim > ts_maxupri ||
    938 			    tsparmsp->ts_uprilim < -ts_maxupri)
    939 				return (EINVAL);
    940 			break;
    941 
    942 		case TS_KY_UPRI:
    943 			if (priflag++)
    944 				return (EINVAL);
    945 			tsparmsp->ts_upri = (pri_t)vpp->pc_parm;
    946 			if (tsparmsp->ts_upri > ts_maxupri ||
    947 			    tsparmsp->ts_upri < -ts_maxupri)
    948 				return (EINVAL);
    949 			break;
    950 
    951 		default:
    952 			return (EINVAL);
    953 		}
    954 	}
    955 
    956 	if (vaparmsp->pc_vaparmscnt == 0) {
    957 		/*
    958 		 * Use default parameters.
    959 		 */
    960 		tsparmsp->ts_upri = tsparmsp->ts_uprilim = 0;
    961 	}
    962 
    963 	return (0);
    964 }
    965 
    966 static int
    967 ia_vaparmsin(void *parmsp, pc_vaparms_t *vaparmsp)
    968 {
    969 	iaparms_t	*iaparmsp = (iaparms_t *)parmsp;
    970 	int		priflag = 0;
    971 	int		limflag = 0;
    972 	int		mflag = 0;
    973 	uint_t		cnt;
    974 	pc_vaparm_t	*vpp = &vaparmsp->pc_parms[0];
    975 
    976 	/*
    977 	 * IA_NOCHANGE (-32768) is outside of the range of values for
    978 	 * ia_uprilim, ia_upri and ia_mode. If the structure iaparms_t is
    979 	 * changed, IA_NOCHANGE should be replaced by a flag word (in the
    980 	 * same manner as in rt.c).
    981 	 */
    982 	iaparmsp->ia_uprilim = IA_NOCHANGE;
    983 	iaparmsp->ia_upri = IA_NOCHANGE;
    984 	iaparmsp->ia_mode = IA_NOCHANGE;
    985 
    986 	/*
    987 	 * Get the varargs parameter and check validity of parameters.
    988 	 */
    989 	if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
    990 		return (EINVAL);
    991 
    992 	for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
    993 
    994 		switch (vpp->pc_key) {
    995 		case IA_KY_UPRILIM:
    996 			if (limflag++)
    997 				return (EINVAL);
    998 			iaparmsp->ia_uprilim = (pri_t)vpp->pc_parm;
    999 			if (iaparmsp->ia_uprilim > ia_maxupri ||
   1000 			    iaparmsp->ia_uprilim < -ia_maxupri)
   1001 				return (EINVAL);
   1002 			break;
   1003 
   1004 		case IA_KY_UPRI:
   1005 			if (priflag++)
   1006 				return (EINVAL);
   1007 			iaparmsp->ia_upri = (pri_t)vpp->pc_parm;
   1008 			if (iaparmsp->ia_upri > ia_maxupri ||
   1009 			    iaparmsp->ia_upri < -ia_maxupri)
   1010 				return (EINVAL);
   1011 			break;
   1012 
   1013 		case IA_KY_MODE:
   1014 			if (mflag++)
   1015 				return (EINVAL);
   1016 			iaparmsp->ia_mode = (int)vpp->pc_parm;
   1017 			if (iaparmsp->ia_mode != IA_SET_INTERACTIVE &&
   1018 			    iaparmsp->ia_mode != IA_INTERACTIVE_OFF)
   1019 				return (EINVAL);
   1020 			break;
   1021 
   1022 		default:
   1023 			return (EINVAL);
   1024 		}
   1025 	}
   1026 
   1027 	if (vaparmsp->pc_vaparmscnt == 0) {
   1028 		/*
   1029 		 * Use default parameters.
   1030 		 */
   1031 		iaparmsp->ia_upri = iaparmsp->ia_uprilim = 0;
   1032 		iaparmsp->ia_mode = IA_SET_INTERACTIVE;
   1033 	}
   1034 
   1035 	return (0);
   1036 }
   1037 
   1038 /*
   1039  * Nothing to do here but return success.
   1040  */
   1041 /* ARGSUSED */
   1042 static int
   1043 ts_parmsout(void *parmsp, pc_vaparms_t *vaparmsp)
   1044 {
   1045 	return (0);
   1046 }
   1047 
   1048 
   1049 /*
   1050  * Copy all selected time-sharing class parameters to the user.
   1051  * The parameters are specified by a key.
   1052  */
   1053 static int
   1054 ts_vaparmsout(void *prmsp, pc_vaparms_t *vaparmsp)
   1055 {
   1056 	tsparms_t	*tsprmsp = (tsparms_t *)prmsp;
   1057 	int		priflag = 0;
   1058 	int		limflag = 0;
   1059 	uint_t		cnt;
   1060 	pc_vaparm_t	*vpp = &vaparmsp->pc_parms[0];
   1061 
   1062 	ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
   1063 
   1064 	if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
   1065 		return (EINVAL);
   1066 
   1067 	for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
   1068 
   1069 		switch (vpp->pc_key) {
   1070 		case TS_KY_UPRILIM:
   1071 			if (limflag++)
   1072 				return (EINVAL);
   1073 			if (copyout(&tsprmsp->ts_uprilim,
   1074 			    (caddr_t)(uintptr_t)vpp->pc_parm, sizeof (pri_t)))
   1075 				return (EFAULT);
   1076 			break;
   1077 
   1078 		case TS_KY_UPRI:
   1079 			if (priflag++)
   1080 				return (EINVAL);
   1081 			if (copyout(&tsprmsp->ts_upri,
   1082 			    (caddr_t)(uintptr_t)vpp->pc_parm, sizeof (pri_t)))
   1083 				return (EFAULT);
   1084 			break;
   1085 
   1086 		default:
   1087 			return (EINVAL);
   1088 		}
   1089 	}
   1090 
   1091 	return (0);
   1092 }
   1093 
   1094 
   1095 /*
   1096  * Copy all selected interactive class parameters to the user.
   1097  * The parameters are specified by a key.
   1098  */
   1099 static int
   1100 ia_vaparmsout(void *prmsp, pc_vaparms_t *vaparmsp)
   1101 {
   1102 	iaparms_t	*iaprmsp = (iaparms_t *)prmsp;
   1103 	int		priflag = 0;
   1104 	int		limflag = 0;
   1105 	int		mflag = 0;
   1106 	uint_t		cnt;
   1107 	pc_vaparm_t	*vpp = &vaparmsp->pc_parms[0];
   1108 
   1109 	ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
   1110 
   1111 	if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
   1112 		return (EINVAL);
   1113 
   1114 	for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
   1115 
   1116 		switch (vpp->pc_key) {
   1117 		case IA_KY_UPRILIM:
   1118 			if (limflag++)
   1119 				return (EINVAL);
   1120 			if (copyout(&