17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 59acbbeafSnn35248 * Common Development and Distribution License (the "License"). 69acbbeafSnn35248 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 219ac8606fSraf 227c478bd9Sstevel@tonic-gate /* 23d5493db7SPramod Batni * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved. 24*24d819e6SJerry Jelinek * Copyright 2013, Joyent, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #include <sys/types.h> 317c478bd9Sstevel@tonic-gate #include <sys/param.h> 327c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 337c478bd9Sstevel@tonic-gate #include <sys/cred.h> 347c478bd9Sstevel@tonic-gate #include <sys/proc.h> 357c478bd9Sstevel@tonic-gate #include <sys/session.h> 367c478bd9Sstevel@tonic-gate #include <sys/strsubr.h> 377c478bd9Sstevel@tonic-gate #include <sys/signal.h> 387c478bd9Sstevel@tonic-gate #include <sys/user.h> 397c478bd9Sstevel@tonic-gate #include <sys/priocntl.h> 407c478bd9Sstevel@tonic-gate #include <sys/class.h> 417c478bd9Sstevel@tonic-gate #include <sys/disp.h> 427c478bd9Sstevel@tonic-gate #include <sys/procset.h> 437c478bd9Sstevel@tonic-gate #include <sys/debug.h> 447c478bd9Sstevel@tonic-gate #include <sys/ts.h> 457c478bd9Sstevel@tonic-gate #include <sys/tspriocntl.h> 467c478bd9Sstevel@tonic-gate #include <sys/iapriocntl.h> 477c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 487c478bd9Sstevel@tonic-gate #include <sys/errno.h> 497c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 507c478bd9Sstevel@tonic-gate #include <sys/systm.h> /* for lbolt */ 517c478bd9Sstevel@tonic-gate #include <sys/vtrace.h> 527c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h> 537c478bd9Sstevel@tonic-gate #include <sys/schedctl.h> 547c478bd9Sstevel@tonic-gate #include <sys/tnf_probe.h> 557c478bd9Sstevel@tonic-gate #include <sys/atomic.h> 567c478bd9Sstevel@tonic-gate #include <sys/policy.h> 577c478bd9Sstevel@tonic-gate #include <sys/sdt.h> 587c478bd9Sstevel@tonic-gate #include <sys/cpupart.h> 597c478bd9Sstevel@tonic-gate #include <vm/rm.h> 607c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h> 617c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 62c97ad5cdSakolb #include <sys/cpucaps.h> 637c478bd9Sstevel@tonic-gate 647c478bd9Sstevel@tonic-gate static pri_t ts_init(id_t, int, classfuncs_t **); 657c478bd9Sstevel@tonic-gate 667c478bd9Sstevel@tonic-gate static struct sclass csw = { 677c478bd9Sstevel@tonic-gate "TS", 687c478bd9Sstevel@tonic-gate ts_init, 697c478bd9Sstevel@tonic-gate 0 707c478bd9Sstevel@tonic-gate }; 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate static struct modlsched modlsched = { 737c478bd9Sstevel@tonic-gate &mod_schedops, "time sharing sched class", &csw 747c478bd9Sstevel@tonic-gate }; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 777c478bd9Sstevel@tonic-gate MODREV_1, (void *)&modlsched, NULL 787c478bd9Sstevel@tonic-gate }; 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate int 817c478bd9Sstevel@tonic-gate _init() 827c478bd9Sstevel@tonic-gate { 837c478bd9Sstevel@tonic-gate return (mod_install(&modlinkage)); 847c478bd9Sstevel@tonic-gate } 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate int 877c478bd9Sstevel@tonic-gate _fini() 887c478bd9Sstevel@tonic-gate { 897c478bd9Sstevel@tonic-gate return (EBUSY); /* don't remove TS for now */ 907c478bd9Sstevel@tonic-gate } 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate int 937c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 947c478bd9Sstevel@tonic-gate { 957c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 967c478bd9Sstevel@tonic-gate } 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * Class specific code for the time-sharing class 1007c478bd9Sstevel@tonic-gate */ 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate 1037c478bd9Sstevel@tonic-gate /* 1047c478bd9Sstevel@tonic-gate * Extern declarations for variables defined in the ts master file 1057c478bd9Sstevel@tonic-gate */ 1067c478bd9Sstevel@tonic-gate #define TSMAXUPRI 60 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate pri_t ts_maxupri = TSMAXUPRI; /* max time-sharing user priority */ 1097c478bd9Sstevel@tonic-gate pri_t ts_maxumdpri; /* maximum user mode ts priority */ 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate pri_t ia_maxupri = IAMAXUPRI; /* max interactive user priority */ 1127c478bd9Sstevel@tonic-gate pri_t ia_boost = IA_BOOST; /* boost value for interactive */ 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate tsdpent_t *ts_dptbl; /* time-sharing disp parameter table */ 1157c478bd9Sstevel@tonic-gate pri_t *ts_kmdpris; /* array of global pris used by ts procs when */ 1167c478bd9Sstevel@tonic-gate /* sleeping or running in kernel after sleep */ 1177c478bd9Sstevel@tonic-gate 1187c478bd9Sstevel@tonic-gate static id_t ia_cid; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate int ts_sleep_promote = 1; 1217c478bd9Sstevel@tonic-gate 1227c478bd9Sstevel@tonic-gate #define tsmedumdpri (ts_maxumdpri >> 1) 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate #define TS_NEWUMDPRI(tspp) \ 1257c478bd9Sstevel@tonic-gate { \ 1267c478bd9Sstevel@tonic-gate pri_t pri; \ 1277c478bd9Sstevel@tonic-gate pri = (tspp)->ts_cpupri + (tspp)->ts_upri + (tspp)->ts_boost; \ 1287c478bd9Sstevel@tonic-gate if (pri > ts_maxumdpri) \ 1297c478bd9Sstevel@tonic-gate (tspp)->ts_umdpri = ts_maxumdpri; \ 1307c478bd9Sstevel@tonic-gate else if (pri < 0) \ 1317c478bd9Sstevel@tonic-gate (tspp)->ts_umdpri = 0; \ 1327c478bd9Sstevel@tonic-gate else \ 1337c478bd9Sstevel@tonic-gate (tspp)->ts_umdpri = pri; \ 1347c478bd9Sstevel@tonic-gate ASSERT((tspp)->ts_umdpri >= 0 && (tspp)->ts_umdpri <= ts_maxumdpri); \ 1357c478bd9Sstevel@tonic-gate } 1367c478bd9Sstevel@tonic-gate 1377c478bd9Sstevel@tonic-gate /* 1387c478bd9Sstevel@tonic-gate * The tsproc_t structures are kept in an array of circular doubly linked 1397c478bd9Sstevel@tonic-gate * lists. A hash on the thread pointer is used to determine which list 1407c478bd9Sstevel@tonic-gate * each thread should be placed. Each list has a dummy "head" which is 1417c478bd9Sstevel@tonic-gate * never removed, so the list is never empty. ts_update traverses these 1427c478bd9Sstevel@tonic-gate * lists to update the priorities of threads that have been waiting on 1437c478bd9Sstevel@tonic-gate * the run queue. 1447c478bd9Sstevel@tonic-gate */ 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate #define TS_LISTS 16 /* number of lists, must be power of 2 */ 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* hash function, argument is a thread pointer */ 1497c478bd9Sstevel@tonic-gate #define TS_LIST_HASH(tp) (((uintptr_t)(tp) >> 9) & (TS_LISTS - 1)) 1507c478bd9Sstevel@tonic-gate 1517c478bd9Sstevel@tonic-gate /* iterate to the next list */ 1527c478bd9Sstevel@tonic-gate #define TS_LIST_NEXT(i) (((i) + 1) & (TS_LISTS - 1)) 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate /* 1557c478bd9Sstevel@tonic-gate * Insert thread into the appropriate tsproc list. 1567c478bd9Sstevel@tonic-gate */ 1577c478bd9Sstevel@tonic-gate #define TS_LIST_INSERT(tspp) \ 1587c478bd9Sstevel@tonic-gate { \ 1597c478bd9Sstevel@tonic-gate int index = TS_LIST_HASH(tspp->ts_tp); \ 1607c478bd9Sstevel@tonic-gate kmutex_t *lockp = &ts_list_lock[index]; \ 1617c478bd9Sstevel@tonic-gate tsproc_t *headp = &ts_plisthead[index]; \ 1627c478bd9Sstevel@tonic-gate mutex_enter(lockp); \ 1637c478bd9Sstevel@tonic-gate tspp->ts_next = headp->ts_next; \ 1647c478bd9Sstevel@tonic-gate tspp->ts_prev = headp; \ 1657c478bd9Sstevel@tonic-gate headp->ts_next->ts_prev = tspp; \ 1667c478bd9Sstevel@tonic-gate headp->ts_next = tspp; \ 1677c478bd9Sstevel@tonic-gate mutex_exit(lockp); \ 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * Remove thread from tsproc list. 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate #define TS_LIST_DELETE(tspp) \ 1747c478bd9Sstevel@tonic-gate { \ 1757c478bd9Sstevel@tonic-gate int index = TS_LIST_HASH(tspp->ts_tp); \ 1767c478bd9Sstevel@tonic-gate kmutex_t *lockp = &ts_list_lock[index]; \ 1777c478bd9Sstevel@tonic-gate mutex_enter(lockp); \ 1787c478bd9Sstevel@tonic-gate tspp->ts_prev->ts_next = tspp->ts_next; \ 1797c478bd9Sstevel@tonic-gate tspp->ts_next->ts_prev = tspp->ts_prev; \ 1807c478bd9Sstevel@tonic-gate mutex_exit(lockp); \ 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate 1847c478bd9Sstevel@tonic-gate static int ts_admin(caddr_t, cred_t *); 1857c478bd9Sstevel@tonic-gate static int ts_enterclass(kthread_t *, id_t, void *, cred_t *, void *); 1867c478bd9Sstevel@tonic-gate static int ts_fork(kthread_t *, kthread_t *, void *); 1877c478bd9Sstevel@tonic-gate static int ts_getclinfo(void *); 1887c478bd9Sstevel@tonic-gate static int ts_getclpri(pcpri_t *); 1897c478bd9Sstevel@tonic-gate static int ts_parmsin(void *); 1907c478bd9Sstevel@tonic-gate static int ts_parmsout(void *, pc_vaparms_t *); 1917c478bd9Sstevel@tonic-gate static int ts_vaparmsin(void *, pc_vaparms_t *); 1927c478bd9Sstevel@tonic-gate static int ts_vaparmsout(void *, pc_vaparms_t *); 1937c478bd9Sstevel@tonic-gate static int ts_parmsset(kthread_t *, void *, id_t, cred_t *); 194c97ad5cdSakolb static void ts_exit(kthread_t *); 1957c478bd9Sstevel@tonic-gate static int ts_donice(kthread_t *, cred_t *, int, int *); 196d4204c85Sraf static int ts_doprio(kthread_t *, cred_t *, int, int *); 1977c478bd9Sstevel@tonic-gate static void ts_exitclass(void *); 1987c478bd9Sstevel@tonic-gate static int ts_canexit(kthread_t *, cred_t *); 1997c478bd9Sstevel@tonic-gate static void ts_forkret(kthread_t *, kthread_t *); 2007c478bd9Sstevel@tonic-gate static void ts_nullsys(); 2017c478bd9Sstevel@tonic-gate static void ts_parmsget(kthread_t *, void *); 2027c478bd9Sstevel@tonic-gate static void ts_preempt(kthread_t *); 2037c478bd9Sstevel@tonic-gate static void ts_setrun(kthread_t *); 2047c478bd9Sstevel@tonic-gate static void ts_sleep(kthread_t *); 2057c478bd9Sstevel@tonic-gate static pri_t ts_swapin(kthread_t *, int); 2067c478bd9Sstevel@tonic-gate static pri_t ts_swapout(kthread_t *, int); 2077c478bd9Sstevel@tonic-gate static void ts_tick(kthread_t *); 2087c478bd9Sstevel@tonic-gate static void ts_trapret(kthread_t *); 2097c478bd9Sstevel@tonic-gate static void ts_update(void *); 2107c478bd9Sstevel@tonic-gate static int ts_update_list(int); 2117c478bd9Sstevel@tonic-gate static void ts_wakeup(kthread_t *); 2127c478bd9Sstevel@tonic-gate static pri_t ts_globpri(kthread_t *); 2137c478bd9Sstevel@tonic-gate static void ts_yield(kthread_t *); 2147c478bd9Sstevel@tonic-gate extern tsdpent_t *ts_getdptbl(void); 2157c478bd9Sstevel@tonic-gate extern pri_t *ts_getkmdpris(void); 2167c478bd9Sstevel@tonic-gate extern pri_t td_getmaxumdpri(void); 2177c478bd9Sstevel@tonic-gate static int ts_alloc(void **, int); 2187c478bd9Sstevel@tonic-gate static void ts_free(void *); 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate pri_t ia_init(id_t, int, classfuncs_t **); 2217c478bd9Sstevel@tonic-gate static int ia_getclinfo(void *); 222d4204c85Sraf static int ia_getclpri(pcpri_t *); 2237c478bd9Sstevel@tonic-gate static int ia_parmsin(void *); 2247c478bd9Sstevel@tonic-gate static int ia_vaparmsin(void *, pc_vaparms_t *); 2257c478bd9Sstevel@tonic-gate static int ia_vaparmsout(void *, pc_vaparms_t *); 2267c478bd9Sstevel@tonic-gate static int ia_parmsset(kthread_t *, void *, id_t, cred_t *); 2277c478bd9Sstevel@tonic-gate static void ia_parmsget(kthread_t *, void *); 2287c478bd9Sstevel@tonic-gate static void ia_set_process_group(pid_t, pid_t, pid_t); 2297c478bd9Sstevel@tonic-gate 2307c478bd9Sstevel@tonic-gate static void ts_change_priority(kthread_t *, tsproc_t *); 2317c478bd9Sstevel@tonic-gate 2327c478bd9Sstevel@tonic-gate extern pri_t ts_maxkmdpri; /* maximum kernel mode ts priority */ 2337c478bd9Sstevel@tonic-gate static pri_t ts_maxglobpri; /* maximum global priority used by ts class */ 2347c478bd9Sstevel@tonic-gate static kmutex_t ts_dptblock; /* protects time sharing dispatch table */ 2357c478bd9Sstevel@tonic-gate static kmutex_t ts_list_lock[TS_LISTS]; /* protects tsproc lists */ 2367c478bd9Sstevel@tonic-gate static tsproc_t ts_plisthead[TS_LISTS]; /* dummy tsproc at head of lists */ 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate static gid_t IA_gid = 0; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate static struct classfuncs ts_classfuncs = { 2417c478bd9Sstevel@tonic-gate /* class functions */ 2427c478bd9Sstevel@tonic-gate ts_admin, 2437c478bd9Sstevel@tonic-gate ts_getclinfo, 2447c478bd9Sstevel@tonic-gate ts_parmsin, 2457c478bd9Sstevel@tonic-gate ts_parmsout, 2467c478bd9Sstevel@tonic-gate ts_vaparmsin, 2477c478bd9Sstevel@tonic-gate ts_vaparmsout, 2487c478bd9Sstevel@tonic-gate ts_getclpri, 2497c478bd9Sstevel@tonic-gate ts_alloc, 2507c478bd9Sstevel@tonic-gate ts_free, 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /* thread functions */ 2537c478bd9Sstevel@tonic-gate ts_enterclass, 2547c478bd9Sstevel@tonic-gate ts_exitclass, 2557c478bd9Sstevel@tonic-gate ts_canexit, 2567c478bd9Sstevel@tonic-gate ts_fork, 2577c478bd9Sstevel@tonic-gate ts_forkret, 2587c478bd9Sstevel@tonic-gate ts_parmsget, 2597c478bd9Sstevel@tonic-gate ts_parmsset, 2607c478bd9Sstevel@tonic-gate ts_nullsys, /* stop */ 261c97ad5cdSakolb ts_exit, 2627c478bd9Sstevel@tonic-gate ts_nullsys, /* active */ 2637c478bd9Sstevel@tonic-gate ts_nullsys, /* inactive */ 2647c478bd9Sstevel@tonic-gate ts_swapin, 2657c478bd9Sstevel@tonic-gate ts_swapout, 2667c478bd9Sstevel@tonic-gate ts_trapret, 2677c478bd9Sstevel@tonic-gate ts_preempt, 2687c478bd9Sstevel@tonic-gate ts_setrun, 2697c478bd9Sstevel@tonic-gate ts_sleep, 2707c478bd9Sstevel@tonic-gate ts_tick, 2717c478bd9Sstevel@tonic-gate ts_wakeup, 2727c478bd9Sstevel@tonic-gate ts_donice, 2737c478bd9Sstevel@tonic-gate ts_globpri, 2747c478bd9Sstevel@tonic-gate ts_nullsys, /* set_process_group */ 2757c478bd9Sstevel@tonic-gate ts_yield, 276d4204c85Sraf ts_doprio, 2777c478bd9Sstevel@tonic-gate }; 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate /* 2807c478bd9Sstevel@tonic-gate * ia_classfuncs is used for interactive class threads; IA threads are stored 2817c478bd9Sstevel@tonic-gate * on the same class list as TS threads, and most of the class functions are 2827c478bd9Sstevel@tonic-gate * identical, but a few have different enough functionality to require their 2837c478bd9Sstevel@tonic-gate * own functions. 2847c478bd9Sstevel@tonic-gate */ 2857c478bd9Sstevel@tonic-gate static struct classfuncs ia_classfuncs = { 2867c478bd9Sstevel@tonic-gate /* class functions */ 2877c478bd9Sstevel@tonic-gate ts_admin, 2887c478bd9Sstevel@tonic-gate ia_getclinfo, 2897c478bd9Sstevel@tonic-gate ia_parmsin, 2907c478bd9Sstevel@tonic-gate ts_parmsout, 2917c478bd9Sstevel@tonic-gate ia_vaparmsin, 2927c478bd9Sstevel@tonic-gate ia_vaparmsout, 293d4204c85Sraf ia_getclpri, 2947c478bd9Sstevel@tonic-gate ts_alloc, 2957c478bd9Sstevel@tonic-gate ts_free, 2967c478bd9Sstevel@tonic-gate 2977c478bd9Sstevel@tonic-gate /* thread functions */ 2987c478bd9Sstevel@tonic-gate ts_enterclass, 2997c478bd9Sstevel@tonic-gate ts_exitclass, 3007c478bd9Sstevel@tonic-gate ts_canexit, 3017c478bd9Sstevel@tonic-gate ts_fork, 3027c478bd9Sstevel@tonic-gate ts_forkret, 3037c478bd9Sstevel@tonic-gate ia_parmsget, 3047c478bd9Sstevel@tonic-gate ia_parmsset, 3057c478bd9Sstevel@tonic-gate ts_nullsys, /* stop */ 306c97ad5cdSakolb ts_exit, 3077c478bd9Sstevel@tonic-gate ts_nullsys, /* active */ 3087c478bd9Sstevel@tonic-gate ts_nullsys, /* inactive */ 3097c478bd9Sstevel@tonic-gate ts_swapin, 3107c478bd9Sstevel@tonic-gate ts_swapout, 3117c478bd9Sstevel@tonic-gate ts_trapret, 3127c478bd9Sstevel@tonic-gate ts_preempt, 3137c478bd9Sstevel@tonic-gate ts_setrun, 3147c478bd9Sstevel@tonic-gate ts_sleep, 3157c478bd9Sstevel@tonic-gate ts_tick, 3167c478bd9Sstevel@tonic-gate ts_wakeup, 3177c478bd9Sstevel@tonic-gate ts_donice, 3187c478bd9Sstevel@tonic-gate ts_globpri, 3197c478bd9Sstevel@tonic-gate ia_set_process_group, 3207c478bd9Sstevel@tonic-gate ts_yield, 321d4204c85Sraf ts_doprio, 3227c478bd9Sstevel@tonic-gate }; 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate /* 3267c478bd9Sstevel@tonic-gate * Time sharing class initialization. Called by dispinit() at boot time. 3277c478bd9Sstevel@tonic-gate * We can ignore the clparmsz argument since we know that the smallest 3287c478bd9Sstevel@tonic-gate * possible parameter buffer is big enough for us. 3297c478bd9Sstevel@tonic-gate */ 3307c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3317c478bd9Sstevel@tonic-gate static pri_t 3327c478bd9Sstevel@tonic-gate ts_init(id_t cid, int clparmsz, classfuncs_t **clfuncspp) 3337c478bd9Sstevel@tonic-gate { 3347c478bd9Sstevel@tonic-gate int i; 3357c478bd9Sstevel@tonic-gate extern pri_t ts_getmaxumdpri(void); 3367c478bd9Sstevel@tonic-gate 3377c478bd9Sstevel@tonic-gate ts_dptbl = ts_getdptbl(); 3387c478bd9Sstevel@tonic-gate ts_kmdpris = ts_getkmdpris(); 3397c478bd9Sstevel@tonic-gate ts_maxumdpri = ts_getmaxumdpri(); 3407c478bd9Sstevel@tonic-gate ts_maxglobpri = MAX(ts_kmdpris[0], ts_dptbl[ts_maxumdpri].ts_globpri); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * Initialize the tsproc lists. 3447c478bd9Sstevel@tonic-gate */ 3457c478bd9Sstevel@tonic-gate for (i = 0; i < TS_LISTS; i++) { 3467c478bd9Sstevel@tonic-gate ts_plisthead[i].ts_next = ts_plisthead[i].ts_prev = 3477c478bd9Sstevel@tonic-gate &ts_plisthead[i]; 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate /* 3517c478bd9Sstevel@tonic-gate * We're required to return a pointer to our classfuncs 3527c478bd9Sstevel@tonic-gate * structure and the highest global priority value we use. 3537c478bd9Sstevel@tonic-gate */ 3547c478bd9Sstevel@tonic-gate *clfuncspp = &ts_classfuncs; 3557c478bd9Sstevel@tonic-gate return (ts_maxglobpri); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate /* 3607c478bd9Sstevel@tonic-gate * Interactive class scheduler initialization 3617c478bd9Sstevel@tonic-gate */ 3627c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3637c478bd9Sstevel@tonic-gate pri_t 3647c478bd9Sstevel@tonic-gate ia_init(id_t cid, int clparmsz, classfuncs_t **clfuncspp) 3657c478bd9Sstevel@tonic-gate { 3667c478bd9Sstevel@tonic-gate /* 3677c478bd9Sstevel@tonic-gate * We're required to return a pointer to our classfuncs 3687c478bd9Sstevel@tonic-gate * structure and the highest global priority value we use. 3697c478bd9Sstevel@tonic-gate */ 3707c478bd9Sstevel@tonic-gate ia_cid = cid; 3717c478bd9Sstevel@tonic-gate *clfuncspp = &ia_classfuncs; 3727c478bd9Sstevel@tonic-gate return (ts_maxglobpri); 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate /* 3777c478bd9Sstevel@tonic-gate * Get or reset the ts_dptbl values per the user's request. 3787c478bd9Sstevel@tonic-gate */ 3797c478bd9Sstevel@tonic-gate static int 3807c478bd9Sstevel@tonic-gate ts_admin(caddr_t uaddr, cred_t *reqpcredp) 3817c478bd9Sstevel@tonic-gate { 3827c478bd9Sstevel@tonic-gate tsadmin_t tsadmin; 3837c478bd9Sstevel@tonic-gate tsdpent_t *tmpdpp; 3847c478bd9Sstevel@tonic-gate int userdpsz; 3857c478bd9Sstevel@tonic-gate int i; 3867c478bd9Sstevel@tonic-gate size_t tsdpsz; 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 3897c478bd9Sstevel@tonic-gate if (copyin(uaddr, &tsadmin, sizeof (tsadmin_t))) 3907c478bd9Sstevel@tonic-gate return (EFAULT); 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 3937c478bd9Sstevel@tonic-gate else { 3947c478bd9Sstevel@tonic-gate /* get tsadmin struct from ILP32 caller */ 3957c478bd9Sstevel@tonic-gate tsadmin32_t tsadmin32; 3967c478bd9Sstevel@tonic-gate if (copyin(uaddr, &tsadmin32, sizeof (tsadmin32_t))) 3977c478bd9Sstevel@tonic-gate return (EFAULT); 3987c478bd9Sstevel@tonic-gate tsadmin.ts_dpents = 3997c478bd9Sstevel@tonic-gate (struct tsdpent *)(uintptr_t)tsadmin32.ts_dpents; 4007c478bd9Sstevel@tonic-gate tsadmin.ts_ndpents = tsadmin32.ts_ndpents; 4017c478bd9Sstevel@tonic-gate tsadmin.ts_cmd = tsadmin32.ts_cmd; 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate tsdpsz = (ts_maxumdpri + 1) * sizeof (tsdpent_t); 4067c478bd9Sstevel@tonic-gate 4077c478bd9Sstevel@tonic-gate switch (tsadmin.ts_cmd) { 4087c478bd9Sstevel@tonic-gate case TS_GETDPSIZE: 4097c478bd9Sstevel@tonic-gate tsadmin.ts_ndpents = ts_maxumdpri + 1; 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 4127c478bd9Sstevel@tonic-gate if (copyout(&tsadmin, uaddr, sizeof (tsadmin_t))) 4137c478bd9Sstevel@tonic-gate return (EFAULT); 4147c478bd9Sstevel@tonic-gate } 4157c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 4167c478bd9Sstevel@tonic-gate else { 4177c478bd9Sstevel@tonic-gate /* return tsadmin struct to ILP32 caller */ 4187c478bd9Sstevel@tonic-gate tsadmin32_t tsadmin32; 4197c478bd9Sstevel@tonic-gate tsadmin32.ts_dpents = 4207c478bd9Sstevel@tonic-gate (caddr32_t)(uintptr_t)tsadmin.ts_dpents; 4217c478bd9Sstevel@tonic-gate tsadmin32.ts_ndpents = tsadmin.ts_ndpents; 4227c478bd9Sstevel@tonic-gate tsadmin32.ts_cmd = tsadmin.ts_cmd; 4237c478bd9Sstevel@tonic-gate if (copyout(&tsadmin32, uaddr, sizeof (tsadmin32_t))) 4247c478bd9Sstevel@tonic-gate return (EFAULT); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 4277c478bd9Sstevel@tonic-gate break; 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate case TS_GETDPTBL: 4307c478bd9Sstevel@tonic-gate userdpsz = MIN(tsadmin.ts_ndpents * sizeof (tsdpent_t), 4317c478bd9Sstevel@tonic-gate tsdpsz); 4327c478bd9Sstevel@tonic-gate if (copyout(ts_dptbl, tsadmin.ts_dpents, userdpsz)) 4337c478bd9Sstevel@tonic-gate return (EFAULT); 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate tsadmin.ts_ndpents = userdpsz / sizeof (tsdpent_t); 4367c478bd9Sstevel@tonic-gate 4377c478bd9Sstevel@tonic-gate if (get_udatamodel() == DATAMODEL_NATIVE) { 4387c478bd9Sstevel@tonic-gate if (copyout(&tsadmin, uaddr, sizeof (tsadmin_t))) 4397c478bd9Sstevel@tonic-gate return (EFAULT); 4407c478bd9Sstevel@tonic-gate } 4417c478bd9Sstevel@tonic-gate #ifdef _SYSCALL32_IMPL 4427c478bd9Sstevel@tonic-gate else { 4437c478bd9Sstevel@tonic-gate /* return tsadmin struct to ILP32 callers */ 4447c478bd9Sstevel@tonic-gate tsadmin32_t tsadmin32; 4457c478bd9Sstevel@tonic-gate tsadmin32.ts_dpents = 4467c478bd9Sstevel@tonic-gate (caddr32_t)(uintptr_t)tsadmin.ts_dpents; 4477c478bd9Sstevel@tonic-gate tsadmin32.ts_ndpents = tsadmin.ts_ndpents; 4487c478bd9Sstevel@tonic-gate tsadmin32.ts_cmd = tsadmin.ts_cmd; 4497c478bd9Sstevel@tonic-gate if (copyout(&tsadmin32, uaddr, sizeof (tsadmin32_t))) 4507c478bd9Sstevel@tonic-gate return (EFAULT); 4517c478bd9Sstevel@tonic-gate } 4527c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32_IMPL */ 4537c478bd9Sstevel@tonic-gate break; 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate case TS_SETDPTBL: 4567c478bd9Sstevel@tonic-gate /* 4577c478bd9Sstevel@tonic-gate * We require that the requesting process has sufficient 4587c478bd9Sstevel@tonic-gate * priveleges. We also require that the table supplied by 4597c478bd9Sstevel@tonic-gate * the user exactly match the current ts_dptbl in size. 4607c478bd9Sstevel@tonic-gate */ 4617c478bd9Sstevel@tonic-gate if (secpolicy_dispadm(reqpcredp) != 0) 4627c478bd9Sstevel@tonic-gate return (EPERM); 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate if (tsadmin.ts_ndpents * sizeof (tsdpent_t) != tsdpsz) { 4657c478bd9Sstevel@tonic-gate return (EINVAL); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * We read the user supplied table into a temporary buffer 4707c478bd9Sstevel@tonic-gate * where it is validated before being copied over the 4717c478bd9Sstevel@tonic-gate * ts_dptbl. 4727c478bd9Sstevel@tonic-gate */ 4737c478bd9Sstevel@tonic-gate tmpdpp = kmem_alloc(tsdpsz, KM_SLEEP); 4747c478bd9Sstevel@tonic-gate if (copyin((caddr_t)tsadmin.ts_dpents, (caddr_t)tmpdpp, 4757c478bd9Sstevel@tonic-gate tsdpsz)) { 4767c478bd9Sstevel@tonic-gate kmem_free(tmpdpp, tsdpsz); 4777c478bd9Sstevel@tonic-gate return (EFAULT); 4787c478bd9Sstevel@tonic-gate } 4797c478bd9Sstevel@tonic-gate for (i = 0; i < tsadmin.ts_ndpents; i++) { 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * Validate the user supplied values. All we are doing 4837c478bd9Sstevel@tonic-gate * here is verifying that the values are within their 4847c478bd9Sstevel@tonic-gate * allowable ranges and will not panic the system. We 4857c478bd9Sstevel@tonic-gate * make no attempt to ensure that the resulting 4867c478bd9Sstevel@tonic-gate * configuration makes sense or results in reasonable 4877c478bd9Sstevel@tonic-gate * performance. 4887c478bd9Sstevel@tonic-gate */ 4897c478bd9Sstevel@tonic-gate if (tmpdpp[i].ts_quantum <= 0) { 4907c478bd9Sstevel@tonic-gate kmem_free(tmpdpp, tsdpsz); 4917c478bd9Sstevel@tonic-gate return (EINVAL); 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate if (tmpdpp[i].ts_tqexp > ts_maxumdpri || 4947c478bd9Sstevel@tonic-gate tmpdpp[i].ts_tqexp < 0) { 4957c478bd9Sstevel@tonic-gate kmem_free(tmpdpp, tsdpsz); 4967c478bd9Sstevel@tonic-gate return (EINVAL); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate if (tmpdpp[i].ts_slpret > ts_maxumdpri || 4997c478bd9Sstevel@tonic-gate tmpdpp[i].ts_slpret < 0) { 5007c478bd9Sstevel@tonic-gate kmem_free(tmpdpp, tsdpsz); 5017c478bd9Sstevel@tonic-gate return (EINVAL); 5027c478bd9Sstevel@tonic-gate } 5037c478bd9Sstevel@tonic-gate if (tmpdpp[i].ts_maxwait < 0) { 5047c478bd9Sstevel@tonic-gate kmem_free(tmpdpp, tsdpsz); 5057c478bd9Sstevel@tonic-gate return (EINVAL); 5067c478bd9Sstevel@tonic-gate } 5077c478bd9Sstevel@tonic-gate if (tmpdpp[i].ts_lwait > ts_maxumdpri || 5087c478bd9Sstevel@tonic-gate tmpdpp[i].ts_lwait < 0) { 5097c478bd9Sstevel@tonic-gate kmem_free(tmpdpp, tsdpsz); 5107c478bd9Sstevel@tonic-gate return (EINVAL); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate } 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate /* 5157c478bd9Sstevel@tonic-gate * Copy the user supplied values over the current ts_dptbl 5167c478bd9Sstevel@tonic-gate * values. The ts_globpri member is read-only so we don't 5177c478bd9Sstevel@tonic-gate * overwrite it. 5187c478bd9Sstevel@tonic-gate */ 5197c478bd9Sstevel@tonic-gate mutex_enter(&ts_dptblock); 5207c478bd9Sstevel@tonic-gate for (i = 0; i < tsadmin.ts_ndpents; i++) { 5217c478bd9Sstevel@tonic-gate ts_dptbl[i].ts_quantum = tmpdpp[i].ts_quantum; 5227c478bd9Sstevel@tonic-gate ts_dptbl[i].ts_tqexp = tmpdpp[i].ts_tqexp; 5237c478bd9Sstevel@tonic-gate ts_dptbl[i].ts_slpret = tmpdpp[i].ts_slpret; 5247c478bd9Sstevel@tonic-gate ts_dptbl[i].ts_maxwait = tmpdpp[i].ts_maxwait; 5257c478bd9Sstevel@tonic-gate ts_dptbl[i].ts_lwait = tmpdpp[i].ts_lwait; 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate mutex_exit(&ts_dptblock); 5287c478bd9Sstevel@tonic-gate kmem_free(tmpdpp, tsdpsz); 5297c478bd9Sstevel@tonic-gate break; 5307c478bd9Sstevel@tonic-gate 5317c478bd9Sstevel@tonic-gate default: 5327c478bd9Sstevel@tonic-gate return (EINVAL); 5337c478bd9Sstevel@tonic-gate } 5347c478bd9Sstevel@tonic-gate return (0); 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate 5387c478bd9Sstevel@tonic-gate /* 5397c478bd9Sstevel@tonic-gate * Allocate a time-sharing class specific thread structure and 5407c478bd9Sstevel@tonic-gate * initialize it with the parameters supplied. Also move the thread 5417c478bd9Sstevel@tonic-gate * to specified time-sharing priority. 5427c478bd9Sstevel@tonic-gate */ 5437c478bd9Sstevel@tonic-gate static int 5447c478bd9Sstevel@tonic-gate ts_enterclass(kthread_t *t, id_t cid, void *parmsp, 5457c478bd9Sstevel@tonic-gate cred_t *reqpcredp, void *bufp) 5467c478bd9Sstevel@tonic-gate { 5477c478bd9Sstevel@tonic-gate tsparms_t *tsparmsp = (tsparms_t *)parmsp; 5487c478bd9Sstevel@tonic-gate tsproc_t *tspp; 5497c478bd9Sstevel@tonic-gate pri_t reqtsuprilim; 5507c478bd9Sstevel@tonic-gate pri_t reqtsupri; 5517c478bd9Sstevel@tonic-gate static uint32_t tspexists = 0; /* set on first occurrence of */ 5527c478bd9Sstevel@tonic-gate /* a time-sharing process */ 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate tspp = (tsproc_t *)bufp; 5557c478bd9Sstevel@tonic-gate ASSERT(tspp != NULL); 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate /* 5587c478bd9Sstevel@tonic-gate * Initialize the tsproc structure. 5597c478bd9Sstevel@tonic-gate */ 5607c478bd9Sstevel@tonic-gate tspp->ts_cpupri = tsmedumdpri; 5617c478bd9Sstevel@tonic-gate if (cid == ia_cid) { 5627c478bd9Sstevel@tonic-gate /* 5637c478bd9Sstevel@tonic-gate * Check to make sure caller is either privileged or the 5647c478bd9Sstevel@tonic-gate * window system. When the window system is converted 5657c478bd9Sstevel@tonic-gate * to using privileges, the second check can go away. 5667c478bd9Sstevel@tonic-gate */ 5677c478bd9Sstevel@tonic-gate if (reqpcredp != NULL && !groupmember(IA_gid, reqpcredp) && 5687c478bd9Sstevel@tonic-gate secpolicy_setpriority(reqpcredp) != 0) 5697c478bd9Sstevel@tonic-gate return (EPERM); 5707c478bd9Sstevel@tonic-gate /* 5717c478bd9Sstevel@tonic-gate * Belongs to IA "class", so set appropriate flags. 5727c478bd9Sstevel@tonic-gate * Mark as 'on' so it will not be a swap victim 5737c478bd9Sstevel@tonic-gate * while forking. 5747c478bd9Sstevel@tonic-gate */ 5757c478bd9Sstevel@tonic-gate tspp->ts_flags = TSIA | TSIASET; 5767c478bd9Sstevel@tonic-gate tspp->ts_boost = ia_boost; 5777c478bd9Sstevel@tonic-gate } else { 5787c478bd9Sstevel@tonic-gate tspp->ts_flags = 0; 5797c478bd9Sstevel@tonic-gate tspp->ts_boost = 0; 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate if (tsparmsp == NULL) { 5837c478bd9Sstevel@tonic-gate /* 5847c478bd9Sstevel@tonic-gate * Use default values. 5857c478bd9Sstevel@tonic-gate */ 5867c478bd9Sstevel@tonic-gate tspp->ts_uprilim = tspp->ts_upri = 0; 5877c478bd9Sstevel@tonic-gate tspp->ts_nice = NZERO; 5887c478bd9Sstevel@tonic-gate } else { 5897c478bd9Sstevel@tonic-gate /* 5907c478bd9Sstevel@tonic-gate * Use supplied values. 5917c478bd9Sstevel@tonic-gate */ 5927c478bd9Sstevel@tonic-gate if (tsparmsp->ts_uprilim == TS_NOCHANGE) 5937c478bd9Sstevel@tonic-gate reqtsuprilim = 0; 5947c478bd9Sstevel@tonic-gate else { 5957c478bd9Sstevel@tonic-gate if (tsparmsp->ts_uprilim > 0 && 5967c478bd9Sstevel@tonic-gate secpolicy_setpriority(reqpcredp) != 0) 5977c478bd9Sstevel@tonic-gate return (EPERM); 5987c478bd9Sstevel@tonic-gate reqtsuprilim = tsparmsp->ts_uprilim; 5997c478bd9Sstevel@tonic-gate } 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate if (tsparmsp->ts_upri == TS_NOCHANGE) { 6027c478bd9Sstevel@tonic-gate reqtsupri = reqtsuprilim; 6037c478bd9Sstevel@tonic-gate } else { 6047c478bd9Sstevel@tonic-gate if (tsparmsp->ts_upri > 0 && 6057c478bd9Sstevel@tonic-gate secpolicy_setpriority(reqpcredp) != 0) 6067c478bd9Sstevel@tonic-gate return (EPERM); 6077c478bd9Sstevel@tonic-gate /* 6087c478bd9Sstevel@tonic-gate * Set the user priority to the requested value 6097c478bd9Sstevel@tonic-gate * or the upri limit, whichever is lower. 6107c478bd9Sstevel@tonic-gate */ 6117c478bd9Sstevel@tonic-gate reqtsupri = tsparmsp->ts_upri; 6127c478bd9Sstevel@tonic-gate if (reqtsupri > reqtsuprilim) 6137c478bd9Sstevel@tonic-gate reqtsupri = reqtsuprilim; 6147c478bd9Sstevel@tonic-gate } 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate tspp->ts_uprilim = reqtsuprilim; 6187c478bd9Sstevel@tonic-gate tspp->ts_upri = reqtsupri; 619d4204c85Sraf tspp->ts_nice = NZERO - (NZERO * reqtsupri) / ts_maxupri; 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(tspp); 6227c478bd9Sstevel@tonic-gate 6237c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 6247c478bd9Sstevel@tonic-gate tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum; 6257c478bd9Sstevel@tonic-gate tspp->ts_tp = t; 626c97ad5cdSakolb cpucaps_sc_init(&tspp->ts_caps); 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate /* 6297c478bd9Sstevel@tonic-gate * Reset priority. Process goes to a "user mode" priority 6307c478bd9Sstevel@tonic-gate * here regardless of whether or not it has slept since 6317c478bd9Sstevel@tonic-gate * entering the kernel. 6327c478bd9Sstevel@tonic-gate */ 6337c478bd9Sstevel@tonic-gate thread_lock(t); /* get dispatcher lock on thread */ 6347c478bd9Sstevel@tonic-gate t->t_clfuncs = &(sclass[cid].cl_funcs->thread); 6357c478bd9Sstevel@tonic-gate t->t_cid = cid; 6367c478bd9Sstevel@tonic-gate t->t_cldata = (void *)tspp; 6377c478bd9Sstevel@tonic-gate t->t_schedflag &= ~TS_RUNQMATCH; 6387c478bd9Sstevel@tonic-gate ts_change_priority(t, tspp); 6397c478bd9Sstevel@tonic-gate thread_unlock(t); 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate /* 6427c478bd9Sstevel@tonic-gate * Link new structure into tsproc list. 6437c478bd9Sstevel@tonic-gate */ 6447c478bd9Sstevel@tonic-gate TS_LIST_INSERT(tspp); 6457c478bd9Sstevel@tonic-gate 6467c478bd9Sstevel@tonic-gate /* 6477c478bd9Sstevel@tonic-gate * If this is the first time-sharing thread to occur since 6487c478bd9Sstevel@tonic-gate * boot we set up the initial call to ts_update() here. 6497c478bd9Sstevel@tonic-gate * Use an atomic compare-and-swap since that's easier and 6507c478bd9Sstevel@tonic-gate * faster than a mutex (but check with an ordinary load first 6517c478bd9Sstevel@tonic-gate * since most of the time this will already be done). 6527c478bd9Sstevel@tonic-gate */ 6537c478bd9Sstevel@tonic-gate if (tspexists == 0 && cas32(&tspexists, 0, 1) == 0) 6547c478bd9Sstevel@tonic-gate (void) timeout(ts_update, NULL, hz); 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate return (0); 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate 6607c478bd9Sstevel@tonic-gate /* 6617c478bd9Sstevel@tonic-gate * Free tsproc structure of thread. 6627c478bd9Sstevel@tonic-gate */ 6637c478bd9Sstevel@tonic-gate static void 6647c478bd9Sstevel@tonic-gate ts_exitclass(void *procp) 6657c478bd9Sstevel@tonic-gate { 6667c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)procp; 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate /* Remove tsproc_t structure from list */ 6697c478bd9Sstevel@tonic-gate TS_LIST_DELETE(tspp); 6707c478bd9Sstevel@tonic-gate kmem_free(tspp, sizeof (tsproc_t)); 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate /* ARGSUSED */ 6747c478bd9Sstevel@tonic-gate static int 6757c478bd9Sstevel@tonic-gate ts_canexit(kthread_t *t, cred_t *cred) 6767c478bd9Sstevel@tonic-gate { 6777c478bd9Sstevel@tonic-gate /* 6787c478bd9Sstevel@tonic-gate * A thread can always leave a TS/IA class 6797c478bd9Sstevel@tonic-gate */ 6807c478bd9Sstevel@tonic-gate return (0); 6817c478bd9Sstevel@tonic-gate } 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate static int 6847c478bd9Sstevel@tonic-gate ts_fork(kthread_t *t, kthread_t *ct, void *bufp) 6857c478bd9Sstevel@tonic-gate { 6867c478bd9Sstevel@tonic-gate tsproc_t *ptspp; /* ptr to parent's tsproc structure */ 6877c478bd9Sstevel@tonic-gate tsproc_t *ctspp; /* ptr to child's tsproc structure */ 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock)); 6907c478bd9Sstevel@tonic-gate 6917c478bd9Sstevel@tonic-gate ctspp = (tsproc_t *)bufp; 6927c478bd9Sstevel@tonic-gate ASSERT(ctspp != NULL); 6937c478bd9Sstevel@tonic-gate ptspp = (tsproc_t *)t->t_cldata; 6947c478bd9Sstevel@tonic-gate /* 6957c478bd9Sstevel@tonic-gate * Initialize child's tsproc structure. 6967c478bd9Sstevel@tonic-gate */ 6977c478bd9Sstevel@tonic-gate thread_lock(t); 6987c478bd9Sstevel@tonic-gate ctspp->ts_timeleft = ts_dptbl[ptspp->ts_cpupri].ts_quantum; 6997c478bd9Sstevel@tonic-gate ctspp->ts_cpupri = ptspp->ts_cpupri; 7007c478bd9Sstevel@tonic-gate ctspp->ts_boost = ptspp->ts_boost; 7017c478bd9Sstevel@tonic-gate ctspp->ts_uprilim = ptspp->ts_uprilim; 7027c478bd9Sstevel@tonic-gate ctspp->ts_upri = ptspp->ts_upri; 7037c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(ctspp); 7047c478bd9Sstevel@tonic-gate ctspp->ts_nice = ptspp->ts_nice; 7057c478bd9Sstevel@tonic-gate ctspp->ts_dispwait = 0; 7069ac8606fSraf ctspp->ts_flags = ptspp->ts_flags & ~(TSKPRI | TSBACKQ | TSRESTORE); 7077c478bd9Sstevel@tonic-gate ctspp->ts_tp = ct; 708c97ad5cdSakolb cpucaps_sc_init(&ctspp->ts_caps); 7097c478bd9Sstevel@tonic-gate thread_unlock(t); 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate /* 7127c478bd9Sstevel@tonic-gate * Link new structure into tsproc list. 7137c478bd9Sstevel@tonic-gate */ 7147c478bd9Sstevel@tonic-gate ct->t_cldata = (void *)ctspp; 7157c478bd9Sstevel@tonic-gate TS_LIST_INSERT(ctspp); 7167c478bd9Sstevel@tonic-gate return (0); 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate 7207c478bd9Sstevel@tonic-gate /* 7217c478bd9Sstevel@tonic-gate * Child is placed at back of dispatcher queue and parent gives 7227c478bd9Sstevel@tonic-gate * up processor so that the child runs first after the fork. 7237c478bd9Sstevel@tonic-gate * This allows the child immediately execing to break the multiple 7247c478bd9Sstevel@tonic-gate * use of copy on write pages with no disk home. The parent will 7257c478bd9Sstevel@tonic-gate * get to steal them back rather than uselessly copying them. 7267c478bd9Sstevel@tonic-gate */ 7277c478bd9Sstevel@tonic-gate static void 7287c478bd9Sstevel@tonic-gate ts_forkret(kthread_t *t, kthread_t *ct) 7297c478bd9Sstevel@tonic-gate { 7307c478bd9Sstevel@tonic-gate proc_t *pp = ttoproc(t); 7317c478bd9Sstevel@tonic-gate proc_t *cp = ttoproc(ct); 7327c478bd9Sstevel@tonic-gate tsproc_t *tspp; 7337c478bd9Sstevel@tonic-gate 7347c478bd9Sstevel@tonic-gate ASSERT(t == curthread); 7357c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 7367c478bd9Sstevel@tonic-gate 7377c478bd9Sstevel@tonic-gate /* 7387c478bd9Sstevel@tonic-gate * Grab the child's p_lock before dropping pidlock to ensure 7397c478bd9Sstevel@tonic-gate * the process does not disappear before we set it running. 7407c478bd9Sstevel@tonic-gate */ 7417c478bd9Sstevel@tonic-gate mutex_enter(&cp->p_lock); 7427c478bd9Sstevel@tonic-gate continuelwps(cp); 7437c478bd9Sstevel@tonic-gate mutex_exit(&cp->p_lock); 7447c478bd9Sstevel@tonic-gate 7457c478bd9Sstevel@tonic-gate mutex_enter(&pp->p_lock); 746d5493db7SPramod Batni mutex_exit(&pidlock); 7477c478bd9Sstevel@tonic-gate continuelwps(pp); 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate thread_lock(t); 7507c478bd9Sstevel@tonic-gate tspp = (tsproc_t *)(t->t_cldata); 7517c478bd9Sstevel@tonic-gate tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_tqexp; 7527c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(tspp); 7537c478bd9Sstevel@tonic-gate tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum; 7547c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 7557c478bd9Sstevel@tonic-gate t->t_pri = ts_dptbl[tspp->ts_umdpri].ts_globpri; 7567c478bd9Sstevel@tonic-gate ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri); 7577c478bd9Sstevel@tonic-gate tspp->ts_flags &= ~TSKPRI; 7587c478bd9Sstevel@tonic-gate THREAD_TRANSITION(t); 7597c478bd9Sstevel@tonic-gate ts_setrun(t); 7607c478bd9Sstevel@tonic-gate thread_unlock(t); 761d5493db7SPramod Batni /* 762d5493db7SPramod Batni * Safe to drop p_lock now since since it is safe to change 763d5493db7SPramod Batni * the scheduling class after this point. 764d5493db7SPramod Batni */ 765d5493db7SPramod Batni mutex_exit(&pp->p_lock); 7667c478bd9Sstevel@tonic-gate 7677c478bd9Sstevel@tonic-gate swtch(); 7687c478bd9Sstevel@tonic-gate } 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* 7727c478bd9Sstevel@tonic-gate * Get information about the time-sharing class into the buffer 7737c478bd9Sstevel@tonic-gate * pointed to by tsinfop. The maximum configured user priority 7747c478bd9Sstevel@tonic-gate * is the only information we supply. ts_getclinfo() is called 7757c478bd9Sstevel@tonic-gate * for TS threads, and ia_getclinfo() is called for IA threads. 7767c478bd9Sstevel@tonic-gate */ 7777c478bd9Sstevel@tonic-gate static int 7787c478bd9Sstevel@tonic-gate ts_getclinfo(void *infop) 7797c478bd9Sstevel@tonic-gate { 7807c478bd9Sstevel@tonic-gate tsinfo_t *tsinfop = (tsinfo_t *)infop; 7817c478bd9Sstevel@tonic-gate tsinfop->ts_maxupri = ts_maxupri; 7827c478bd9Sstevel@tonic-gate return (0); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate static int 7867c478bd9Sstevel@tonic-gate ia_getclinfo(void *infop) 7877c478bd9Sstevel@tonic-gate { 7887c478bd9Sstevel@tonic-gate iainfo_t *iainfop = (iainfo_t *)infop; 7897c478bd9Sstevel@tonic-gate iainfop->ia_maxupri = ia_maxupri; 7907c478bd9Sstevel@tonic-gate return (0); 7917c478bd9Sstevel@tonic-gate } 7927c478bd9Sstevel@tonic-gate 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate /* 795d4204c85Sraf * Return the user mode scheduling priority range. 7967c478bd9Sstevel@tonic-gate */ 7977c478bd9Sstevel@tonic-gate static int 7987c478bd9Sstevel@tonic-gate ts_getclpri(pcpri_t *pcprip) 7997c478bd9Sstevel@tonic-gate { 800d4204c85Sraf pcprip->pc_clpmax = ts_maxupri; 801d4204c85Sraf pcprip->pc_clpmin = -ts_maxupri; 802d4204c85Sraf return (0); 803d4204c85Sraf } 804d4204c85Sraf 805d4204c85Sraf 806d4204c85Sraf static int 807d4204c85Sraf ia_getclpri(pcpri_t *pcprip) 808d4204c85Sraf { 809d4204c85Sraf pcprip->pc_clpmax = ia_maxupri; 810d4204c85Sraf pcprip->pc_clpmin = -ia_maxupri; 8117c478bd9Sstevel@tonic-gate return (0); 8127c478bd9Sstevel@tonic-gate } 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate static void 8167c478bd9Sstevel@tonic-gate ts_nullsys() 8177c478bd9Sstevel@tonic-gate {} 8187c478bd9Sstevel@tonic-gate 8197c478bd9Sstevel@tonic-gate 8207c478bd9Sstevel@tonic-gate /* 8217c478bd9Sstevel@tonic-gate * Get the time-sharing parameters of the thread pointed to by 8227c478bd9Sstevel@tonic-gate * tsprocp into the buffer pointed to by tsparmsp. ts_parmsget() 8237c478bd9Sstevel@tonic-gate * is called for TS threads, and ia_parmsget() is called for IA 8247c478bd9Sstevel@tonic-gate * threads. 8257c478bd9Sstevel@tonic-gate */ 8267c478bd9Sstevel@tonic-gate static void 8277c478bd9Sstevel@tonic-gate ts_parmsget(kthread_t *t, void *parmsp) 8287c478bd9Sstevel@tonic-gate { 8297c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)t->t_cldata; 8307c478bd9Sstevel@tonic-gate tsparms_t *tsparmsp = (tsparms_t *)parmsp; 8317c478bd9Sstevel@tonic-gate 8327c478bd9Sstevel@tonic-gate tsparmsp->ts_uprilim = tspp->ts_uprilim; 8337c478bd9Sstevel@tonic-gate tsparmsp->ts_upri = tspp->ts_upri; 8347c478bd9Sstevel@tonic-gate } 8357c478bd9Sstevel@tonic-gate 8367c478bd9Sstevel@tonic-gate static void 8377c478bd9Sstevel@tonic-gate ia_parmsget(kthread_t *t, void *parmsp) 8387c478bd9Sstevel@tonic-gate { 8397c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)t->t_cldata; 8407c478bd9Sstevel@tonic-gate iaparms_t *iaparmsp = (iaparms_t *)parmsp; 8417c478bd9Sstevel@tonic-gate 8427c478bd9Sstevel@tonic-gate iaparmsp->ia_uprilim = tspp->ts_uprilim; 8437c478bd9Sstevel@tonic-gate iaparmsp->ia_upri = tspp->ts_upri; 8447c478bd9Sstevel@tonic-gate if (tspp->ts_flags & TSIASET) 8457c478bd9Sstevel@tonic-gate iaparmsp->ia_mode = IA_SET_INTERACTIVE; 8467c478bd9Sstevel@tonic-gate else 8477c478bd9Sstevel@tonic-gate iaparmsp->ia_mode = IA_INTERACTIVE_OFF; 8487c478bd9Sstevel@tonic-gate } 8497c478bd9Sstevel@tonic-gate 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate /* 8527c478bd9Sstevel@tonic-gate * Check the validity of the time-sharing parameters in the buffer 8537c478bd9Sstevel@tonic-gate * pointed to by tsparmsp. 8547c478bd9Sstevel@tonic-gate * ts_parmsin() is called for TS threads, and ia_parmsin() is called 8557c478bd9Sstevel@tonic-gate * for IA threads. 8567c478bd9Sstevel@tonic-gate */ 8577c478bd9Sstevel@tonic-gate static int 8587c478bd9Sstevel@tonic-gate ts_parmsin(void *parmsp) 8597c478bd9Sstevel@tonic-gate { 8607c478bd9Sstevel@tonic-gate tsparms_t *tsparmsp = (tsparms_t *)parmsp; 8617c478bd9Sstevel@tonic-gate /* 8627c478bd9Sstevel@tonic-gate * Check validity of parameters. 8637c478bd9Sstevel@tonic-gate */ 8647c478bd9Sstevel@tonic-gate if ((tsparmsp->ts_uprilim > ts_maxupri || 8657c478bd9Sstevel@tonic-gate tsparmsp->ts_uprilim < -ts_maxupri) && 8667c478bd9Sstevel@tonic-gate tsparmsp->ts_uprilim != TS_NOCHANGE) 8677c478bd9Sstevel@tonic-gate return (EINVAL); 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate if ((tsparmsp->ts_upri > ts_maxupri || 8707c478bd9Sstevel@tonic-gate tsparmsp->ts_upri < -ts_maxupri) && 8717c478bd9Sstevel@tonic-gate tsparmsp->ts_upri != TS_NOCHANGE) 8727c478bd9Sstevel@tonic-gate return (EINVAL); 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate return (0); 8757c478bd9Sstevel@tonic-gate } 8767c478bd9Sstevel@tonic-gate 8777c478bd9Sstevel@tonic-gate static int 8787c478bd9Sstevel@tonic-gate ia_parmsin(void *parmsp) 8797c478bd9Sstevel@tonic-gate { 8807c478bd9Sstevel@tonic-gate iaparms_t *iaparmsp = (iaparms_t *)parmsp; 8817c478bd9Sstevel@tonic-gate 8827c478bd9Sstevel@tonic-gate if ((iaparmsp->ia_uprilim > ia_maxupri || 8837c478bd9Sstevel@tonic-gate iaparmsp->ia_uprilim < -ia_maxupri) && 8847c478bd9Sstevel@tonic-gate iaparmsp->ia_uprilim != IA_NOCHANGE) { 8857c478bd9Sstevel@tonic-gate return (EINVAL); 8867c478bd9Sstevel@tonic-gate } 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate if ((iaparmsp->ia_upri > ia_maxupri || 8897c478bd9Sstevel@tonic-gate iaparmsp->ia_upri < -ia_maxupri) && 8907c478bd9Sstevel@tonic-gate iaparmsp->ia_upri != IA_NOCHANGE) { 8917c478bd9Sstevel@tonic-gate return (EINVAL); 8927c478bd9Sstevel@tonic-gate } 8937c478bd9Sstevel@tonic-gate 8947c478bd9Sstevel@tonic-gate return (0); 8957c478bd9Sstevel@tonic-gate } 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate 8987c478bd9Sstevel@tonic-gate /* 8997c478bd9Sstevel@tonic-gate * Check the validity of the time-sharing parameters in the pc_vaparms_t 9007c478bd9Sstevel@tonic-gate * structure vaparmsp and put them in the buffer pointed to by tsparmsp. 9017c478bd9Sstevel@tonic-gate * pc_vaparms_t contains (key, value) pairs of parameter. 9027c478bd9Sstevel@tonic-gate * ts_vaparmsin() is called for TS threads, and ia_vaparmsin() is called 9037c478bd9Sstevel@tonic-gate * for IA threads. ts_vaparmsin() is the variable parameter version of 9047c478bd9Sstevel@tonic-gate * ts_parmsin() and ia_vaparmsin() is the variable parameter version of 9057c478bd9Sstevel@tonic-gate * ia_parmsin(). 9067c478bd9Sstevel@tonic-gate */ 9077c478bd9Sstevel@tonic-gate static int 9087c478bd9Sstevel@tonic-gate ts_vaparmsin(void *parmsp, pc_vaparms_t *vaparmsp) 9097c478bd9Sstevel@tonic-gate { 9107c478bd9Sstevel@tonic-gate tsparms_t *tsparmsp = (tsparms_t *)parmsp; 9117c478bd9Sstevel@tonic-gate int priflag = 0; 9127c478bd9Sstevel@tonic-gate int limflag = 0; 9137c478bd9Sstevel@tonic-gate uint_t cnt; 9147c478bd9Sstevel@tonic-gate pc_vaparm_t *vpp = &vaparmsp->pc_parms[0]; 9157c478bd9Sstevel@tonic-gate 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate /* 9187c478bd9Sstevel@tonic-gate * TS_NOCHANGE (-32768) is outside of the range of values for 9197c478bd9Sstevel@tonic-gate * ts_uprilim and ts_upri. If the structure tsparms_t is changed, 9207c478bd9Sstevel@tonic-gate * TS_NOCHANGE should be replaced by a flag word (in the same manner 9217c478bd9Sstevel@tonic-gate * as in rt.c). 9227c478bd9Sstevel@tonic-gate */ 9237c478bd9Sstevel@tonic-gate tsparmsp->ts_uprilim = TS_NOCHANGE; 9247c478bd9Sstevel@tonic-gate tsparmsp->ts_upri = TS_NOCHANGE; 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate /* 9277c478bd9Sstevel@tonic-gate * Get the varargs parameter and check validity of parameters. 9287c478bd9Sstevel@tonic-gate */ 9297c478bd9Sstevel@tonic-gate if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT) 9307c478bd9Sstevel@tonic-gate return (EINVAL); 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) { 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate switch (vpp->pc_key) { 9357c478bd9Sstevel@tonic-gate case TS_KY_UPRILIM: 9367c478bd9Sstevel@tonic-gate if (limflag++) 9377c478bd9Sstevel@tonic-gate return (EINVAL); 9387c478bd9Sstevel@tonic-gate tsparmsp->ts_uprilim = (pri_t)vpp->pc_parm; 9397c478bd9Sstevel@tonic-gate if (tsparmsp->ts_uprilim > ts_maxupri || 9407c478bd9Sstevel@tonic-gate tsparmsp->ts_uprilim < -ts_maxupri) 9417c478bd9Sstevel@tonic-gate return (EINVAL); 9427c478bd9Sstevel@tonic-gate break; 9437c478bd9Sstevel@tonic-gate 9447c478bd9Sstevel@tonic-gate case TS_KY_UPRI: 9457c478bd9Sstevel@tonic-gate if (priflag++) 9467c478bd9Sstevel@tonic-gate return (EINVAL); 9477c478bd9Sstevel@tonic-gate tsparmsp->ts_upri = (pri_t)vpp->pc_parm; 9487c478bd9Sstevel@tonic-gate if (tsparmsp->ts_upri > ts_maxupri || 9497c478bd9Sstevel@tonic-gate tsparmsp->ts_upri < -ts_maxupri) 9507c478bd9Sstevel@tonic-gate return (EINVAL); 9517c478bd9Sstevel@tonic-gate break; 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate default: 9547c478bd9Sstevel@tonic-gate return (EINVAL); 9557c478bd9Sstevel@tonic-gate } 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate if (vaparmsp->pc_vaparmscnt == 0) { 9597c478bd9Sstevel@tonic-gate /* 9607c478bd9Sstevel@tonic-gate * Use default parameters. 9617c478bd9Sstevel@tonic-gate */ 9627c478bd9Sstevel@tonic-gate tsparmsp->ts_upri = tsparmsp->ts_uprilim = 0; 9637c478bd9Sstevel@tonic-gate } 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate return (0); 9667c478bd9Sstevel@tonic-gate } 9677c478bd9Sstevel@tonic-gate 9687c478bd9Sstevel@tonic-gate static int 9697c478bd9Sstevel@tonic-gate ia_vaparmsin(void *parmsp, pc_vaparms_t *vaparmsp) 9707c478bd9Sstevel@tonic-gate { 9717c478bd9Sstevel@tonic-gate iaparms_t *iaparmsp = (iaparms_t *)parmsp; 9727c478bd9Sstevel@tonic-gate int priflag = 0; 9737c478bd9Sstevel@tonic-gate int limflag = 0; 9747c478bd9Sstevel@tonic-gate int mflag = 0; 9757c478bd9Sstevel@tonic-gate uint_t cnt; 9767c478bd9Sstevel@tonic-gate pc_vaparm_t *vpp = &vaparmsp->pc_parms[0]; 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate /* 9797c478bd9Sstevel@tonic-gate * IA_NOCHANGE (-32768) is outside of the range of values for 9807c478bd9Sstevel@tonic-gate * ia_uprilim, ia_upri and ia_mode. If the structure iaparms_t is 9817c478bd9Sstevel@tonic-gate * changed, IA_NOCHANGE should be replaced by a flag word (in the 9827c478bd9Sstevel@tonic-gate * same manner as in rt.c). 9837c478bd9Sstevel@tonic-gate */ 9847c478bd9Sstevel@tonic-gate iaparmsp->ia_uprilim = IA_NOCHANGE; 9857c478bd9Sstevel@tonic-gate iaparmsp->ia_upri = IA_NOCHANGE; 9867c478bd9Sstevel@tonic-gate iaparmsp->ia_mode = IA_NOCHANGE; 9877c478bd9Sstevel@tonic-gate 9887c478bd9Sstevel@tonic-gate /* 9897c478bd9Sstevel@tonic-gate * Get the varargs parameter and check validity of parameters. 9907c478bd9Sstevel@tonic-gate */ 9917c478bd9Sstevel@tonic-gate if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT) 9927c478bd9Sstevel@tonic-gate return (EINVAL); 9937c478bd9Sstevel@tonic-gate 9947c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) { 9957c478bd9Sstevel@tonic-gate 9967c478bd9Sstevel@tonic-gate switch (vpp->pc_key) { 9977c478bd9Sstevel@tonic-gate case IA_KY_UPRILIM: 9987c478bd9Sstevel@tonic-gate if (limflag++) 9997c478bd9Sstevel@tonic-gate return (EINVAL); 10007c478bd9Sstevel@tonic-gate iaparmsp->ia_uprilim = (pri_t)vpp->pc_parm; 10017c478bd9Sstevel@tonic-gate if (iaparmsp->ia_uprilim > ia_maxupri || 10027c478bd9Sstevel@tonic-gate iaparmsp->ia_uprilim < -ia_maxupri) 10037c478bd9Sstevel@tonic-gate return (EINVAL); 10047c478bd9Sstevel@tonic-gate break; 10057c478bd9Sstevel@tonic-gate 10067c478bd9Sstevel@tonic-gate case IA_KY_UPRI: 10077c478bd9Sstevel@tonic-gate if (priflag++) 10087c478bd9Sstevel@tonic-gate return (EINVAL); 10097c478bd9Sstevel@tonic-gate iaparmsp->ia_upri = (pri_t)vpp->pc_parm; 10107c478bd9Sstevel@tonic-gate if (iaparmsp->ia_upri > ia_maxupri || 10117c478bd9Sstevel@tonic-gate iaparmsp->ia_upri < -ia_maxupri) 10127c478bd9Sstevel@tonic-gate return (EINVAL); 10137c478bd9Sstevel@tonic-gate break; 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate case IA_KY_MODE: 10167c478bd9Sstevel@tonic-gate if (mflag++) 10177c478bd9Sstevel@tonic-gate return (EINVAL); 10187c478bd9Sstevel@tonic-gate iaparmsp->ia_mode = (int)vpp->pc_parm; 10197c478bd9Sstevel@tonic-gate if (iaparmsp->ia_mode != IA_SET_INTERACTIVE && 10207c478bd9Sstevel@tonic-gate iaparmsp->ia_mode != IA_INTERACTIVE_OFF) 10217c478bd9Sstevel@tonic-gate return (EINVAL); 10227c478bd9Sstevel@tonic-gate break; 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate default: 10257c478bd9Sstevel@tonic-gate return (EINVAL); 10267c478bd9Sstevel@tonic-gate } 10277c478bd9Sstevel@tonic-gate } 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate if (vaparmsp->pc_vaparmscnt == 0) { 10307c478bd9Sstevel@tonic-gate /* 10317c478bd9Sstevel@tonic-gate * Use default parameters. 10327c478bd9Sstevel@tonic-gate */ 10337c478bd9Sstevel@tonic-gate iaparmsp->ia_upri = iaparmsp->ia_uprilim = 0; 10347c478bd9Sstevel@tonic-gate iaparmsp->ia_mode = IA_SET_INTERACTIVE; 10357c478bd9Sstevel@tonic-gate } 10367c478bd9Sstevel@tonic-gate 10377c478bd9Sstevel@tonic-gate return (0); 10387c478bd9Sstevel@tonic-gate } 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate /* 10417c478bd9Sstevel@tonic-gate * Nothing to do here but return success. 10427c478bd9Sstevel@tonic-gate */ 10437c478bd9Sstevel@tonic-gate /* ARGSUSED */ 10447c478bd9Sstevel@tonic-gate static int 10457c478bd9Sstevel@tonic-gate ts_parmsout(void *parmsp, pc_vaparms_t *vaparmsp) 10467c478bd9Sstevel@tonic-gate { 10477c478bd9Sstevel@tonic-gate return (0); 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate 10517c478bd9Sstevel@tonic-gate /* 10527c478bd9Sstevel@tonic-gate * Copy all selected time-sharing class parameters to the user. 10537c478bd9Sstevel@tonic-gate * The parameters are specified by a key. 10547c478bd9Sstevel@tonic-gate */ 10557c478bd9Sstevel@tonic-gate static int 10567c478bd9Sstevel@tonic-gate ts_vaparmsout(void *prmsp, pc_vaparms_t *vaparmsp) 10577c478bd9Sstevel@tonic-gate { 10587c478bd9Sstevel@tonic-gate tsparms_t *tsprmsp = (tsparms_t *)prmsp; 10597c478bd9Sstevel@tonic-gate int priflag = 0; 10607c478bd9Sstevel@tonic-gate int limflag = 0; 10617c478bd9Sstevel@tonic-gate uint_t cnt; 10627c478bd9Sstevel@tonic-gate pc_vaparm_t *vpp = &vaparmsp->pc_parms[0]; 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&curproc->p_lock)); 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT) 10677c478bd9Sstevel@tonic-gate return (EINVAL); 10687c478bd9Sstevel@tonic-gate 10697c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) { 10707c478bd9Sstevel@tonic-gate 10717c478bd9Sstevel@tonic-gate switch (vpp->pc_key) { 10727c478bd9Sstevel@tonic-gate case TS_KY_UPRILIM: 10737c478bd9Sstevel@tonic-gate if (limflag++) 10747c478bd9Sstevel@tonic-gate return (EINVAL); 10757c478bd9Sstevel@tonic-gate if (copyout(&tsprmsp->ts_uprilim, 10767c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)vpp->pc_parm, sizeof (pri_t))) 10777c478bd9Sstevel@tonic-gate return (EFAULT); 10787c478bd9Sstevel@tonic-gate break; 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate case TS_KY_UPRI: 10817c478bd9Sstevel@tonic-gate if (priflag++) 10827c478bd9Sstevel@tonic-gate return (EINVAL); 10837c478bd9Sstevel@tonic-gate if (copyout(&tsprmsp->ts_upri, 10847c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)vpp->pc_parm, sizeof (pri_t))) 10857c478bd9Sstevel@tonic-gate return (EFAULT); 10867c478bd9Sstevel@tonic-gate break; 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate default: 10897c478bd9Sstevel@tonic-gate return (EINVAL); 10907c478bd9Sstevel@tonic-gate } 10917c478bd9Sstevel@tonic-gate } 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate return (0); 10947c478bd9Sstevel@tonic-gate } 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate 10977c478bd9Sstevel@tonic-gate /* 10987c478bd9Sstevel@tonic-gate * Copy all selected interactive class parameters to the user. 10997c478bd9Sstevel@tonic-gate * The parameters are specified by a key. 11007c478bd9Sstevel@tonic-gate */ 11017c478bd9Sstevel@tonic-gate static int 11027c478bd9Sstevel@tonic-gate ia_vaparmsout(void *prmsp, pc_vaparms_t *vaparmsp) 11037c478bd9Sstevel@tonic-gate { 11047c478bd9Sstevel@tonic-gate iaparms_t *iaprmsp = (iaparms_t *)prmsp; 11057c478bd9Sstevel@tonic-gate int priflag = 0; 11067c478bd9Sstevel@tonic-gate int limflag = 0; 11077c478bd9Sstevel@tonic-gate int mflag = 0; 11087c478bd9Sstevel@tonic-gate uint_t cnt; 11097c478bd9Sstevel@tonic-gate pc_vaparm_t *vpp = &vaparmsp->pc_parms[0]; 11107c478bd9Sstevel@tonic-gate 11117c478bd9Sstevel@tonic-gate ASSERT(MUTEX_NOT_HELD(&curproc->p_lock)); 11127c478bd9Sstevel@tonic-gate 11137c478bd9Sstevel@tonic-gate if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT) 11147c478bd9Sstevel@tonic-gate return (EINVAL); 11157c478bd9Sstevel@tonic-gate 11167c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) { 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate switch (vpp->pc_key) { 11197c478bd9Sstevel@tonic-gate case IA_KY_UPRILIM: 11207c478bd9Sstevel@tonic-gate if (limflag++) 11217c478bd9Sstevel@tonic-gate return (EINVAL); 11227c478bd9Sstevel@tonic-gate if (copyout(&iaprmsp->ia_uprilim, 11237c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)vpp->pc_parm, sizeof (pri_t))) 11247c478bd9Sstevel@tonic-gate return (EFAULT); 11257c478bd9Sstevel@tonic-gate break; 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate case IA_KY_UPRI: 11287c478bd9Sstevel@tonic-gate if (priflag++) 11297c478bd9Sstevel@tonic-gate return (EINVAL); 11307c478bd9Sstevel@tonic-gate if (copyout(&iaprmsp->ia_upri, 11317c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)vpp->pc_parm, sizeof (pri_t))) 11327c478bd9Sstevel@tonic-gate return (EFAULT); 11337c478bd9Sstevel@tonic-gate break; 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate case IA_KY_MODE: 11367c478bd9Sstevel@tonic-gate if (mflag++) 11377c478bd9Sstevel@tonic-gate return (EINVAL); 11387c478bd9Sstevel@tonic-gate if (copyout(&iaprmsp->ia_mode, 11397c478bd9Sstevel@tonic-gate (caddr_t)(uintptr_t)vpp->pc_parm, sizeof (int))) 11407c478bd9Sstevel@tonic-gate return (EFAULT); 11417c478bd9Sstevel@tonic-gate break; 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate default: 11447c478bd9Sstevel@tonic-gate return (EINVAL); 11457c478bd9Sstevel@tonic-gate } 11467c478bd9Sstevel@tonic-gate } 11477c478bd9Sstevel@tonic-gate return (0); 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate 11517c478bd9Sstevel@tonic-gate /* 11527c478bd9Sstevel@tonic-gate * Set the scheduling parameters of the thread pointed to by tsprocp 11537c478bd9Sstevel@tonic-gate * to those specified in the buffer pointed to by tsparmsp. 11547c478bd9Sstevel@tonic-gate * ts_parmsset() is called for TS threads, and ia_parmsset() is 11557c478bd9Sstevel@tonic-gate * called for IA threads. 11567c478bd9Sstevel@tonic-gate */ 11577c478bd9Sstevel@tonic-gate /* ARGSUSED */ 11587c478bd9Sstevel@tonic-gate static int 11597c478bd9Sstevel@tonic-gate ts_parmsset(kthread_t *tx, void *parmsp, id_t reqpcid, cred_t *reqpcredp) 11607c478bd9Sstevel@tonic-gate { 11617c478bd9Sstevel@tonic-gate char nice; 11627c478bd9Sstevel@tonic-gate pri_t reqtsuprilim; 11637c478bd9Sstevel@tonic-gate pri_t reqtsupri; 11647c478bd9Sstevel@tonic-gate tsparms_t *tsparmsp = (tsparms_t *)parmsp; 11657c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)tx->t_cldata; 11667c478bd9Sstevel@tonic-gate 11677c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&(ttoproc(tx))->p_lock)); 11687c478bd9Sstevel@tonic-gate 11697c478bd9Sstevel@tonic-gate if (tsparmsp->ts_uprilim == TS_NOCHANGE) 11707c478bd9Sstevel@tonic-gate reqtsuprilim = tspp->ts_uprilim; 11717c478bd9Sstevel@tonic-gate else 11727c478bd9Sstevel@tonic-gate reqtsuprilim = tsparmsp->ts_uprilim; 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate if (tsparmsp->ts_upri == TS_NOCHANGE) 11757c478bd9Sstevel@tonic-gate reqtsupri = tspp->ts_upri; 11767c478bd9Sstevel@tonic-gate else 11777c478bd9Sstevel@tonic-gate reqtsupri = tsparmsp->ts_upri; 11787c478bd9Sstevel@tonic-gate 11797c478bd9Sstevel@tonic-gate /* 11807c478bd9Sstevel@tonic-gate * Make sure the user priority doesn't exceed the upri limit. 11817c478bd9Sstevel@tonic-gate */ 11827c478bd9Sstevel@tonic-gate if (reqtsupri > reqtsuprilim) 11837c478bd9Sstevel@tonic-gate reqtsupri = reqtsuprilim; 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate /* 11867c478bd9Sstevel@tonic-gate * Basic permissions enforced by generic kernel code 11877c478bd9Sstevel@tonic-gate * for all classes require that a thread attempting 11887c478bd9Sstevel@tonic-gate * to change the scheduling parameters of a target 11897c478bd9Sstevel@tonic-gate * thread be privileged or have a real or effective 11907c478bd9Sstevel@tonic-gate * UID matching that of the target thread. We are not 11917c478bd9Sstevel@tonic-gate * called unless these basic permission checks have 11927c478bd9Sstevel@tonic-gate * already passed. The time-sharing class requires in 11937c478bd9Sstevel@tonic-gate * addition that the calling thread be privileged if it 11947c478bd9Sstevel@tonic-gate * is attempting to raise the upri limit above its current 11957c478bd9Sstevel@tonic-gate * value This may have been checked previously but if our 11967c478bd9Sstevel@tonic-gate * caller passed us a non-NULL credential pointer we assume 11977c478bd9Sstevel@tonic-gate * it hasn't and we check it here. 11987c478bd9Sstevel@tonic-gate */ 11997c478bd9Sstevel@tonic-gate if (reqpcredp != NULL && 12007c478bd9Sstevel@tonic-gate reqtsuprilim > tspp->ts_uprilim && 1201*24d819e6SJerry Jelinek secpolicy_raisepriority(reqpcredp) != 0) 12027c478bd9Sstevel@tonic-gate return (EPERM); 12037c478bd9Sstevel@tonic-gate 12047c478bd9Sstevel@tonic-gate /* 12057c478bd9Sstevel@tonic-gate * Set ts_nice to the nice value corresponding to the user 12067c478bd9Sstevel@tonic-gate * priority we are setting. Note that setting the nice field 12077c478bd9Sstevel@tonic-gate * of the parameter struct won't affect upri or nice. 12087c478bd9Sstevel@tonic-gate */ 12097c478bd9Sstevel@tonic-gate nice = NZERO - (reqtsupri * NZERO) / ts_maxupri; 12107c478bd9Sstevel@tonic-gate if (nice >= 2 * NZERO) 12117c478bd9Sstevel@tonic-gate nice = 2 * NZERO - 1; 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate thread_lock(tx); 12147c478bd9Sstevel@tonic-gate 12157c478bd9Sstevel@tonic-gate tspp->ts_uprilim = reqtsuprilim; 12167c478bd9Sstevel@tonic-gate tspp->ts_upri = reqtsupri; 12177c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(tspp); 12187c478bd9Sstevel@tonic-gate tspp->ts_nice = nice; 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate if ((tspp->ts_flags & TSKPRI) != 0) { 12217c478bd9Sstevel@tonic-gate thread_unlock(tx); 12227c478bd9Sstevel@tonic-gate return (0); 12237c478bd9Sstevel@tonic-gate } 12247c478bd9Sstevel@tonic-gate 12257c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 12267c478bd9Sstevel@tonic-gate ts_change_priority(tx, tspp); 12277c478bd9Sstevel@tonic-gate thread_unlock(tx); 12287c478bd9Sstevel@tonic-gate return (0); 12297c478bd9Sstevel@tonic-gate } 12307c478bd9Sstevel@tonic-gate 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate static int 12337c478bd9Sstevel@tonic-gate ia_parmsset(kthread_t *tx, void *parmsp, id_t reqpcid, cred_t *reqpcredp) 12347c478bd9Sstevel@tonic-gate { 12357c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)tx->t_cldata; 12367c478bd9Sstevel@tonic-gate iaparms_t *iaparmsp = (iaparms_t *)parmsp; 12377c478bd9Sstevel@tonic-gate proc_t *p; 12387c478bd9Sstevel@tonic-gate pid_t pid, pgid, sid; 12397c478bd9Sstevel@tonic-gate pid_t on, off; 12407c478bd9Sstevel@tonic-gate struct stdata *stp; 12417c478bd9Sstevel@tonic-gate int sess_held; 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate /* 12447c478bd9Sstevel@tonic-gate * Handle user priority changes 12457c478bd9Sstevel@tonic-gate */ 12467c478bd9Sstevel@tonic-gate if (iaparmsp->ia_mode == IA_NOCHANGE) 12477c478bd9Sstevel@tonic-gate return (ts_parmsset(tx, parmsp, reqpcid, reqpcredp)); 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate /* 12507c478bd9Sstevel@tonic-gate * Check permissions for changing modes. 12517c478bd9Sstevel@tonic-gate */ 12527c478bd9Sstevel@tonic-gate 12537c478bd9Sstevel@tonic-gate if (reqpcredp != NULL && !groupmember(IA_gid, reqpcredp) && 1254*24d819e6SJerry Jelinek secpolicy_raisepriority(reqpcredp) != 0) { 12557c478bd9Sstevel@tonic-gate /* 12567c478bd9Sstevel@tonic-gate * Silently fail in case this is just a priocntl 12577c478bd9Sstevel@tonic-gate * call with upri and uprilim set to IA_NOCHANGE. 12587c478bd9Sstevel@tonic-gate */ 12597c478bd9Sstevel@tonic-gate return (0); 12607c478bd9Sstevel@tonic-gate } 12617c478bd9Sstevel@tonic-gate 12627c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 12637c478bd9Sstevel@tonic-gate if ((p = ttoproc(tx)) == NULL) { 12647c478bd9Sstevel@tonic-gate return (0); 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&p->p_lock)); 12677c478bd9Sstevel@tonic-gate if (p->p_stat == SIDL) { 12687c478bd9Sstevel@tonic-gate return (0); 12697c478bd9Sstevel@tonic-gate } 12707c478bd9Sstevel@tonic-gate pid = p->p_pid; 12717c478bd9Sstevel@tonic-gate sid = p->p_sessp->s_sid; 12727c478bd9Sstevel@tonic-gate pgid = p->p_pgrp; 12737c478bd9Sstevel@tonic-gate if (iaparmsp->ia_mode == IA_SET_INTERACTIVE) { 12747c478bd9Sstevel@tonic-gate /* 12757c478bd9Sstevel@tonic-gate * session leaders must be turned on now so all processes 12767c478bd9Sstevel@tonic-gate * in the group controlling the tty will be turned on or off. 12777c478bd9Sstevel@tonic-gate * if the ia_mode is off for the session leader, 12787c478bd9Sstevel@tonic-gate * ia_set_process_group will return without setting the 12797c478bd9Sstevel@tonic-gate * processes in the group controlling the tty on. 12807c478bd9Sstevel@tonic-gate */ 12817c478bd9Sstevel@tonic-gate thread_lock(tx); 12827c478bd9Sstevel@tonic-gate tspp->ts_flags |= TSIASET; 12837c478bd9Sstevel@tonic-gate thread_unlock(tx); 12847c478bd9Sstevel@tonic-gate } 12859acbbeafSnn35248 mutex_enter(&p->p_sessp->s_lock); 12867c478bd9Sstevel@tonic-gate sess_held = 1; 12877c478bd9Sstevel@tonic-gate if ((pid == sid) && (p->p_sessp->s_vp != NULL) && 12887c478bd9Sstevel@tonic-gate ((stp = p->p_sessp->s_vp->v_stream) != NULL)) { 12897c478bd9Sstevel@tonic-gate if ((stp->sd_pgidp != NULL) && (stp->sd_sidp != NULL)) { 12907c478bd9Sstevel@tonic-gate pgid = stp->sd_pgidp->pid_id; 12917c478bd9Sstevel@tonic-gate sess_held = 0; 12929acbbeafSnn35248 mutex_exit(&p->p_sessp->s_lock); 12937c478bd9Sstevel@tonic-gate if (iaparmsp->ia_mode == 12947c478bd9Sstevel@tonic-gate IA_SET_INTERACTIVE) { 12957c478bd9Sstevel@tonic-gate off = 0; 12967c478bd9Sstevel@tonic-gate on = pgid; 12977c478bd9Sstevel@tonic-gate } else { 12987c478bd9Sstevel@tonic-gate off = pgid; 12997c478bd9Sstevel@tonic-gate on = 0; 13007c478bd9Sstevel@tonic-gate } 13017c478bd9Sstevel@tonic-gate TRACE_3(TR_FAC_IA, TR_ACTIVE_CHAIN, 13027c478bd9Sstevel@tonic-gate "active chain:pid %d gid %d %p", 13037c478bd9Sstevel@tonic-gate pid, pgid, p); 13047c478bd9Sstevel@tonic-gate ia_set_process_group(sid, off, on); 13057c478bd9Sstevel@tonic-gate } 13067c478bd9Sstevel@tonic-gate } 13077c478bd9Sstevel@tonic-gate if (sess_held) 13089acbbeafSnn35248 mutex_exit(&p->p_sessp->s_lock); 13097c478bd9Sstevel@tonic-gate 13107c478bd9Sstevel@tonic-gate thread_lock(tx); 13117c478bd9Sstevel@tonic-gate 13127c478bd9Sstevel@tonic-gate if (iaparmsp->ia_mode == IA_SET_INTERACTIVE) { 13137c478bd9Sstevel@tonic-gate tspp->ts_flags |= TSIASET; 13147c478bd9Sstevel@tonic-gate tspp->ts_boost = ia_boost; 13157c478bd9Sstevel@tonic-gate } else { 13167c478bd9Sstevel@tonic-gate tspp->ts_flags &= ~TSIASET; 13177c478bd9Sstevel@tonic-gate tspp->ts_boost = -ia_boost; 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate thread_unlock(tx); 13207c478bd9Sstevel@tonic-gate 13217c478bd9Sstevel@tonic-gate return (ts_parmsset(tx, parmsp, reqpcid, reqpcredp)); 13227c478bd9Sstevel@tonic-gate } 13237c478bd9Sstevel@tonic-gate 1324c97ad5cdSakolb static void 1325c97ad5cdSakolb ts_exit(kthread_t *t) 1326c97ad5cdSakolb { 1327c97ad5cdSakolb tsproc_t *tspp; 1328c97ad5cdSakolb 1329c97ad5cdSakolb if (CPUCAPS_ON()) { 1330c97ad5cdSakolb /* 1331c97ad5cdSakolb * A thread could be exiting in between clock ticks, 1332c97ad5cdSakolb * so we need to calculate how much CPU time it used 1333c97ad5cdSakolb * since it was charged last time. 13348c34bbb7Sakolb * 13358c34bbb7Sakolb * CPU caps are not enforced on exiting processes - it is 13368c34bbb7Sakolb * usually desirable to exit as soon as possible to free 13378c34bbb7Sakolb * resources. 1338c97ad5cdSakolb */ 1339c97ad5cdSakolb thread_lock(t); 1340c97ad5cdSakolb tspp = (tsproc_t *)t->t_cldata; 1341c97ad5cdSakolb (void) cpucaps_charge(t, &tspp->ts_caps, CPUCAPS_CHARGE_ONLY); 1342c97ad5cdSakolb thread_unlock(t); 1343c97ad5cdSakolb } 1344c97ad5cdSakolb } 1345c97ad5cdSakolb 13467c478bd9Sstevel@tonic-gate /* 13477c478bd9Sstevel@tonic-gate * Return the global scheduling priority that would be assigned 13487c478bd9Sstevel@tonic-gate * to a thread entering the time-sharing class with the ts_upri. 13497c478bd9Sstevel@tonic-gate */ 13507c478bd9Sstevel@tonic-gate static pri_t 13517c478bd9Sstevel@tonic-gate ts_globpri(kthread_t *t) 13527c478bd9Sstevel@tonic-gate { 13537c478bd9Sstevel@tonic-gate tsproc_t *tspp; 13547c478bd9Sstevel@tonic-gate pri_t tspri; 13557c478bd9Sstevel@tonic-gate 13567c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock)); 13577c478bd9Sstevel@tonic-gate tspp = (tsproc_t *)t->t_cldata; 13587c478bd9Sstevel@tonic-gate tspri = tsmedumdpri + tspp->ts_upri; 13597c478bd9Sstevel@tonic-gate if (tspri > ts_maxumdpri) 13607c478bd9Sstevel@tonic-gate tspri = ts_maxumdpri; 13617c478bd9Sstevel@tonic-gate else if (tspri < 0) 13627c478bd9Sstevel@tonic-gate tspri = 0; 13637c478bd9Sstevel@tonic-gate return (ts_dptbl[tspri].ts_globpri); 13647c478bd9Sstevel@tonic-gate } 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate /* 13677c478bd9Sstevel@tonic-gate * Arrange for thread to be placed in appropriate location 13687c478bd9Sstevel@tonic-gate * on dispatcher queue. 13697c478bd9Sstevel@tonic-gate * 13707c478bd9Sstevel@tonic-gate * This is called with the current thread in TS_ONPROC and locked. 13717c478bd9Sstevel@tonic-gate */ 13727c478bd9Sstevel@tonic-gate static void 13737c478bd9Sstevel@tonic-gate ts_preempt(kthread_t *t) 13747c478bd9Sstevel@tonic-gate { 13757c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)(t->t_cldata); 1376c97ad5cdSakolb klwp_t *lwp = curthread->t_lwp; 13777c478bd9Sstevel@tonic-gate pri_t oldpri = t->t_pri; 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate ASSERT(t == curthread); 13807c478bd9Sstevel@tonic-gate ASSERT(THREAD_LOCK_HELD(curthread)); 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate /* 13837c478bd9Sstevel@tonic-gate * If preempted in the kernel, make sure the thread has 13847c478bd9Sstevel@tonic-gate * a kernel priority if needed. 13857c478bd9Sstevel@tonic-gate */ 13867c478bd9Sstevel@tonic-gate if (!(tspp->ts_flags & TSKPRI) && lwp != NULL && t->t_kpri_req) { 13877c478bd9Sstevel@tonic-gate tspp->ts_flags |= TSKPRI; 13887c478bd9Sstevel@tonic-gate THREAD_CHANGE_PRI(t, ts_kmdpris[0]); 13897c478bd9Sstevel@tonic-gate ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri); 13907c478bd9Sstevel@tonic-gate t->t_trapret = 1; /* so ts_trapret will run */ 13917c478bd9Sstevel@tonic-gate aston(t); 13927c478bd9Sstevel@tonic-gate } 1393c97ad5cdSakolb 13947c478bd9Sstevel@tonic-gate /* 1395c97ad5cdSakolb * This thread may be placed on wait queue by CPU Caps. In this case we 1396c97ad5cdSakolb * do not need to do anything until it is removed from the wait queue. 1397c97ad5cdSakolb * Do not enforce CPU caps on threads running at a kernel priority 1398c97ad5cdSakolb */ 1399c97ad5cdSakolb if (CPUCAPS_ON()) { 14008c34bbb7Sakolb (void) cpucaps_charge(t, &tspp->ts_caps, 14018c34bbb7Sakolb CPUCAPS_CHARGE_ENFORCE); 1402c97ad5cdSakolb if (!(tspp->ts_flags & TSKPRI) && CPUCAPS_ENFORCE(t)) 1403c97ad5cdSakolb return; 1404c97ad5cdSakolb } 1405c97ad5cdSakolb 1406c97ad5cdSakolb /* 1407c97ad5cdSakolb * If thread got preempted in the user-land then we know 1408c97ad5cdSakolb * it isn't holding any locks. Mark it as swappable. 14097c478bd9Sstevel@tonic-gate */ 14107c478bd9Sstevel@tonic-gate ASSERT(t->t_schedflag & TS_DONT_SWAP); 14117c478bd9Sstevel@tonic-gate if (lwp != NULL && lwp->lwp_state == LWP_USER) 14127c478bd9Sstevel@tonic-gate t->t_schedflag &= ~TS_DONT_SWAP; 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate /* 14157c478bd9Sstevel@tonic-gate * Check to see if we're doing "preemption control" here. If 14167c478bd9Sstevel@tonic-gate * we are, and if the user has requested that this thread not 14177c478bd9Sstevel@tonic-gate * be preempted, and if preemptions haven't been put off for 14187c478bd9Sstevel@tonic-gate * too long, let the preemption happen here but try to make 14197c478bd9Sstevel@tonic-gate * sure the thread is rescheduled as soon as possible. We do 14207c478bd9Sstevel@tonic-gate * this by putting it on the front of the highest priority run 14217c478bd9Sstevel@tonic-gate * queue in the TS class. If the preemption has been put off 14227c478bd9Sstevel@tonic-gate * for too long, clear the "nopreempt" bit and let the thread 14237c478bd9Sstevel@tonic-gate * be preempted. 14247c478bd9Sstevel@tonic-gate */ 14257c478bd9Sstevel@tonic-gate if (t->t_schedctl && schedctl_get_nopreempt(t)) { 14267c478bd9Sstevel@tonic-gate if (tspp->ts_timeleft > -SC_MAX_TICKS) { 14277c478bd9Sstevel@tonic-gate DTRACE_SCHED1(schedctl__nopreempt, kthread_t *, t); 14287c478bd9Sstevel@tonic-gate if (!(tspp->ts_flags & TSKPRI)) { 14299ac8606fSraf /* 14309ac8606fSraf * If not already remembered, remember current 14319ac8606fSraf * priority for restoration in ts_yield(). 14329ac8606fSraf */ 14339ac8606fSraf if (!(tspp->ts_flags & TSRESTORE)) { 14349ac8606fSraf tspp->ts_scpri = t->t_pri; 14359ac8606fSraf tspp->ts_flags |= TSRESTORE; 14369ac8606fSraf } 14377c478bd9Sstevel@tonic-gate THREAD_CHANGE_PRI(t, ts_maxumdpri); 14387c478bd9Sstevel@tonic-gate t->t_schedflag |= TS_DONT_SWAP; 14397c478bd9Sstevel@tonic-gate } 14409ac8606fSraf schedctl_set_yield(t, 1); 14417c478bd9Sstevel@tonic-gate setfrontdq(t); 14427c478bd9Sstevel@tonic-gate goto done; 14437c478bd9Sstevel@tonic-gate } else { 14449ac8606fSraf if (tspp->ts_flags & TSRESTORE) { 14459ac8606fSraf THREAD_CHANGE_PRI(t, tspp->ts_scpri); 14469ac8606fSraf tspp->ts_flags &= ~TSRESTORE; 14479ac8606fSraf } 14487c478bd9Sstevel@tonic-gate schedctl_set_nopreempt(t, 0); 14497c478bd9Sstevel@tonic-gate DTRACE_SCHED1(schedctl__preempt, kthread_t *, t); 14507c478bd9Sstevel@tonic-gate TNF_PROBE_2(schedctl_preempt, "schedctl TS ts_preempt", 14517c478bd9Sstevel@tonic-gate /* CSTYLED */, tnf_pid, pid, ttoproc(t)->p_pid, 14527c478bd9Sstevel@tonic-gate tnf_lwpid, lwpid, t->t_tid); 14537c478bd9Sstevel@tonic-gate /* 14547c478bd9Sstevel@tonic-gate * Fall through and be preempted below. 14557c478bd9Sstevel@tonic-gate */ 14567c478bd9Sstevel@tonic-gate } 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate if ((tspp->ts_flags & (TSBACKQ|TSKPRI)) == TSBACKQ) { 14607c478bd9Sstevel@tonic-gate tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum; 14617c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 14627c478bd9Sstevel@tonic-gate tspp->ts_flags &= ~TSBACKQ; 14637c478bd9Sstevel@tonic-gate setbackdq(t); 14647c478bd9Sstevel@tonic-gate } else if ((tspp->ts_flags & (TSBACKQ|TSKPRI)) == (TSBACKQ|TSKPRI)) { 14657c478bd9Sstevel@tonic-gate tspp->ts_flags &= ~TSBACKQ; 14667c478bd9Sstevel@tonic-gate setbackdq(t); 14677c478bd9Sstevel@tonic-gate } else { 14687c478bd9Sstevel@tonic-gate setfrontdq(t); 14697c478bd9Sstevel@tonic-gate } 14707c478bd9Sstevel@tonic-gate 14717c478bd9Sstevel@tonic-gate done: 14727c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_DISP, TR_PREEMPT, 14737c478bd9Sstevel@tonic-gate "preempt:tid %p old pri %d", t, oldpri); 14747c478bd9Sstevel@tonic-gate } 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate static void 14777c478bd9Sstevel@tonic-gate ts_setrun(kthread_t *t) 14787c478bd9Sstevel@tonic-gate { 14797c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)(t->t_cldata); 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate ASSERT(THREAD_LOCK_HELD(t)); /* t should be in transition */ 14827c478bd9Sstevel@tonic-gate 14837c478bd9Sstevel@tonic-gate if (tspp->ts_dispwait > ts_dptbl[tspp->ts_umdpri].ts_maxwait) { 14847c478bd9Sstevel@tonic-gate tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_slpret; 14857c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(tspp); 14867c478bd9Sstevel@tonic-gate tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum; 14877c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 14887c478bd9Sstevel@tonic-gate if ((tspp->ts_flags & TSKPRI) == 0) { 14897c478bd9Sstevel@tonic-gate THREAD_CHANGE_PRI(t, 14907c478bd9Sstevel@tonic-gate ts_dptbl[tspp->ts_umdpri].ts_globpri); 14917c478bd9Sstevel@tonic-gate ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri); 14927c478bd9Sstevel@tonic-gate } 14937c478bd9Sstevel@tonic-gate } 14947c478bd9Sstevel@tonic-gate 14957c478bd9Sstevel@tonic-gate tspp->ts_flags &= ~TSBACKQ; 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate if (tspp->ts_flags & TSIA) { 14987c478bd9Sstevel@tonic-gate if (tspp->ts_flags & TSIASET) 14997c478bd9Sstevel@tonic-gate setfrontdq(t); 15007c478bd9Sstevel@tonic-gate else 15017c478bd9Sstevel@tonic-gate setbackdq(t); 15027c478bd9Sstevel@tonic-gate } else { 1503d3d50737SRafael Vanoni if (t->t_disp_time != ddi_get_lbolt()) 15047c478bd9Sstevel@tonic-gate setbackdq(t); 15057c478bd9Sstevel@tonic-gate else 15067c478bd9Sstevel@tonic-gate setfrontdq(t); 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate } 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate 15117c478bd9Sstevel@tonic-gate /* 15127c478bd9Sstevel@tonic-gate * Prepare thread for sleep. We reset the thread priority so it will 15137c478bd9Sstevel@tonic-gate * run at the kernel priority level when it wakes up. 15147c478bd9Sstevel@tonic-gate */ 15157c478bd9Sstevel@tonic-gate static void 15167c478bd9Sstevel@tonic-gate ts_sleep(kthread_t *t) 15177c478bd9Sstevel@tonic-gate { 15187c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)(t->t_cldata); 15197c478bd9Sstevel@tonic-gate int flags; 15207c478bd9Sstevel@tonic-gate pri_t old_pri = t->t_pri; 15217c478bd9Sstevel@tonic-gate 15227c478bd9Sstevel@tonic-gate ASSERT(t == curthread); 15237c478bd9Sstevel@tonic-gate ASSERT(THREAD_LOCK_HELD(t)); 15247c478bd9Sstevel@tonic-gate 1525c97ad5cdSakolb /* 1526c97ad5cdSakolb * Account for time spent on CPU before going to sleep. 1527c97ad5cdSakolb */ 15288c34bbb7Sakolb (void) CPUCAPS_CHARGE(t, &tspp->ts_caps, CPUCAPS_CHARGE_ENFORCE); 1529c97ad5cdSakolb 15307c478bd9Sstevel@tonic-gate flags = tspp->ts_flags; 15317c478bd9Sstevel@tonic-gate if (t->t_kpri_req) { 15327c478bd9Sstevel@tonic-gate tspp->ts_flags = flags | TSKPRI; 15337c478bd9Sstevel@tonic-gate THREAD_CHANGE_PRI(t, ts_kmdpris[0]); 15347c478bd9Sstevel@tonic-gate ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri); 15357c478bd9Sstevel@tonic-gate t->t_trapret = 1; /* so ts_trapret will run */ 15367c478bd9Sstevel@tonic-gate aston(t); 15377c478bd9Sstevel@tonic-gate } else if (tspp->ts_dispwait > ts_dptbl[tspp->ts_umdpri].ts_maxwait) { 15387c478bd9Sstevel@tonic-gate /* 15397c478bd9Sstevel@tonic-gate * If thread has blocked in the kernel (as opposed to 15407c478bd9Sstevel@tonic-gate * being merely preempted), recompute the user mode priority. 15417c478bd9Sstevel@tonic-gate */ 15427c478bd9Sstevel@tonic-gate tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_slpret; 15437c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(tspp); 15447c478bd9Sstevel@tonic-gate tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum; 15457c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 15467c478bd9Sstevel@tonic-gate 15477c478bd9Sstevel@tonic-gate THREAD_CHANGE_PRI(curthread, 15487c478bd9Sstevel@tonic-gate ts_dptbl[tspp->ts_umdpri].ts_globpri); 15497c478bd9Sstevel@tonic-gate ASSERT(curthread->t_pri >= 0 && 15507c478bd9Sstevel@tonic-gate curthread->t_pri <= ts_maxglobpri); 15517c478bd9Sstevel@tonic-gate tspp->ts_flags = flags & ~TSKPRI; 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate if (DISP_MUST_SURRENDER(curthread)) 15547c478bd9Sstevel@tonic-gate cpu_surrender(curthread); 15557c478bd9Sstevel@tonic-gate } else if (flags & TSKPRI) { 15567c478bd9Sstevel@tonic-gate THREAD_CHANGE_PRI(curthread, 15577c478bd9Sstevel@tonic-gate ts_dptbl[tspp->ts_umdpri].ts_globpri); 15587c478bd9Sstevel@tonic-gate ASSERT(curthread->t_pri >= 0 && 15597c478bd9Sstevel@tonic-gate curthread->t_pri <= ts_maxglobpri); 15607c478bd9Sstevel@tonic-gate tspp->ts_flags = flags & ~TSKPRI; 15617c478bd9Sstevel@tonic-gate 15627c478bd9Sstevel@tonic-gate if (DISP_MUST_SURRENDER(curthread)) 15637c478bd9Sstevel@tonic-gate cpu_surrender(curthread); 15647c478bd9Sstevel@tonic-gate } 1565d3d50737SRafael Vanoni t->t_stime = ddi_get_lbolt(); /* time stamp for the swapper */ 15667c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_DISP, TR_SLEEP, 15677c478bd9Sstevel@tonic-gate "sleep:tid %p old pri %d", t, old_pri); 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate 15717c478bd9Sstevel@tonic-gate /* 15727c478bd9Sstevel@tonic-gate * Return Values: 15737c478bd9Sstevel@tonic-gate * 15747c478bd9Sstevel@tonic-gate * -1 if the thread is loaded or is not eligible to be swapped in. 15757c478bd9Sstevel@tonic-gate * 15767c478bd9Sstevel@tonic-gate * effective priority of the specified thread based on swapout time 15777c478bd9Sstevel@tonic-gate * and size of process (epri >= 0 , epri <= SHRT_MAX). 15787c478bd9Sstevel@tonic-gate */ 15797c478bd9Sstevel@tonic-gate /* ARGSUSED */ 15807c478bd9Sstevel@tonic-gate static pri_t 15817c478bd9Sstevel@tonic-gate ts_swapin(kthread_t *t, int flags) 15827c478bd9Sstevel@tonic-gate { 15837c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)(t->t_cldata); 15847c478bd9Sstevel@tonic-gate long epri = -1; 15857c478bd9Sstevel@tonic-gate proc_t *pp = ttoproc(t); 15867c478bd9Sstevel@tonic-gate 15877c478bd9Sstevel@tonic-gate ASSERT(THREAD_LOCK_HELD(t)); 15887c478bd9Sstevel@tonic-gate 15897c478bd9Sstevel@tonic-gate /* 15907c478bd9Sstevel@tonic-gate * We know that pri_t is a short. 15917c478bd9Sstevel@tonic-gate * Be sure not to overrun its range. 15927c478bd9Sstevel@tonic-gate */ 15937c478bd9Sstevel@tonic-gate if (t->t_state == TS_RUN && (t->t_schedflag & TS_LOAD) == 0) { 15947c478bd9Sstevel@tonic-gate time_t swapout_time; 15957c478bd9Sstevel@tonic-gate 1596d3d50737SRafael Vanoni swapout_time = (ddi_get_lbolt() - t->t_stime) / hz; 15977c478bd9Sstevel@tonic-gate if (INHERITED(t) || (tspp->ts_flags & (TSKPRI | TSIASET))) 15987c478bd9Sstevel@tonic-gate epri = (long)DISP_PRIO(t) + swapout_time; 15997c478bd9Sstevel@tonic-gate else { 16007c478bd9Sstevel@tonic-gate /* 16017c478bd9Sstevel@tonic-gate * Threads which have been out for a long time, 16027c478bd9Sstevel@tonic-gate * have high user mode priority and are associated 16037c478bd9Sstevel@tonic-gate * with a small address space are more deserving 16047c478bd9Sstevel@tonic-gate */ 16057c478bd9Sstevel@tonic-gate epri = ts_dptbl[tspp->ts_umdpri].ts_globpri; 16067c478bd9Sstevel@tonic-gate ASSERT(epri >= 0 && epri <= ts_maxumdpri); 16077c478bd9Sstevel@tonic-gate epri += swapout_time - pp->p_swrss / nz(maxpgio)/2; 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate /* 16107c478bd9Sstevel@tonic-gate * Scale epri so SHRT_MAX/2 represents zero priority. 16117c478bd9Sstevel@tonic-gate */ 16127c478bd9Sstevel@tonic-gate epri += SHRT_MAX/2; 16137c478bd9Sstevel@tonic-gate if (epri < 0) 16147c478bd9Sstevel@tonic-gate epri = 0; 16157c478bd9Sstevel@tonic-gate else if (epri > SHRT_MAX) 16167c478bd9Sstevel@tonic-gate epri = SHRT_MAX; 16177c478bd9Sstevel@tonic-gate } 16187c478bd9Sstevel@tonic-gate return ((pri_t)epri); 16197c478bd9Sstevel@tonic-gate } 16207c478bd9Sstevel@tonic-gate 16217c478bd9Sstevel@tonic-gate /* 16227c478bd9Sstevel@tonic-gate * Return Values 16237c478bd9Sstevel@tonic-gate * -1 if the thread isn't loaded or is not eligible to be swapped out. 16247c478bd9Sstevel@tonic-gate * 16257c478bd9Sstevel@tonic-gate * effective priority of the specified thread based on if the swapper 16267c478bd9Sstevel@tonic-gate * is in softswap or hardswap mode. 16277c478bd9Sstevel@tonic-gate * 16287c478bd9Sstevel@tonic-gate * Softswap: Return a low effective priority for threads 16297c478bd9Sstevel@tonic-gate * sleeping for more than maxslp secs. 16307c478bd9Sstevel@tonic-gate * 16317c478bd9Sstevel@tonic-gate * Hardswap: Return an effective priority such that threads 16327c478bd9Sstevel@tonic-gate * which have been in memory for a while and are 16337c478bd9Sstevel@tonic-gate * associated with a small address space are swapped 16347c478bd9Sstevel@tonic-gate * in before others. 16357c478bd9Sstevel@tonic-gate * 16367c478bd9Sstevel@tonic-gate * (epri >= 0 , epri <= SHRT_MAX). 16377c478bd9Sstevel@tonic-gate */ 16387c478bd9Sstevel@tonic-gate time_t ts_minrun = 2; /* XXX - t_pri becomes 59 within 2 secs */ 16397c478bd9Sstevel@tonic-gate time_t ts_minslp = 2; /* min time on sleep queue for hardswap */ 16407c478bd9Sstevel@tonic-gate 16417c478bd9Sstevel@tonic-gate static pri_t 16427c478bd9Sstevel@tonic-gate ts_swapout(kthread_t *t, int flags) 16437c478bd9Sstevel@tonic-gate { 16447c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)(t->t_cldata); 16457c478bd9Sstevel@tonic-gate long epri = -1; 16467c478bd9Sstevel@tonic-gate proc_t *pp = ttoproc(t); 16477c478bd9Sstevel@tonic-gate time_t swapin_time; 16487c478bd9Sstevel@tonic-gate 16497c478bd9Sstevel@tonic-gate ASSERT(THREAD_LOCK_HELD(t)); 16507c478bd9Sstevel@tonic-gate 16517c478bd9Sstevel@tonic-gate if (INHERITED(t) || (tspp->ts_flags & (TSKPRI | TSIASET)) || 16527c478bd9Sstevel@tonic-gate (t->t_proc_flag & TP_LWPEXIT) || 1653c97ad5cdSakolb (t->t_state & (TS_ZOMB | TS_FREE | TS_STOPPED | 1654c97ad5cdSakolb TS_ONPROC | TS_WAIT)) || 16557c478bd9Sstevel@tonic-gate !(t->t_schedflag & TS_LOAD) || !SWAP_OK(t)) 16567c478bd9Sstevel@tonic-gate return (-1); 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate ASSERT(t->t_state & (TS_SLEEP | TS_RUN)); 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate /* 16617c478bd9Sstevel@tonic-gate * We know that pri_t is a short. 16627c478bd9Sstevel@tonic-gate * Be sure not to overrun its range. 16637c478bd9Sstevel@tonic-gate */ 1664d3d50737SRafael Vanoni swapin_time = (ddi_get_lbolt() - t->t_stime) / hz; 16657c478bd9Sstevel@tonic-gate if (flags == SOFTSWAP) { 16667c478bd9Sstevel@tonic-gate if (t->t_state == TS_SLEEP && swapin_time > maxslp) { 16677c478bd9Sstevel@tonic-gate epri = 0; 16687c478bd9Sstevel@tonic-gate } else { 16697c478bd9Sstevel@tonic-gate return ((pri_t)epri); 16707c478bd9Sstevel@tonic-gate } 16717c478bd9Sstevel@tonic-gate } else { 16727c478bd9Sstevel@tonic-gate pri_t pri; 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate if ((t->t_state == TS_SLEEP && swapin_time > ts_minslp) || 16757c478bd9Sstevel@tonic-gate (t->t_state == TS_RUN && swapin_time > ts_minrun)) { 16767c478bd9Sstevel@tonic-gate pri = ts_dptbl[tspp->ts_umdpri].ts_globpri; 16777c478bd9Sstevel@tonic-gate ASSERT(pri >= 0 && pri <= ts_maxumdpri); 16787c478bd9Sstevel@tonic-gate epri = swapin_time - 16797c478bd9Sstevel@tonic-gate (rm_asrss(pp->p_as) / nz(maxpgio)/2) - (long)pri; 16807c478bd9Sstevel@tonic-gate } else { 16817c478bd9Sstevel@tonic-gate return ((pri_t)epri); 16827c478bd9Sstevel@tonic-gate } 16837c478bd9Sstevel@tonic-gate } 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate /* 16867c478bd9Sstevel@tonic-gate * Scale epri so SHRT_MAX/2 represents zero priority. 16877c478bd9Sstevel@tonic-gate */ 16887c478bd9Sstevel@tonic-gate epri += SHRT_MAX/2; 16897c478bd9Sstevel@tonic-gate if (epri < 0) 16907c478bd9Sstevel@tonic-gate epri = 0; 16917c478bd9Sstevel@tonic-gate else if (epri > SHRT_MAX) 16927c478bd9Sstevel@tonic-gate epri = SHRT_MAX; 16937c478bd9Sstevel@tonic-gate 16947c478bd9Sstevel@tonic-gate return ((pri_t)epri); 16957c478bd9Sstevel@tonic-gate } 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate /* 16987c478bd9Sstevel@tonic-gate * Check for time slice expiration. If time slice has expired 16997c478bd9Sstevel@tonic-gate * move thread to priority specified in tsdptbl for time slice expiration 17007c478bd9Sstevel@tonic-gate * and set runrun to cause preemption. 17017c478bd9Sstevel@tonic-gate */ 17027c478bd9Sstevel@tonic-gate static void 17037c478bd9Sstevel@tonic-gate ts_tick(kthread_t *t) 17047c478bd9Sstevel@tonic-gate { 17057c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)(t->t_cldata); 17067c478bd9Sstevel@tonic-gate klwp_t *lwp; 1707c97ad5cdSakolb boolean_t call_cpu_surrender = B_FALSE; 17087c478bd9Sstevel@tonic-gate pri_t oldpri = t->t_pri; 17097c478bd9Sstevel@tonic-gate 17107c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock)); 17117c478bd9Sstevel@tonic-gate 17127c478bd9Sstevel@tonic-gate thread_lock(t); 1713c97ad5cdSakolb 1714c97ad5cdSakolb /* 1715c97ad5cdSakolb * Keep track of thread's project CPU usage. Note that projects 1716c97ad5cdSakolb * get charged even when threads are running in the kernel. 1717c97ad5cdSakolb */ 1718c97ad5cdSakolb if (CPUCAPS_ON()) { 1719c97ad5cdSakolb call_cpu_surrender = cpucaps_charge(t, &tspp->ts_caps, 1720c97ad5cdSakolb CPUCAPS_CHARGE_ENFORCE) && !(tspp->ts_flags & TSKPRI); 1721c97ad5cdSakolb } 1722c97ad5cdSakolb 17237c478bd9Sstevel@tonic-gate if ((tspp->ts_flags & TSKPRI) == 0) { 17247c478bd9Sstevel@tonic-gate if (--tspp->ts_timeleft <= 0) { 17257c478bd9Sstevel@tonic-gate pri_t new_pri; 17267c478bd9Sstevel@tonic-gate 17277c478bd9Sstevel@tonic-gate /* 17287c478bd9Sstevel@tonic-gate * If we're doing preemption control and trying to 17297c478bd9Sstevel@tonic-gate * avoid preempting this thread, just note that 17307c478bd9Sstevel@tonic-gate * the thread should yield soon and let it keep 17317c478bd9Sstevel@tonic-gate * running (unless it's been a while). 17327c478bd9Sstevel@tonic-gate */ 17337c478bd9Sstevel@tonic-gate if (t->t_schedctl && schedctl_get_nopreempt(t)) { 17347c478bd9Sstevel@tonic-gate if (tspp->ts_timeleft > -SC_MAX_TICKS) { 17357c478bd9Sstevel@tonic-gate DTRACE_SCHED1(schedctl__nopreempt, 17367c478bd9Sstevel@tonic-gate kthread_t *, t); 17377c478bd9Sstevel@tonic-gate schedctl_set_yield(t, 1); 17387c478bd9Sstevel@tonic-gate thread_unlock_nopreempt(t); 17397c478bd9Sstevel@tonic-gate return; 17407c478bd9Sstevel@tonic-gate } 17417c478bd9Sstevel@tonic-gate 17427c478bd9Sstevel@tonic-gate TNF_PROBE_2(schedctl_failsafe, 17437c478bd9Sstevel@tonic-gate "schedctl TS ts_tick", /* CSTYLED */, 17447c478bd9Sstevel@tonic-gate tnf_pid, pid, ttoproc(t)->p_pid, 17457c478bd9Sstevel@tonic-gate tnf_lwpid, lwpid, t->t_tid); 17467c478bd9Sstevel@tonic-gate } 17479ac8606fSraf tspp->ts_flags &= ~TSRESTORE; 17487c478bd9Sstevel@tonic-gate tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_tqexp; 17497c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(tspp); 17507c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 17517c478bd9Sstevel@tonic-gate new_pri = ts_dptbl[tspp->ts_umdpri].ts_globpri; 17527c478bd9Sstevel@tonic-gate ASSERT(new_pri >= 0 && new_pri <= ts_maxglobpri); 17537c478bd9Sstevel@tonic-gate /* 17547c478bd9Sstevel@tonic-gate * When the priority of a thread is changed, 17557c478bd9Sstevel@tonic-gate * it may be necessary to adjust its position 17567c478bd9Sstevel@tonic-gate * on a sleep queue or dispatch queue. 17577c478bd9Sstevel@tonic-gate * The function thread_change_pri accomplishes 17587c478bd9Sstevel@tonic-gate * this. 17597c478bd9Sstevel@tonic-gate */ 17607c478bd9Sstevel@tonic-gate if (thread_change_pri(t, new_pri, 0)) { 17617c478bd9Sstevel@tonic-gate if ((t->t_schedflag & TS_LOAD) && 17627c478bd9Sstevel@tonic-gate (lwp = t->t_lwp) && 17637c478bd9Sstevel@tonic-gate lwp->lwp_state == LWP_USER) 17647c478bd9Sstevel@tonic-gate t->t_schedflag &= ~TS_DONT_SWAP; 17657c478bd9Sstevel@tonic-gate tspp->ts_timeleft = 17667c478bd9Sstevel@tonic-gate ts_dptbl[tspp->ts_cpupri].ts_quantum; 17677c478bd9Sstevel@tonic-gate } else { 1768c97ad5cdSakolb call_cpu_surrender = B_TRUE; 17697c478bd9Sstevel@tonic-gate } 17707c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_DISP, TR_TICK, 17717c478bd9Sstevel@tonic-gate "tick:tid %p old pri %d", t, oldpri); 1772b3383343Smishra } else if (t->t_state == TS_ONPROC && 1773b3383343Smishra t->t_pri < t->t_disp_queue->disp_maxrunpri) { 1774c97ad5cdSakolb call_cpu_surrender = B_TRUE; 1775c97ad5cdSakolb } 1776c97ad5cdSakolb } 1777c97ad5cdSakolb 1778c97ad5cdSakolb if (call_cpu_surrender) { 17797c478bd9Sstevel@tonic-gate tspp->ts_flags |= TSBACKQ; 17807c478bd9Sstevel@tonic-gate cpu_surrender(t); 17817c478bd9Sstevel@tonic-gate } 1782c97ad5cdSakolb 17837c478bd9Sstevel@tonic-gate thread_unlock_nopreempt(t); /* clock thread can't be preempted */ 17847c478bd9Sstevel@tonic-gate } 17857c478bd9Sstevel@tonic-gate 17867c478bd9Sstevel@tonic-gate 17877c478bd9Sstevel@tonic-gate /* 17887c478bd9Sstevel@tonic-gate * If thread is currently at a kernel mode priority (has slept) 17897c478bd9Sstevel@tonic-gate * we assign it the appropriate user mode priority and time quantum 17907c478bd9Sstevel@tonic-gate * here. If we are lowering the thread's priority below that of 17917c478bd9Sstevel@tonic-gate * other runnable threads we will normally set runrun via cpu_surrender() to 17927c478bd9Sstevel@tonic-gate * cause preemption. 17937c478bd9Sstevel@tonic-gate */ 17947c478bd9Sstevel@tonic-gate static void 17957c478bd9Sstevel@tonic-gate ts_trapret(kthread_t *t) 17967c478bd9Sstevel@tonic-gate { 17977c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)t->t_cldata; 17987c478bd9Sstevel@tonic-gate cpu_t *cp = CPU; 17997c478bd9Sstevel@tonic-gate pri_t old_pri = curthread->t_pri; 18007c478bd9Sstevel@tonic-gate 18017c478bd9Sstevel@tonic-gate ASSERT(THREAD_LOCK_HELD(t)); 18027c478bd9Sstevel@tonic-gate ASSERT(t == curthread); 18037c478bd9Sstevel@tonic-gate ASSERT(cp->cpu_dispthread == t); 18047c478bd9Sstevel@tonic-gate ASSERT(t->t_state == TS_ONPROC); 18057c478bd9Sstevel@tonic-gate 18067c478bd9Sstevel@tonic-gate t->t_kpri_req = 0; 18077c478bd9Sstevel@tonic-gate if (tspp->ts_dispwait > ts_dptbl[tspp->ts_umdpri].ts_maxwait) { 18087c478bd9Sstevel@tonic-gate tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_slpret; 18097c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(tspp); 18107c478bd9Sstevel@tonic-gate tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum; 18117c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate /* 18147c478bd9Sstevel@tonic-gate * If thread has blocked in the kernel (as opposed to 18157c478bd9Sstevel@tonic-gate * being merely preempted), recompute the user mode priority. 18167c478bd9Sstevel@tonic-gate */ 18177c478bd9Sstevel@tonic-gate THREAD_CHANGE_PRI(t, ts_dptbl[tspp->ts_umdpri].ts_globpri); 18187c478bd9Sstevel@tonic-gate cp->cpu_dispatch_pri = DISP_PRIO(t); 18197c478bd9Sstevel@tonic-gate ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri); 18207c478bd9Sstevel@tonic-gate tspp->ts_flags &= ~TSKPRI; 18217c478bd9Sstevel@tonic-gate 18227c478bd9Sstevel@tonic-gate if (DISP_MUST_SURRENDER(t)) 18237c478bd9Sstevel@tonic-gate cpu_surrender(t); 18247c478bd9Sstevel@tonic-gate } else if (tspp->ts_flags & TSKPRI) { 18257c478bd9Sstevel@tonic-gate /* 18267c478bd9Sstevel@tonic-gate * If thread has blocked in the kernel (as opposed to 18277c478bd9Sstevel@tonic-gate * being merely preempted), recompute the user mode priority. 18287c478bd9Sstevel@tonic-gate */ 18297c478bd9Sstevel@tonic-gate THREAD_CHANGE_PRI(t, ts_dptbl[tspp->ts_umdpri].ts_globpri); 18307c478bd9Sstevel@tonic-gate cp->cpu_dispatch_pri = DISP_PRIO(t); 18317c478bd9Sstevel@tonic-gate ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri); 18327c478bd9Sstevel@tonic-gate tspp->ts_flags &= ~TSKPRI; 18337c478bd9Sstevel@tonic-gate 18347c478bd9Sstevel@tonic-gate if (DISP_MUST_SURRENDER(t)) 18357c478bd9Sstevel@tonic-gate cpu_surrender(t); 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate 18387c478bd9Sstevel@tonic-gate /* 18397c478bd9Sstevel@tonic-gate * Swapout lwp if the swapper is waiting for this thread to 18407c478bd9Sstevel@tonic-gate * reach a safe point. 18417c478bd9Sstevel@tonic-gate */ 18427c478bd9Sstevel@tonic-gate if ((t->t_schedflag & TS_SWAPENQ) && !(tspp->ts_flags & TSIASET)) { 18437c478bd9Sstevel@tonic-gate thread_unlock(t); 18447c478bd9Sstevel@tonic-gate swapout_lwp(ttolwp(t)); 18457c478bd9Sstevel@tonic-gate thread_lock(t); 18467c478bd9Sstevel@tonic-gate } 18477c478bd9Sstevel@tonic-gate 18487c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_DISP, TR_TRAPRET, 18497c478bd9Sstevel@tonic-gate "trapret:tid %p old pri %d", t, old_pri); 18507c478bd9Sstevel@tonic-gate } 18517c478bd9Sstevel@tonic-gate 18527c478bd9Sstevel@tonic-gate 18537c478bd9Sstevel@tonic-gate /* 18547c478bd9Sstevel@tonic-gate * Update the ts_dispwait values of all time sharing threads that 18557c478bd9Sstevel@tonic-gate * are currently runnable at a user mode priority and bump the priority 18567c478bd9Sstevel@tonic-gate * if ts_dispwait exceeds ts_maxwait. Called once per second via 18577c478bd9Sstevel@tonic-gate * timeout which we reset here. 18587c478bd9Sstevel@tonic-gate * 18597c478bd9Sstevel@tonic-gate * There are several lists of time sharing threads broken up by a hash on 18607c478bd9Sstevel@tonic-gate * the thread pointer. Each list has its own lock. This avoids blocking 18617c478bd9Sstevel@tonic-gate * all ts_enterclass, ts_fork, and ts_exitclass operations while ts_update 18627c478bd9Sstevel@tonic-gate * runs. ts_update traverses each list in turn. 18637c478bd9Sstevel@tonic-gate * 18647c478bd9Sstevel@tonic-gate * If multiple threads have their priorities updated to the same value, 18657c478bd9Sstevel@tonic-gate * the system implicitly favors the one that is updated first (since it 18667c478bd9Sstevel@tonic-gate * winds up first on the run queue). To avoid this unfairness, the 18677c478bd9Sstevel@tonic-gate * traversal of threads starts at the list indicated by a marker. When 18687c478bd9Sstevel@tonic-gate * threads in more than one list have their priorities updated, the marker 18697c478bd9Sstevel@tonic-gate * is moved. This changes the order the threads will be placed on the run 18707c478bd9Sstevel@tonic-gate * queue the next time ts_update is called and preserves fairness over the 18717c478bd9Sstevel@tonic-gate * long run. The marker doesn't need to be protected by a lock since it's 18727c478bd9Sstevel@tonic-gate * only accessed by ts_update, which is inherently single-threaded (only 18737c478bd9Sstevel@tonic-gate * one instance can be running at a time). 18747c478bd9Sstevel@tonic-gate */ 18757c478bd9Sstevel@tonic-gate static void 18767c478bd9Sstevel@tonic-gate ts_update(void *arg) 18777c478bd9Sstevel@tonic-gate { 18787c478bd9Sstevel@tonic-gate int i; 18797c478bd9Sstevel@tonic-gate int new_marker = -1; 18807c478bd9Sstevel@tonic-gate static int ts_update_marker; 18817c478bd9Sstevel@tonic-gate 18827c478bd9Sstevel@tonic-gate /* 18837c478bd9Sstevel@tonic-gate * Start with the ts_update_marker list, then do the rest. 18847c478bd9Sstevel@tonic-gate */ 18857c478bd9Sstevel@tonic-gate i = ts_update_marker; 18867c478bd9Sstevel@tonic-gate do { 18877c478bd9Sstevel@tonic-gate /* 18887c478bd9Sstevel@tonic-gate * If this is the first list after the current marker to 18897c478bd9Sstevel@tonic-gate * have threads with priorities updated, advance the marker 18907c478bd9Sstevel@tonic-gate * to this list for the next time ts_update runs. 18917c478bd9Sstevel@tonic-gate */ 18927c478bd9Sstevel@tonic-gate if (ts_update_list(i) && new_marker == -1 && 18937c478bd9Sstevel@tonic-gate i != ts_update_marker) { 18947c478bd9Sstevel@tonic-gate new_marker = i; 18957c478bd9Sstevel@tonic-gate } 18967c478bd9Sstevel@tonic-gate } while ((i = TS_LIST_NEXT(i)) != ts_update_marker); 18977c478bd9Sstevel@tonic-gate 18987c478bd9Sstevel@tonic-gate /* advance marker for next ts_update call */ 18997c478bd9Sstevel@tonic-gate if (new_marker != -1) 19007c478bd9Sstevel@tonic-gate ts_update_marker = new_marker; 19017c478bd9Sstevel@tonic-gate 19027c478bd9Sstevel@tonic-gate (void) timeout(ts_update, arg, hz); 19037c478bd9Sstevel@tonic-gate } 19047c478bd9Sstevel@tonic-gate 19057c478bd9Sstevel@tonic-gate /* 19067c478bd9Sstevel@tonic-gate * Updates priority for a list of threads. Returns 1 if the priority of 19077c478bd9Sstevel@tonic-gate * one of the threads was actually updated, 0 if none were for various 19087c478bd9Sstevel@tonic-gate * reasons (thread is no longer in the TS or IA class, isn't runnable, 19097c478bd9Sstevel@tonic-gate * hasn't waited long enough, has the preemption control no-preempt bit 19107c478bd9Sstevel@tonic-gate * set, etc.) 19117c478bd9Sstevel@tonic-gate */ 19127c478bd9Sstevel@tonic-gate static int 19137c478bd9Sstevel@tonic-gate ts_update_list(int i) 19147c478bd9Sstevel@tonic-gate { 19157c478bd9Sstevel@tonic-gate tsproc_t *tspp; 19167c478bd9Sstevel@tonic-gate kthread_t *tx; 19177c478bd9Sstevel@tonic-gate int updated = 0; 19187c478bd9Sstevel@tonic-gate 19197c478bd9Sstevel@tonic-gate mutex_enter(&ts_list_lock[i]); 19207c478bd9Sstevel@tonic-gate for (tspp = ts_plisthead[i].ts_next; tspp != &ts_plisthead[i]; 19217c478bd9Sstevel@tonic-gate tspp = tspp->ts_next) { 19227c478bd9Sstevel@tonic-gate tx = tspp->ts_tp; 19237c478bd9Sstevel@tonic-gate /* 19247c478bd9Sstevel@tonic-gate * Lock the thread and verify state. 19257c478bd9Sstevel@tonic-gate */ 19267c478bd9Sstevel@tonic-gate thread_lock(tx); 19277c478bd9Sstevel@tonic-gate /* 19287c478bd9Sstevel@tonic-gate * Skip the thread if it is no longer in the TS (or IA) class. 19297c478bd9Sstevel@tonic-gate */ 19307c478bd9Sstevel@tonic-gate if (tx->t_clfuncs != &ts_classfuncs.thread && 19317c478bd9Sstevel@tonic-gate tx->t_clfuncs != &ia_classfuncs.thread) 19327c478bd9Sstevel@tonic-gate goto next; 19337c478bd9Sstevel@tonic-gate tspp->ts_dispwait++; 19347c478bd9Sstevel@tonic-gate if ((tspp->ts_flags & TSKPRI) != 0) 19357c478bd9Sstevel@tonic-gate goto next; 19367c478bd9Sstevel@tonic-gate if (tspp->ts_dispwait <= ts_dptbl[tspp->ts_umdpri].ts_maxwait) 19377c478bd9Sstevel@tonic-gate goto next; 19387c478bd9Sstevel@tonic-gate if (tx->t_schedctl && schedctl_get_nopreempt(tx)) 19397c478bd9Sstevel@tonic-gate goto next; 1940c97ad5cdSakolb if (tx->t_state != TS_RUN && tx->t_state != TS_WAIT && 1941c97ad5cdSakolb (tx->t_state != TS_SLEEP || !ts_sleep_promote)) { 19427c478bd9Sstevel@tonic-gate /* make next syscall/trap do CL_TRAPRET */ 19437c478bd9Sstevel@tonic-gate tx->t_trapret = 1; 19447c478bd9Sstevel@tonic-gate aston(tx); 19457c478bd9Sstevel@tonic-gate goto next; 19467c478bd9Sstevel@tonic-gate } 19477c478bd9Sstevel@tonic-gate tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_lwait; 19487c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(tspp); 19497c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 19507c478bd9Sstevel@tonic-gate updated = 1; 19517c478bd9Sstevel@tonic-gate 19527c478bd9Sstevel@tonic-gate /* 19537c478bd9Sstevel@tonic-gate * Only dequeue it if needs to move; otherwise it should 19547c478bd9Sstevel@tonic-gate * just round-robin here. 19557c478bd9Sstevel@tonic-gate */ 19567c478bd9Sstevel@tonic-gate if (tx->t_pri != ts_dptbl[tspp->ts_umdpri].ts_globpri) { 19577c478bd9Sstevel@tonic-gate pri_t oldpri = tx->t_pri; 19587c478bd9Sstevel@tonic-gate ts_change_priority(tx, tspp); 19597c478bd9Sstevel@tonic-gate TRACE_2(TR_FAC_DISP, TR_UPDATE, 19607c478bd9Sstevel@tonic-gate "update:tid %p old pri %d", tx, oldpri); 19617c478bd9Sstevel@tonic-gate } 19627c478bd9Sstevel@tonic-gate next: 19637c478bd9Sstevel@tonic-gate thread_unlock(tx); 19647c478bd9Sstevel@tonic-gate } 19657c478bd9Sstevel@tonic-gate mutex_exit(&ts_list_lock[i]); 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate return (updated); 19687c478bd9Sstevel@tonic-gate } 19697c478bd9Sstevel@tonic-gate 19707c478bd9Sstevel@tonic-gate /* 19717c478bd9Sstevel@tonic-gate * Processes waking up go to the back of their queue. We don't 19727c478bd9Sstevel@tonic-gate * need to assign a time quantum here because thread is still 19737c478bd9Sstevel@tonic-gate * at a kernel mode priority and the time slicing is not done 19747c478bd9Sstevel@tonic-gate * for threads running in the kernel after sleeping. The proper 19757c478bd9Sstevel@tonic-gate * time quantum will be assigned by ts_trapret before the thread 19767c478bd9Sstevel@tonic-gate * returns to user mode. 19777c478bd9Sstevel@tonic-gate */ 19787c478bd9Sstevel@tonic-gate static void 19797c478bd9Sstevel@tonic-gate ts_wakeup(kthread_t *t) 19807c478bd9Sstevel@tonic-gate { 19817c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)(t->t_cldata); 19827c478bd9Sstevel@tonic-gate 19837c478bd9Sstevel@tonic-gate ASSERT(THREAD_LOCK_HELD(t)); 19847c478bd9Sstevel@tonic-gate 1985d3d50737SRafael Vanoni t->t_stime = ddi_get_lbolt(); /* time stamp for the swapper */ 19867c478bd9Sstevel@tonic-gate 19877c478bd9Sstevel@tonic-gate if (tspp->ts_flags & TSKPRI) { 19887c478bd9Sstevel@tonic-gate tspp->ts_flags &= ~TSBACKQ; 19897c478bd9Sstevel@tonic-gate if (tspp->ts_flags & TSIASET) 19907c478bd9Sstevel@tonic-gate setfrontdq(t); 19917c478bd9Sstevel@tonic-gate else 19927c478bd9Sstevel@tonic-gate setbackdq(t); 19937c478bd9Sstevel@tonic-gate } else if (t->t_kpri_req) { 19947c478bd9Sstevel@tonic-gate /* 19957c478bd9Sstevel@tonic-gate * Give thread a priority boost if we were asked. 19967c478bd9Sstevel@tonic-gate */ 19977c478bd9Sstevel@tonic-gate tspp->ts_flags |= TSKPRI; 19987c478bd9Sstevel@tonic-gate THREAD_CHANGE_PRI(t, ts_kmdpris[0]); 19997c478bd9Sstevel@tonic-gate setbackdq(t); 20007c478bd9Sstevel@tonic-gate t->t_trapret = 1; /* so that ts_trapret will run */ 20017c478bd9Sstevel@tonic-gate aston(t); 20027c478bd9Sstevel@tonic-gate } else { 20037c478bd9Sstevel@tonic-gate if (tspp->ts_dispwait > ts_dptbl[tspp->ts_umdpri].ts_maxwait) { 20047c478bd9Sstevel@tonic-gate tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_slpret; 20057c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(tspp); 20067c478bd9Sstevel@tonic-gate tspp->ts_timeleft = 20077c478bd9Sstevel@tonic-gate ts_dptbl[tspp->ts_cpupri].ts_quantum; 20087c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 20097c478bd9Sstevel@tonic-gate THREAD_CHANGE_PRI(t, 20107c478bd9Sstevel@tonic-gate ts_dptbl[tspp->ts_umdpri].ts_globpri); 20117c478bd9Sstevel@tonic-gate ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri); 20127c478bd9Sstevel@tonic-gate } 20137c478bd9Sstevel@tonic-gate 20147c478bd9Sstevel@tonic-gate tspp->ts_flags &= ~TSBACKQ; 20157c478bd9Sstevel@tonic-gate 20167c478bd9Sstevel@tonic-gate if (tspp->ts_flags & TSIA) { 20177c478bd9Sstevel@tonic-gate if (tspp->ts_flags & TSIASET) 20187c478bd9Sstevel@tonic-gate setfrontdq(t); 20197c478bd9Sstevel@tonic-gate else 20207c478bd9Sstevel@tonic-gate setbackdq(t); 20217c478bd9Sstevel@tonic-gate } else { 2022d3d50737SRafael Vanoni if (t->t_disp_time != ddi_get_lbolt()) 20237c478bd9Sstevel@tonic-gate setbackdq(t); 20247c478bd9Sstevel@tonic-gate else 20257c478bd9Sstevel@tonic-gate setfrontdq(t); 20267c478bd9Sstevel@tonic-gate } 20277c478bd9Sstevel@tonic-gate } 20287c478bd9Sstevel@tonic-gate } 20297c478bd9Sstevel@tonic-gate 20307c478bd9Sstevel@tonic-gate 20317c478bd9Sstevel@tonic-gate /* 20327c478bd9Sstevel@tonic-gate * When a thread yields, put it on the back of the run queue. 20337c478bd9Sstevel@tonic-gate */ 20347c478bd9Sstevel@tonic-gate static void 20357c478bd9Sstevel@tonic-gate ts_yield(kthread_t *t) 20367c478bd9Sstevel@tonic-gate { 20377c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)(t->t_cldata); 20387c478bd9Sstevel@tonic-gate 20397c478bd9Sstevel@tonic-gate ASSERT(t == curthread); 20407c478bd9Sstevel@tonic-gate ASSERT(THREAD_LOCK_HELD(t)); 20417c478bd9Sstevel@tonic-gate 20427c478bd9Sstevel@tonic-gate /* 2043c97ad5cdSakolb * Collect CPU usage spent before yielding 2044c97ad5cdSakolb */ 20458c34bbb7Sakolb (void) CPUCAPS_CHARGE(t, &tspp->ts_caps, CPUCAPS_CHARGE_ENFORCE); 2046c97ad5cdSakolb 2047c97ad5cdSakolb /* 20487c478bd9Sstevel@tonic-gate * Clear the preemption control "yield" bit since the user is 20497c478bd9Sstevel@tonic-gate * doing a yield. 20507c478bd9Sstevel@tonic-gate */ 20517c478bd9Sstevel@tonic-gate if (t->t_schedctl) 20527c478bd9Sstevel@tonic-gate schedctl_set_yield(t, 0); 20539ac8606fSraf /* 20549ac8606fSraf * If ts_preempt() artifically increased the thread's priority 20559ac8606fSraf * to avoid preemption, restore the original priority now. 20569ac8606fSraf */ 20579ac8606fSraf if (tspp->ts_flags & TSRESTORE) { 20589ac8606fSraf THREAD_CHANGE_PRI(t, tspp->ts_scpri); 20599ac8606fSraf tspp->ts_flags &= ~TSRESTORE; 20609ac8606fSraf } 20617c478bd9Sstevel@tonic-gate if (tspp->ts_timeleft <= 0) { 20627c478bd9Sstevel@tonic-gate /* 20637c478bd9Sstevel@tonic-gate * Time slice was artificially extended to avoid 20647c478bd9Sstevel@tonic-gate * preemption, so pretend we're preempting it now. 20657c478bd9Sstevel@tonic-gate */ 20667c478bd9Sstevel@tonic-gate DTRACE_SCHED1(schedctl__yield, int, -tspp->ts_timeleft); 20677c478bd9Sstevel@tonic-gate tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_tqexp; 20687c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(tspp); 20697c478bd9Sstevel@tonic-gate tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum; 20707c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 20717c478bd9Sstevel@tonic-gate THREAD_CHANGE_PRI(t, ts_dptbl[tspp->ts_umdpri].ts_globpri); 20727c478bd9Sstevel@tonic-gate ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri); 20737c478bd9Sstevel@tonic-gate } 20747c478bd9Sstevel@tonic-gate tspp->ts_flags &= ~TSBACKQ; 20757c478bd9Sstevel@tonic-gate setbackdq(t); 20767c478bd9Sstevel@tonic-gate } 20777c478bd9Sstevel@tonic-gate 20787c478bd9Sstevel@tonic-gate 20797c478bd9Sstevel@tonic-gate /* 20807c478bd9Sstevel@tonic-gate * Increment the nice value of the specified thread by incr and 20817c478bd9Sstevel@tonic-gate * return the new value in *retvalp. 20827c478bd9Sstevel@tonic-gate */ 20837c478bd9Sstevel@tonic-gate static int 20847c478bd9Sstevel@tonic-gate ts_donice(kthread_t *t, cred_t *cr, int incr, int *retvalp) 20857c478bd9Sstevel@tonic-gate { 20867c478bd9Sstevel@tonic-gate int newnice; 20877c478bd9Sstevel@tonic-gate tsproc_t *tspp = (tsproc_t *)(t->t_cldata); 20887c478bd9Sstevel@tonic-gate tsparms_t tsparms; 20897c478bd9Sstevel@tonic-gate 20907c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock)); 20917c478bd9Sstevel@tonic-gate 20927c478bd9Sstevel@tonic-gate /* If there's no change to priority, just return current setting */ 20937c478bd9Sstevel@tonic-gate if (incr == 0) { 20947c478bd9Sstevel@tonic-gate if (retvalp) { 20957c478bd9Sstevel@tonic-gate *retvalp = tspp->ts_nice - NZERO; 20967c478bd9Sstevel@tonic-gate } 20977c478bd9Sstevel@tonic-gate return (0); 20987c478bd9Sstevel@tonic-gate } 20997c478bd9Sstevel@tonic-gate 21007c478bd9Sstevel@tonic-gate if ((incr < 0 || incr > 2 * NZERO) && 2101*24d819e6SJerry Jelinek secpolicy_raisepriority(cr) != 0) 21027c478bd9Sstevel@tonic-gate return (EPERM); 21037c478bd9Sstevel@tonic-gate 21047c478bd9Sstevel@tonic-gate /* 21057c478bd9Sstevel@tonic-gate * Specifying a nice increment greater than the upper limit of 21067c478bd9Sstevel@tonic-gate * 2 * NZERO - 1 will result in the thread's nice value being 21077c478bd9Sstevel@tonic-gate * set to the upper limit. We check for this before computing 21087c478bd9Sstevel@tonic-gate * the new value because otherwise we could get overflow 21097c478bd9Sstevel@tonic-gate * if a privileged process specified some ridiculous increment. 21107c478bd9Sstevel@tonic-gate */ 21117c478bd9Sstevel@tonic-gate if (incr > 2 * NZERO - 1) 21127c478bd9Sstevel@tonic-gate incr = 2 * NZERO - 1; 21137c478bd9Sstevel@tonic-gate 21147c478bd9Sstevel@tonic-gate newnice = tspp->ts_nice + incr; 21157c478bd9Sstevel@tonic-gate if (newnice >= 2 * NZERO) 21167c478bd9Sstevel@tonic-gate newnice = 2 * NZERO - 1; 21177c478bd9Sstevel@tonic-gate else if (newnice < 0) 21187c478bd9Sstevel@tonic-gate newnice = 0; 21197c478bd9Sstevel@tonic-gate 21207c478bd9Sstevel@tonic-gate tsparms.ts_uprilim = tsparms.ts_upri = 21217c478bd9Sstevel@tonic-gate -((newnice - NZERO) * ts_maxupri) / NZERO; 21227c478bd9Sstevel@tonic-gate /* 21237c478bd9Sstevel@tonic-gate * Reset the uprilim and upri values of the thread. 21247c478bd9Sstevel@tonic-gate * Call ts_parmsset even if thread is interactive since we're 21257c478bd9Sstevel@tonic-gate * not changing mode. 21267c478bd9Sstevel@tonic-gate */ 21277c478bd9Sstevel@tonic-gate (void) ts_parmsset(t, (void *)&tsparms, (id_t)0, (cred_t *)NULL); 21287c478bd9Sstevel@tonic-gate 21297c478bd9Sstevel@tonic-gate /* 21307c478bd9Sstevel@tonic-gate * Although ts_parmsset already reset ts_nice it may 21317c478bd9Sstevel@tonic-gate * not have been set to precisely the value calculated above 21327c478bd9Sstevel@tonic-gate * because ts_parmsset determines the nice value from the 21337c478bd9Sstevel@tonic-gate * user priority and we may have truncated during the integer 21347c478bd9Sstevel@tonic-gate * conversion from nice value to user priority and back. 21357c478bd9Sstevel@tonic-gate * We reset ts_nice to the value we calculated above. 21367c478bd9Sstevel@tonic-gate */ 21377c478bd9Sstevel@tonic-gate tspp->ts_nice = (char)newnice; 21387c478bd9Sstevel@tonic-gate 21397c478bd9Sstevel@tonic-gate if (retvalp) 21407c478bd9Sstevel@tonic-gate *retvalp = newnice - NZERO; 21417c478bd9Sstevel@tonic-gate return (0); 21427c478bd9Sstevel@tonic-gate } 21437c478bd9Sstevel@tonic-gate 2144d4204c85Sraf /* 2145d4204c85Sraf * Increment the priority of the specified thread by incr and 2146d4204c85Sraf * return the new value in *retvalp. 2147d4204c85Sraf */ 2148d4204c85Sraf static int 2149d4204c85Sraf ts_doprio(kthread_t *t, cred_t *cr, int incr, int *retvalp) 2150d4204c85Sraf { 2151d4204c85Sraf int newpri; 2152d4204c85Sraf tsproc_t *tspp = (tsproc_t *)(t->t_cldata); 2153d4204c85Sraf tsparms_t tsparms; 2154d4204c85Sraf 2155d4204c85Sraf ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock)); 2156d4204c85Sraf 2157d4204c85Sraf /* If there's no change to the priority, just return current setting */ 2158d4204c85Sraf if (incr == 0) { 2159d4204c85Sraf *retvalp = tspp->ts_upri; 2160d4204c85Sraf return (0); 2161d4204c85Sraf } 2162d4204c85Sraf 2163d4204c85Sraf newpri = tspp->ts_upri + incr; 2164d4204c85Sraf if (newpri > ts_maxupri || newpri < -ts_maxupri) 2165d4204c85Sraf return (EINVAL); 2166d4204c85Sraf 2167d4204c85Sraf *retvalp = newpri; 2168d4204c85Sraf tsparms.ts_uprilim = tsparms.ts_upri = newpri; 2169d4204c85Sraf /* 2170d4204c85Sraf * Reset the uprilim and upri values of the thread. 2171d4204c85Sraf * Call ts_parmsset even if thread is interactive since we're 2172d4204c85Sraf * not changing mode. 2173d4204c85Sraf */ 2174d4204c85Sraf return (ts_parmsset(t, &tsparms, 0, cr)); 2175d4204c85Sraf } 21767c478bd9Sstevel@tonic-gate 21777c478bd9Sstevel@tonic-gate /* 21787c478bd9Sstevel@tonic-gate * ia_set_process_group marks foreground processes as interactive 21797c478bd9Sstevel@tonic-gate * and background processes as non-interactive iff the session 21807c478bd9Sstevel@tonic-gate * leader is interactive. This routine is called from two places: 21817c478bd9Sstevel@tonic-gate * strioctl:SPGRP when a new process group gets 21827c478bd9Sstevel@tonic-gate * control of the tty. 21837c478bd9Sstevel@tonic-gate * ia_parmsset-when the process in question is a session leader. 21847c478bd9Sstevel@tonic-gate * ia_set_process_group assumes that pidlock is held by the caller, 21857c478bd9Sstevel@tonic-gate * either strioctl or priocntlsys. If the caller is priocntlsys 21867c478bd9Sstevel@tonic-gate * (via ia_parmsset) then the p_lock of the session leader is held 21877c478bd9Sstevel@tonic-gate * and the code needs to be careful about acquiring other p_locks. 21887c478bd9Sstevel@tonic-gate */ 21897c478bd9Sstevel@tonic-gate static void 21907c478bd9Sstevel@tonic-gate ia_set_process_group(pid_t sid, pid_t bg_pgid, pid_t fg_pgid) 21917c478bd9Sstevel@tonic-gate { 21927c478bd9Sstevel@tonic-gate proc_t *leader, *fg, *bg; 21937c478bd9Sstevel@tonic-gate tsproc_t *tspp; 21947c478bd9Sstevel@tonic-gate kthread_t *tx; 21957c478bd9Sstevel@tonic-gate int plocked = 0; 21967c478bd9Sstevel@tonic-gate 21977c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&pidlock)); 21987c478bd9Sstevel@tonic-gate 21997c478bd9Sstevel@tonic-gate /* 22007c478bd9Sstevel@tonic-gate * see if the session leader is interactive AND 22017c478bd9Sstevel@tonic-gate * if it is currently "on" AND controlling a tty 22027c478bd9Sstevel@tonic-gate * iff it is then make the processes in the foreground 22037c478bd9Sstevel@tonic-gate * group interactive and the processes in the background 22047c478bd9Sstevel@tonic-gate * group non-interactive. 22057c478bd9Sstevel@tonic-gate */ 22067c478bd9Sstevel@tonic-gate if ((leader = (proc_t *)prfind(sid)) == NULL) { 22077c478bd9Sstevel@tonic-gate return; 22087c478bd9Sstevel@tonic-gate } 22097c478bd9Sstevel@tonic-gate if (leader->p_stat == SIDL) { 22107c478bd9Sstevel@tonic-gate return; 22117c478bd9Sstevel@tonic-gate } 22127c478bd9Sstevel@tonic-gate if ((tx = proctot(leader)) == NULL) { 22137c478bd9Sstevel@tonic-gate return; 22147c478bd9Sstevel@tonic-gate } 22157c478bd9Sstevel@tonic-gate /* 22167c478bd9Sstevel@tonic-gate * XXX do all the threads in the leader 22177c478bd9Sstevel@tonic-gate */ 22187c478bd9Sstevel@tonic-gate if (tx->t_cid != ia_cid) { 22197c478bd9Sstevel@tonic-gate return; 22207c478bd9Sstevel@tonic-gate } 22217c478bd9Sstevel@tonic-gate tspp = tx->t_cldata; 22227c478bd9Sstevel@tonic-gate /* 22237c478bd9Sstevel@tonic-gate * session leaders that are not interactive need not have 22247c478bd9Sstevel@tonic-gate * any processing done for them. They are typically shells 22257c478bd9Sstevel@tonic-gate * that do not have focus and are changing the process group 22267c478bd9Sstevel@tonic-gate * attatched to the tty, e.g. a process that is exiting 22277c478bd9Sstevel@tonic-gate */ 22289acbbeafSnn35248 mutex_enter(&leader->p_sessp->s_lock); 22297c478bd9Sstevel@tonic-gate if (!(tspp->ts_flags & TSIASET) || 22307c478bd9Sstevel@tonic-gate (leader->p_sessp->s_vp == NULL) || 22317c478bd9Sstevel@tonic-gate (leader->p_sessp->s_vp->v_stream == NULL)) { 22329acbbeafSnn35248 mutex_exit(&leader->p_sessp->s_lock); 22337c478bd9Sstevel@tonic-gate return; 22347c478bd9Sstevel@tonic-gate } 22359acbbeafSnn35248 mutex_exit(&leader->p_sessp->s_lock); 22367c478bd9Sstevel@tonic-gate 22377c478bd9Sstevel@tonic-gate /* 22387c478bd9Sstevel@tonic-gate * If we're already holding the leader's p_lock, we should use 22397c478bd9Sstevel@tonic-gate * mutex_tryenter instead of mutex_enter to avoid deadlocks from 22407c478bd9Sstevel@tonic-gate * lock ordering violations. 22417c478bd9Sstevel@tonic-gate */ 22427c478bd9Sstevel@tonic-gate if (mutex_owned(&leader->p_lock)) 22437c478bd9Sstevel@tonic-gate plocked = 1; 22447c478bd9Sstevel@tonic-gate 22457c478bd9Sstevel@tonic-gate if (fg_pgid == 0) 22467c478bd9Sstevel@tonic-gate goto skip; 22477c478bd9Sstevel@tonic-gate /* 22487c478bd9Sstevel@tonic-gate * now look for all processes in the foreground group and 22497c478bd9Sstevel@tonic-gate * make them interactive 22507c478bd9Sstevel@tonic-gate */ 22517c478bd9Sstevel@tonic-gate for (fg = (proc_t *)pgfind(fg_pgid); fg != NULL; fg = fg->p_pglink) { 22527c478bd9Sstevel@tonic-gate /* 22537c478bd9Sstevel@tonic-gate * if the process is SIDL it's begin forked, ignore it 22547c478bd9Sstevel@tonic-gate */ 22557c478bd9Sstevel@tonic-gate if (fg->p_stat == SIDL) { 22567c478bd9Sstevel@tonic-gate continue; 22577c478bd9Sstevel@tonic-gate } 22587c478bd9Sstevel@tonic-gate /* 22597c478bd9Sstevel@tonic-gate * sesssion leaders must be turned on/off explicitly 22607c478bd9Sstevel@tonic-gate * not implicitly as happens to other members of 22617c478bd9Sstevel@tonic-gate * the process group. 22627c478bd9Sstevel@tonic-gate */ 22637c478bd9Sstevel@tonic-gate if (fg->p_pid == fg->p_sessp->s_sid) { 22647c478bd9Sstevel@tonic-gate continue; 22657c478bd9Sstevel@tonic-gate } 22667c478bd9Sstevel@tonic-gate 22677c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_IA, TR_GROUP_ON, 22687c478bd9Sstevel@tonic-gate "group on:proc %p", fg); 22697c478bd9Sstevel@tonic-gate 22707c478bd9Sstevel@tonic-gate if (plocked) { 22717c478bd9Sstevel@tonic-gate if (mutex_tryenter(&fg->p_lock) == 0) 22727c478bd9Sstevel@tonic-gate continue; 22737c478bd9Sstevel@tonic-gate } else { 22747c478bd9Sstevel@tonic-gate mutex_enter(&fg->p_lock); 22757c478bd9Sstevel@tonic-gate } 22767c478bd9Sstevel@tonic-gate 22777c478bd9Sstevel@tonic-gate if ((tx = proctot(fg)) == NULL) { 22787c478bd9Sstevel@tonic-gate mutex_exit(&fg->p_lock); 22797c478bd9Sstevel@tonic-gate continue; 22807c478bd9Sstevel@tonic-gate } 22817c478bd9Sstevel@tonic-gate do { 22827c478bd9Sstevel@tonic-gate thread_lock(tx); 22837c478bd9Sstevel@tonic-gate /* 22847c478bd9Sstevel@tonic-gate * if this thread is not interactive continue 22857c478bd9Sstevel@tonic-gate */ 22867c478bd9Sstevel@tonic-gate if (tx->t_cid != ia_cid) { 22877c478bd9Sstevel@tonic-gate thread_unlock(tx); 22887c478bd9Sstevel@tonic-gate continue; 22897c478bd9Sstevel@tonic-gate } 22907c478bd9Sstevel@tonic-gate tspp = tx->t_cldata; 22917c478bd9Sstevel@tonic-gate tspp->ts_flags |= TSIASET; 22927c478bd9Sstevel@tonic-gate tspp->ts_boost = ia_boost; 22937c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(tspp); 22947c478bd9Sstevel@tonic-gate if ((tspp->ts_flags & TSKPRI) != 0) { 22957c478bd9Sstevel@tonic-gate thread_unlock(tx); 22967c478bd9Sstevel@tonic-gate continue; 22977c478bd9Sstevel@tonic-gate } 22987c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 22997c478bd9Sstevel@tonic-gate ts_change_priority(tx, tspp); 23007c478bd9Sstevel@tonic-gate thread_unlock(tx); 23017c478bd9Sstevel@tonic-gate } while ((tx = tx->t_forw) != fg->p_tlist); 23027c478bd9Sstevel@tonic-gate mutex_exit(&fg->p_lock); 23037c478bd9Sstevel@tonic-gate } 23047c478bd9Sstevel@tonic-gate skip: 23057c478bd9Sstevel@tonic-gate if (bg_pgid == 0) 23067c478bd9Sstevel@tonic-gate return; 23077c478bd9Sstevel@tonic-gate for (bg = (proc_t *)pgfind(bg_pgid); bg != NULL; bg = bg->p_pglink) { 23087c478bd9Sstevel@tonic-gate if (bg->p_stat == SIDL) { 23097c478bd9Sstevel@tonic-gate continue; 23107c478bd9Sstevel@tonic-gate } 23117c478bd9Sstevel@tonic-gate /* 23127c478bd9Sstevel@tonic-gate * sesssion leaders must be turned off explicitly 23137c478bd9Sstevel@tonic-gate * not implicitly as happens to other members of 23147c478bd9Sstevel@tonic-gate * the process group. 23157c478bd9Sstevel@tonic-gate */ 23167c478bd9Sstevel@tonic-gate if (bg->p_pid == bg->p_sessp->s_sid) { 23177c478bd9Sstevel@tonic-gate continue; 23187c478bd9Sstevel@tonic-gate } 23197c478bd9Sstevel@tonic-gate 23207c478bd9Sstevel@tonic-gate TRACE_1(TR_FAC_IA, TR_GROUP_OFF, 23217c478bd9Sstevel@tonic-gate "group off:proc %p", bg); 23227c478bd9Sstevel@tonic-gate 23237c478bd9Sstevel@tonic-gate if (plocked) { 23247c478bd9Sstevel@tonic-gate if (mutex_tryenter(&bg->p_lock) == 0) 23257c478bd9Sstevel@tonic-gate continue; 23267c478bd9Sstevel@tonic-gate } else { 23277c478bd9Sstevel@tonic-gate mutex_enter(&bg->p_lock); 23287c478bd9Sstevel@tonic-gate } 23297c478bd9Sstevel@tonic-gate 23307c478bd9Sstevel@tonic-gate if ((tx = proctot(bg)) == NULL) { 23317c478bd9Sstevel@tonic-gate mutex_exit(&bg->p_lock); 23327c478bd9Sstevel@tonic-gate continue; 23337c478bd9Sstevel@tonic-gate } 23347c478bd9Sstevel@tonic-gate do { 23357c478bd9Sstevel@tonic-gate thread_lock(tx); 23367c478bd9Sstevel@tonic-gate /* 23377c478bd9Sstevel@tonic-gate * if this thread is not interactive continue 23387c478bd9Sstevel@tonic-gate */ 23397c478bd9Sstevel@tonic-gate if (tx->t_cid != ia_cid) { 23407c478bd9Sstevel@tonic-gate thread_unlock(tx); 23417c478bd9Sstevel@tonic-gate continue; 23427c478bd9Sstevel@tonic-gate } 23437c478bd9Sstevel@tonic-gate tspp = tx->t_cldata; 23447c478bd9Sstevel@tonic-gate tspp->ts_flags &= ~TSIASET; 23457c478bd9Sstevel@tonic-gate tspp->ts_boost = -ia_boost; 23467c478bd9Sstevel@tonic-gate TS_NEWUMDPRI(tspp); 23477c478bd9Sstevel@tonic-gate if ((tspp->ts_flags & TSKPRI) != 0) { 23487c478bd9Sstevel@tonic-gate thread_unlock(tx); 23497c478bd9Sstevel@tonic-gate continue; 23507c478bd9Sstevel@tonic-gate } 23517c478bd9Sstevel@tonic-gate 23527c478bd9Sstevel@tonic-gate tspp->ts_dispwait = 0; 23537c478bd9Sstevel@tonic-gate ts_change_priority(tx, tspp); 23547c478bd9Sstevel@tonic-gate thread_unlock(tx); 23557c478bd9Sstevel@tonic-gate } while ((tx = tx->t_forw) != bg->p_tlist); 23567c478bd9Sstevel@tonic-gate mutex_exit(&bg->p_lock); 23577c478bd9Sstevel@tonic-gate } 23587c478bd9Sstevel@tonic-gate } 23597c478bd9Sstevel@tonic-gate 23607c478bd9Sstevel@tonic-gate 23617c478bd9Sstevel@tonic-gate static void 23627c478bd9Sstevel@tonic-gate ts_change_priority(kthread_t *t, tsproc_t *tspp) 23637c478bd9Sstevel@tonic-gate { 23647c478bd9Sstevel@tonic-gate pri_t new_pri; 23657c478bd9Sstevel@tonic-gate 23667c478bd9Sstevel@tonic-gate ASSERT(THREAD_LOCK_HELD(t)); 23677c478bd9Sstevel@tonic-gate new_pri = ts_dptbl[tspp->ts_umdpri].ts_globpri; 23687c478bd9Sstevel@tonic-gate ASSERT(new_pri >= 0 && new_pri <= ts_maxglobpri); 23699ac8606fSraf tspp->ts_flags &= ~TSRESTORE; 2370d4204c85Sraf t->t_cpri = tspp->ts_upri; 23717c478bd9Sstevel@tonic-gate if (t == curthread || t->t_state == TS_ONPROC) { 23727c478bd9Sstevel@tonic-gate /* curthread is always onproc */ 23737c478bd9Sstevel@tonic-gate cpu_t *cp = t->t_disp_queue->disp_cpu; 23747c478bd9Sstevel@tonic-gate THREAD_CHANGE_PRI(t, new_pri); 23757c478bd9Sstevel@tonic-gate if (t == cp->cpu_dispthread) 23767c478bd9Sstevel@tonic-gate cp->cpu_dispatch_pri = DISP_PRIO(t); 23777c478bd9Sstevel@tonic-gate if (DISP_MUST_SURRENDER(t)) { 23787c478bd9Sstevel@tonic-gate tspp->ts_flags |= TSBACKQ; 23797c478bd9Sstevel@tonic-gate cpu_surrender(t); 23807c478bd9Sstevel@tonic-gate } else { 23817c478bd9Sstevel@tonic-gate tspp->ts_timeleft = 23827c478bd9Sstevel@tonic-gate ts_dptbl[tspp->ts_cpupri].ts_quantum; 23837c478bd9Sstevel@tonic-gate } 23847c478bd9Sstevel@tonic-gate } else { 23857c478bd9Sstevel@tonic-gate int frontq; 23867c478bd9Sstevel@tonic-gate 23877c478bd9Sstevel@tonic-gate frontq = (tspp->ts_flags & TSIASET) != 0; 23887c478bd9Sstevel@tonic-gate /* 23897c478bd9Sstevel@tonic-gate * When the priority of a thread is changed, 23907c478bd9Sstevel@tonic-gate * it may be necessary to adjust its position 23917c478bd9Sstevel@tonic-gate * on a sleep queue or dispatch queue. 23927c478bd9Sstevel@tonic-gate * The function thread_change_pri accomplishes 23937c478bd9Sstevel@tonic-gate * this. 23947c478bd9Sstevel@tonic-gate */ 23957c478bd9Sstevel@tonic-gate if (thread_change_pri(t, new_pri, frontq)) { 23967c478bd9Sstevel@tonic-gate /* 23977c478bd9Sstevel@tonic-gate * The thread was on a run queue. Reset 23987c478bd9Sstevel@tonic-gate * its CPU timeleft from the quantum 23997c478bd9Sstevel@tonic-gate * associated with the new priority. 24007c478bd9Sstevel@tonic-gate */ 24017c478bd9Sstevel@tonic-gate tspp->ts_timeleft = 24027c478bd9Sstevel@tonic-gate ts_dptbl[tspp->ts_cpupri].ts_quantum; 24037c478bd9Sstevel@tonic-gate } else { 24047c478bd9Sstevel@tonic-gate tspp->ts_flags |= TSBACKQ; 24057c478bd9Sstevel@tonic-gate } 24067c478bd9Sstevel@tonic-gate } 24077c478bd9Sstevel@tonic-gate } 24087c478bd9Sstevel@tonic-gate 24097c478bd9Sstevel@tonic-gate static int 24107c478bd9Sstevel@tonic-gate ts_alloc(void **p, int flag) 24117c478bd9Sstevel@tonic-gate { 24127c478bd9Sstevel@tonic-gate void *bufp; 24137c478bd9Sstevel@tonic-gate bufp = kmem_alloc(sizeof (tsproc_t), flag); 24147c478bd9Sstevel@tonic-gate if (bufp == NULL) { 24157c478bd9Sstevel@tonic-gate return (ENOMEM); 24167c478bd9Sstevel@tonic-gate } else { 24177c478bd9Sstevel@tonic-gate *p = bufp; 24187c478bd9Sstevel@tonic-gate return (0); 24197c478bd9Sstevel@tonic-gate } 24207c478bd9Sstevel@tonic-gate } 24217c478bd9Sstevel@tonic-gate 24227c478bd9Sstevel@tonic-gate static void 24237c478bd9Sstevel@tonic-gate ts_free(void *bufp) 24247c478bd9Sstevel@tonic-gate { 24257c478bd9Sstevel@tonic-gate if (bufp) 24267c478bd9Sstevel@tonic-gate kmem_free(bufp, sizeof (tsproc_t)); 24277c478bd9Sstevel@tonic-gate } 2428