#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysmacros.h>
#include <sys/cred.h>
#include <sys/proc.h>
#include <sys/session.h>
#include <sys/strsubr.h>
#include <sys/signal.h>
#include <sys/user.h>
#include <sys/priocntl.h>
#include <sys/class.h>
#include <sys/disp.h>
#include <sys/procset.h>
#include <sys/debug.h>
#include <sys/ts.h>
#include <sys/tspriocntl.h>
#include <sys/iapriocntl.h>
#include <sys/kmem.h>
#include <sys/errno.h>
#include <sys/cpuvar.h>
#include <sys/systm.h>
#include <sys/vtrace.h>
#include <sys/vmsystm.h>
#include <sys/schedctl.h>
#include <sys/atomic.h>
#include <sys/policy.h>
#include <sys/sdt.h>
#include <sys/cpupart.h>
#include <vm/rm.h>
#include <vm/seg_kmem.h>
#include <sys/modctl.h>
#include <sys/cpucaps.h>
static pri_t ts_init(id_t, int, classfuncs_t **);
static struct sclass csw = {
"TS",
ts_init,
0
};
static struct modlsched modlsched = {
&mod_schedops, "time sharing sched class", &csw
};
static struct modlinkage modlinkage = {
MODREV_1, (void *)&modlsched, NULL
};
int
_init()
{
return (mod_install(&modlinkage));
}
int
_fini()
{
return (EBUSY);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
#define TSMAXUPRI 60
pri_t ts_maxupri = TSMAXUPRI;
pri_t ts_maxumdpri;
pri_t ia_maxupri = IAMAXUPRI;
pri_t ia_boost = IA_BOOST;
tsdpent_t *ts_dptbl;
pri_t *ts_kmdpris;
static id_t ia_cid;
int ts_sleep_promote = 1;
#define tsmedumdpri (ts_maxumdpri >> 1)
#define TS_NEWUMDPRI(tspp) \
{ \
pri_t pri; \
pri = (tspp)->ts_cpupri + (tspp)->ts_upri + (tspp)->ts_boost; \
if (pri > ts_maxumdpri) \
(tspp)->ts_umdpri = ts_maxumdpri; \
else if (pri < 0) \
(tspp)->ts_umdpri = 0; \
else \
(tspp)->ts_umdpri = pri; \
ASSERT((tspp)->ts_umdpri >= 0 && (tspp)->ts_umdpri <= ts_maxumdpri); \
}
#define TS_LISTS 16
#define TS_LIST_HASH(tp) (((uintptr_t)(tp) >> 9) & (TS_LISTS - 1))
#define TS_LIST_NEXT(i) (((i) + 1) & (TS_LISTS - 1))
#define TS_LIST_INSERT(tspp) \
{ \
int index = TS_LIST_HASH(tspp->ts_tp); \
kmutex_t *lockp = &ts_list_lock[index]; \
tsproc_t *headp = &ts_plisthead[index]; \
mutex_enter(lockp); \
tspp->ts_next = headp->ts_next; \
tspp->ts_prev = headp; \
headp->ts_next->ts_prev = tspp; \
headp->ts_next = tspp; \
mutex_exit(lockp); \
}
#define TS_LIST_DELETE(tspp) \
{ \
int index = TS_LIST_HASH(tspp->ts_tp); \
kmutex_t *lockp = &ts_list_lock[index]; \
mutex_enter(lockp); \
tspp->ts_prev->ts_next = tspp->ts_next; \
tspp->ts_next->ts_prev = tspp->ts_prev; \
mutex_exit(lockp); \
}
static int ts_admin(caddr_t, cred_t *);
static int ts_enterclass(kthread_t *, id_t, void *, cred_t *, void *);
static int ts_fork(kthread_t *, kthread_t *, void *);
static int ts_getclinfo(void *);
static int ts_getclpri(pcpri_t *);
static int ts_parmsin(void *);
static int ts_parmsout(void *, pc_vaparms_t *);
static int ts_vaparmsin(void *, pc_vaparms_t *);
static int ts_vaparmsout(void *, pc_vaparms_t *);
static int ts_parmsset(kthread_t *, void *, id_t, cred_t *);
static void ts_exit(kthread_t *);
static int ts_donice(kthread_t *, cred_t *, int, int *);
static int ts_doprio(kthread_t *, cred_t *, int, int *);
static void ts_exitclass(void *);
static int ts_canexit(kthread_t *, cred_t *);
static void ts_forkret(kthread_t *, kthread_t *);
static void ts_nullsys();
static void ts_parmsget(kthread_t *, void *);
static void ts_preempt(kthread_t *);
static void ts_setrun(kthread_t *);
static void ts_sleep(kthread_t *);
static pri_t ts_swapin(kthread_t *, int);
static pri_t ts_swapout(kthread_t *, int);
static void ts_tick(kthread_t *);
static void ts_trapret(kthread_t *);
static void ts_update(void *);
static int ts_update_list(int);
static void ts_wakeup(kthread_t *);
static pri_t ts_globpri(kthread_t *);
static void ts_yield(kthread_t *);
extern tsdpent_t *ts_getdptbl(void);
extern pri_t *ts_getkmdpris(void);
extern pri_t td_getmaxumdpri(void);
static int ts_alloc(void **, int);
static void ts_free(void *);
pri_t ia_init(id_t, int, classfuncs_t **);
static int ia_getclinfo(void *);
static int ia_getclpri(pcpri_t *);
static int ia_parmsin(void *);
static int ia_vaparmsin(void *, pc_vaparms_t *);
static int ia_vaparmsout(void *, pc_vaparms_t *);
static int ia_parmsset(kthread_t *, void *, id_t, cred_t *);
static void ia_parmsget(kthread_t *, void *);
static void ia_set_process_group(pid_t, pid_t, pid_t);
static void ts_change_priority(kthread_t *, tsproc_t *);
static pri_t ts_maxglobpri;
static kmutex_t ts_dptblock;
static kmutex_t ts_list_lock[TS_LISTS];
static tsproc_t ts_plisthead[TS_LISTS];
static gid_t IA_gid = 0;
static struct classfuncs ts_classfuncs = {
ts_admin,
ts_getclinfo,
ts_parmsin,
ts_parmsout,
ts_vaparmsin,
ts_vaparmsout,
ts_getclpri,
ts_alloc,
ts_free,
ts_enterclass,
ts_exitclass,
ts_canexit,
ts_fork,
ts_forkret,
ts_parmsget,
ts_parmsset,
ts_nullsys,
ts_exit,
ts_nullsys,
ts_nullsys,
ts_swapin,
ts_swapout,
ts_trapret,
ts_preempt,
ts_setrun,
ts_sleep,
ts_tick,
ts_wakeup,
ts_donice,
ts_globpri,
ts_nullsys,
ts_yield,
ts_doprio,
};
static struct classfuncs ia_classfuncs = {
ts_admin,
ia_getclinfo,
ia_parmsin,
ts_parmsout,
ia_vaparmsin,
ia_vaparmsout,
ia_getclpri,
ts_alloc,
ts_free,
ts_enterclass,
ts_exitclass,
ts_canexit,
ts_fork,
ts_forkret,
ia_parmsget,
ia_parmsset,
ts_nullsys,
ts_exit,
ts_nullsys,
ts_nullsys,
ts_swapin,
ts_swapout,
ts_trapret,
ts_preempt,
ts_setrun,
ts_sleep,
ts_tick,
ts_wakeup,
ts_donice,
ts_globpri,
ia_set_process_group,
ts_yield,
ts_doprio,
};
static pri_t
ts_init(id_t cid, int clparmsz, classfuncs_t **clfuncspp)
{
int i;
extern pri_t ts_getmaxumdpri(void);
ts_dptbl = ts_getdptbl();
ts_kmdpris = ts_getkmdpris();
ts_maxumdpri = ts_getmaxumdpri();
ts_maxglobpri = MAX(ts_kmdpris[0], ts_dptbl[ts_maxumdpri].ts_globpri);
for (i = 0; i < TS_LISTS; i++) {
ts_plisthead[i].ts_next = ts_plisthead[i].ts_prev =
&ts_plisthead[i];
}
*clfuncspp = &ts_classfuncs;
return (ts_maxglobpri);
}
pri_t
ia_init(id_t cid, int clparmsz, classfuncs_t **clfuncspp)
{
ia_cid = cid;
*clfuncspp = &ia_classfuncs;
return (ts_maxglobpri);
}
static int
ts_admin(caddr_t uaddr, cred_t *reqpcredp)
{
tsadmin_t tsadmin;
tsdpent_t *tmpdpp;
int userdpsz;
int i;
size_t tsdpsz;
if (get_udatamodel() == DATAMODEL_NATIVE) {
if (copyin(uaddr, &tsadmin, sizeof (tsadmin_t)))
return (EFAULT);
}
#ifdef _SYSCALL32_IMPL
else {
tsadmin32_t tsadmin32;
if (copyin(uaddr, &tsadmin32, sizeof (tsadmin32_t)))
return (EFAULT);
tsadmin.ts_dpents =
(struct tsdpent *)(uintptr_t)tsadmin32.ts_dpents;
tsadmin.ts_ndpents = tsadmin32.ts_ndpents;
tsadmin.ts_cmd = tsadmin32.ts_cmd;
}
#endif
tsdpsz = (ts_maxumdpri + 1) * sizeof (tsdpent_t);
switch (tsadmin.ts_cmd) {
case TS_GETDPSIZE:
tsadmin.ts_ndpents = ts_maxumdpri + 1;
if (get_udatamodel() == DATAMODEL_NATIVE) {
if (copyout(&tsadmin, uaddr, sizeof (tsadmin_t)))
return (EFAULT);
}
#ifdef _SYSCALL32_IMPL
else {
tsadmin32_t tsadmin32;
tsadmin32.ts_dpents =
(caddr32_t)(uintptr_t)tsadmin.ts_dpents;
tsadmin32.ts_ndpents = tsadmin.ts_ndpents;
tsadmin32.ts_cmd = tsadmin.ts_cmd;
if (copyout(&tsadmin32, uaddr, sizeof (tsadmin32_t)))
return (EFAULT);
}
#endif
break;
case TS_GETDPTBL:
userdpsz = MIN(tsadmin.ts_ndpents * sizeof (tsdpent_t),
tsdpsz);
if (copyout(ts_dptbl, tsadmin.ts_dpents, userdpsz))
return (EFAULT);
tsadmin.ts_ndpents = userdpsz / sizeof (tsdpent_t);
if (get_udatamodel() == DATAMODEL_NATIVE) {
if (copyout(&tsadmin, uaddr, sizeof (tsadmin_t)))
return (EFAULT);
}
#ifdef _SYSCALL32_IMPL
else {
tsadmin32_t tsadmin32;
tsadmin32.ts_dpents =
(caddr32_t)(uintptr_t)tsadmin.ts_dpents;
tsadmin32.ts_ndpents = tsadmin.ts_ndpents;
tsadmin32.ts_cmd = tsadmin.ts_cmd;
if (copyout(&tsadmin32, uaddr, sizeof (tsadmin32_t)))
return (EFAULT);
}
#endif
break;
case TS_SETDPTBL:
if (secpolicy_dispadm(reqpcredp) != 0)
return (EPERM);
if (tsadmin.ts_ndpents * sizeof (tsdpent_t) != tsdpsz) {
return (EINVAL);
}
tmpdpp = kmem_alloc(tsdpsz, KM_SLEEP);
if (copyin((caddr_t)tsadmin.ts_dpents, (caddr_t)tmpdpp,
tsdpsz)) {
kmem_free(tmpdpp, tsdpsz);
return (EFAULT);
}
for (i = 0; i < tsadmin.ts_ndpents; i++) {
if (tmpdpp[i].ts_quantum <= 0) {
kmem_free(tmpdpp, tsdpsz);
return (EINVAL);
}
if (tmpdpp[i].ts_tqexp > ts_maxumdpri ||
tmpdpp[i].ts_tqexp < 0) {
kmem_free(tmpdpp, tsdpsz);
return (EINVAL);
}
if (tmpdpp[i].ts_slpret > ts_maxumdpri ||
tmpdpp[i].ts_slpret < 0) {
kmem_free(tmpdpp, tsdpsz);
return (EINVAL);
}
if (tmpdpp[i].ts_maxwait < 0) {
kmem_free(tmpdpp, tsdpsz);
return (EINVAL);
}
if (tmpdpp[i].ts_lwait > ts_maxumdpri ||
tmpdpp[i].ts_lwait < 0) {
kmem_free(tmpdpp, tsdpsz);
return (EINVAL);
}
}
mutex_enter(&ts_dptblock);
for (i = 0; i < tsadmin.ts_ndpents; i++) {
ts_dptbl[i].ts_quantum = tmpdpp[i].ts_quantum;
ts_dptbl[i].ts_tqexp = tmpdpp[i].ts_tqexp;
ts_dptbl[i].ts_slpret = tmpdpp[i].ts_slpret;
ts_dptbl[i].ts_maxwait = tmpdpp[i].ts_maxwait;
ts_dptbl[i].ts_lwait = tmpdpp[i].ts_lwait;
}
mutex_exit(&ts_dptblock);
kmem_free(tmpdpp, tsdpsz);
break;
default:
return (EINVAL);
}
return (0);
}
static int
ts_enterclass(kthread_t *t, id_t cid, void *parmsp, cred_t *reqpcredp,
void *bufp)
{
tsparms_t *tsparmsp = (tsparms_t *)parmsp;
tsproc_t *tspp;
pri_t reqtsuprilim;
pri_t reqtsupri;
static uint32_t tspexists = 0;
tspp = (tsproc_t *)bufp;
ASSERT(tspp != NULL);
tspp->ts_cpupri = tsmedumdpri;
if (cid == ia_cid) {
if (reqpcredp != NULL && !groupmember(IA_gid, reqpcredp) &&
secpolicy_setpriority(reqpcredp) != 0)
return (EPERM);
tspp->ts_flags = TSIA | TSIASET;
tspp->ts_boost = ia_boost;
} else {
tspp->ts_flags = 0;
tspp->ts_boost = 0;
}
if (tsparmsp == NULL) {
tspp->ts_uprilim = tspp->ts_upri = 0;
tspp->ts_nice = NZERO;
} else {
if (tsparmsp->ts_uprilim == TS_NOCHANGE)
reqtsuprilim = 0;
else {
if (tsparmsp->ts_uprilim > 0 &&
secpolicy_setpriority(reqpcredp) != 0)
return (EPERM);
reqtsuprilim = tsparmsp->ts_uprilim;
}
if (tsparmsp->ts_upri == TS_NOCHANGE) {
reqtsupri = reqtsuprilim;
} else {
if (tsparmsp->ts_upri > 0 &&
secpolicy_setpriority(reqpcredp) != 0)
return (EPERM);
reqtsupri = tsparmsp->ts_upri;
if (reqtsupri > reqtsuprilim)
reqtsupri = reqtsuprilim;
}
tspp->ts_uprilim = reqtsuprilim;
tspp->ts_upri = reqtsupri;
tspp->ts_nice = NZERO - (NZERO * reqtsupri) / ts_maxupri;
}
TS_NEWUMDPRI(tspp);
tspp->ts_dispwait = 0;
tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum;
tspp->ts_tp = t;
cpucaps_sc_init(&tspp->ts_caps);
thread_lock(t);
t->t_clfuncs = &(sclass[cid].cl_funcs->thread);
t->t_cid = cid;
t->t_cldata = (void *)tspp;
t->t_schedflag &= ~TS_RUNQMATCH;
ts_change_priority(t, tspp);
thread_unlock(t);
TS_LIST_INSERT(tspp);
if (tspexists == 0 && atomic_cas_32(&tspexists, 0, 1) == 0)
(void) timeout(ts_update, NULL, hz);
return (0);
}
static void
ts_exitclass(void *procp)
{
tsproc_t *tspp = (tsproc_t *)procp;
TS_LIST_DELETE(tspp);
kmem_free(tspp, sizeof (tsproc_t));
}
static int
ts_canexit(kthread_t *t, cred_t *cred)
{
return (0);
}
static int
ts_fork(kthread_t *t, kthread_t *ct, void *bufp)
{
tsproc_t *ptspp;
tsproc_t *ctspp;
ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
ctspp = (tsproc_t *)bufp;
ASSERT(ctspp != NULL);
ptspp = (tsproc_t *)t->t_cldata;
thread_lock(t);
ctspp->ts_timeleft = ts_dptbl[ptspp->ts_cpupri].ts_quantum;
ctspp->ts_cpupri = ptspp->ts_cpupri;
ctspp->ts_boost = ptspp->ts_boost;
ctspp->ts_uprilim = ptspp->ts_uprilim;
ctspp->ts_upri = ptspp->ts_upri;
TS_NEWUMDPRI(ctspp);
ctspp->ts_nice = ptspp->ts_nice;
ctspp->ts_dispwait = 0;
ctspp->ts_flags = ptspp->ts_flags & ~(TSBACKQ | TSRESTORE);
ctspp->ts_tp = ct;
cpucaps_sc_init(&ctspp->ts_caps);
thread_unlock(t);
ct->t_cldata = (void *)ctspp;
TS_LIST_INSERT(ctspp);
return (0);
}
static void
ts_forkret(kthread_t *t, kthread_t *ct)
{
proc_t *pp = ttoproc(t);
proc_t *cp = ttoproc(ct);
tsproc_t *tspp;
ASSERT(t == curthread);
ASSERT(MUTEX_HELD(&pidlock));
mutex_enter(&cp->p_lock);
continuelwps(cp);
mutex_exit(&cp->p_lock);
mutex_enter(&pp->p_lock);
mutex_exit(&pidlock);
continuelwps(pp);
thread_lock(t);
tspp = (tsproc_t *)(t->t_cldata);
tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_tqexp;
TS_NEWUMDPRI(tspp);
tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum;
tspp->ts_dispwait = 0;
t->t_pri = ts_dptbl[tspp->ts_umdpri].ts_globpri;
ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri);
THREAD_TRANSITION(t);
ts_setrun(t);
thread_unlock(t);
mutex_exit(&pp->p_lock);
swtch();
}
static int
ts_getclinfo(void *infop)
{
tsinfo_t *tsinfop = (tsinfo_t *)infop;
tsinfop->ts_maxupri = ts_maxupri;
return (0);
}
static int
ia_getclinfo(void *infop)
{
iainfo_t *iainfop = (iainfo_t *)infop;
iainfop->ia_maxupri = ia_maxupri;
return (0);
}
static int
ts_getclpri(pcpri_t *pcprip)
{
pcprip->pc_clpmax = ts_maxupri;
pcprip->pc_clpmin = -ts_maxupri;
return (0);
}
static int
ia_getclpri(pcpri_t *pcprip)
{
pcprip->pc_clpmax = ia_maxupri;
pcprip->pc_clpmin = -ia_maxupri;
return (0);
}
static void
ts_nullsys()
{}
static void
ts_parmsget(kthread_t *t, void *parmsp)
{
tsproc_t *tspp = (tsproc_t *)t->t_cldata;
tsparms_t *tsparmsp = (tsparms_t *)parmsp;
tsparmsp->ts_uprilim = tspp->ts_uprilim;
tsparmsp->ts_upri = tspp->ts_upri;
}
static void
ia_parmsget(kthread_t *t, void *parmsp)
{
tsproc_t *tspp = (tsproc_t *)t->t_cldata;
iaparms_t *iaparmsp = (iaparms_t *)parmsp;
iaparmsp->ia_uprilim = tspp->ts_uprilim;
iaparmsp->ia_upri = tspp->ts_upri;
if (tspp->ts_flags & TSIASET)
iaparmsp->ia_mode = IA_SET_INTERACTIVE;
else
iaparmsp->ia_mode = IA_INTERACTIVE_OFF;
}
static int
ts_parmsin(void *parmsp)
{
tsparms_t *tsparmsp = (tsparms_t *)parmsp;
if ((tsparmsp->ts_uprilim > ts_maxupri ||
tsparmsp->ts_uprilim < -ts_maxupri) &&
tsparmsp->ts_uprilim != TS_NOCHANGE)
return (EINVAL);
if ((tsparmsp->ts_upri > ts_maxupri ||
tsparmsp->ts_upri < -ts_maxupri) &&
tsparmsp->ts_upri != TS_NOCHANGE)
return (EINVAL);
return (0);
}
static int
ia_parmsin(void *parmsp)
{
iaparms_t *iaparmsp = (iaparms_t *)parmsp;
if ((iaparmsp->ia_uprilim > ia_maxupri ||
iaparmsp->ia_uprilim < -ia_maxupri) &&
iaparmsp->ia_uprilim != IA_NOCHANGE) {
return (EINVAL);
}
if ((iaparmsp->ia_upri > ia_maxupri ||
iaparmsp->ia_upri < -ia_maxupri) &&
iaparmsp->ia_upri != IA_NOCHANGE) {
return (EINVAL);
}
return (0);
}
static int
ts_vaparmsin(void *parmsp, pc_vaparms_t *vaparmsp)
{
tsparms_t *tsparmsp = (tsparms_t *)parmsp;
int priflag = 0;
int limflag = 0;
uint_t cnt;
pc_vaparm_t *vpp = &vaparmsp->pc_parms[0];
tsparmsp->ts_uprilim = TS_NOCHANGE;
tsparmsp->ts_upri = TS_NOCHANGE;
if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
return (EINVAL);
for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
switch (vpp->pc_key) {
case TS_KY_UPRILIM:
if (limflag++)
return (EINVAL);
tsparmsp->ts_uprilim = (pri_t)vpp->pc_parm;
if (tsparmsp->ts_uprilim > ts_maxupri ||
tsparmsp->ts_uprilim < -ts_maxupri)
return (EINVAL);
break;
case TS_KY_UPRI:
if (priflag++)
return (EINVAL);
tsparmsp->ts_upri = (pri_t)vpp->pc_parm;
if (tsparmsp->ts_upri > ts_maxupri ||
tsparmsp->ts_upri < -ts_maxupri)
return (EINVAL);
break;
default:
return (EINVAL);
}
}
if (vaparmsp->pc_vaparmscnt == 0) {
tsparmsp->ts_upri = tsparmsp->ts_uprilim = 0;
}
return (0);
}
static int
ia_vaparmsin(void *parmsp, pc_vaparms_t *vaparmsp)
{
iaparms_t *iaparmsp = (iaparms_t *)parmsp;
int priflag = 0;
int limflag = 0;
int mflag = 0;
uint_t cnt;
pc_vaparm_t *vpp = &vaparmsp->pc_parms[0];
iaparmsp->ia_uprilim = IA_NOCHANGE;
iaparmsp->ia_upri = IA_NOCHANGE;
iaparmsp->ia_mode = IA_NOCHANGE;
if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
return (EINVAL);
for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
switch (vpp->pc_key) {
case IA_KY_UPRILIM:
if (limflag++)
return (EINVAL);
iaparmsp->ia_uprilim = (pri_t)vpp->pc_parm;
if (iaparmsp->ia_uprilim > ia_maxupri ||
iaparmsp->ia_uprilim < -ia_maxupri)
return (EINVAL);
break;
case IA_KY_UPRI:
if (priflag++)
return (EINVAL);
iaparmsp->ia_upri = (pri_t)vpp->pc_parm;
if (iaparmsp->ia_upri > ia_maxupri ||
iaparmsp->ia_upri < -ia_maxupri)
return (EINVAL);
break;
case IA_KY_MODE:
if (mflag++)
return (EINVAL);
iaparmsp->ia_mode = (int)vpp->pc_parm;
if (iaparmsp->ia_mode != IA_SET_INTERACTIVE &&
iaparmsp->ia_mode != IA_INTERACTIVE_OFF)
return (EINVAL);
break;
default:
return (EINVAL);
}
}
if (vaparmsp->pc_vaparmscnt == 0) {
iaparmsp->ia_upri = iaparmsp->ia_uprilim = 0;
iaparmsp->ia_mode = IA_SET_INTERACTIVE;
}
return (0);
}
static int
ts_parmsout(void *parmsp, pc_vaparms_t *vaparmsp)
{
return (0);
}
static int
ts_vaparmsout(void *prmsp, pc_vaparms_t *vaparmsp)
{
tsparms_t *tsprmsp = (tsparms_t *)prmsp;
int priflag = 0;
int limflag = 0;
uint_t cnt;
pc_vaparm_t *vpp = &vaparmsp->pc_parms[0];
ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
return (EINVAL);
for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
switch (vpp->pc_key) {
case TS_KY_UPRILIM:
if (limflag++)
return (EINVAL);
if (copyout(&tsprmsp->ts_uprilim,
(caddr_t)(uintptr_t)vpp->pc_parm, sizeof (pri_t)))
return (EFAULT);
break;
case TS_KY_UPRI:
if (priflag++)
return (EINVAL);
if (copyout(&tsprmsp->ts_upri,
(caddr_t)(uintptr_t)vpp->pc_parm, sizeof (pri_t)))
return (EFAULT);
break;
default:
return (EINVAL);
}
}
return (0);
}
static int
ia_vaparmsout(void *prmsp, pc_vaparms_t *vaparmsp)
{
iaparms_t *iaprmsp = (iaparms_t *)prmsp;
int priflag = 0;
int limflag = 0;
int mflag = 0;
uint_t cnt;
pc_vaparm_t *vpp = &vaparmsp->pc_parms[0];
ASSERT(MUTEX_NOT_HELD(&curproc->p_lock));
if (vaparmsp->pc_vaparmscnt > PC_VAPARMCNT)
return (EINVAL);
for (cnt = 0; cnt < vaparmsp->pc_vaparmscnt; cnt++, vpp++) {
switch (vpp->pc_key) {
case IA_KY_UPRILIM:
if (limflag++)
return (EINVAL);
if (copyout(&iaprmsp->ia_uprilim,
(caddr_t)(uintptr_t)vpp->pc_parm, sizeof (pri_t)))
return (EFAULT);
break;
case IA_KY_UPRI:
if (priflag++)
return (EINVAL);
if (copyout(&iaprmsp->ia_upri,
(caddr_t)(uintptr_t)vpp->pc_parm, sizeof (pri_t)))
return (EFAULT);
break;
case IA_KY_MODE:
if (mflag++)
return (EINVAL);
if (copyout(&iaprmsp->ia_mode,
(caddr_t)(uintptr_t)vpp->pc_parm, sizeof (int)))
return (EFAULT);
break;
default:
return (EINVAL);
}
}
return (0);
}
static int
ts_parmsset(kthread_t *tx, void *parmsp, id_t reqpcid, cred_t *reqpcredp)
{
char nice;
pri_t reqtsuprilim;
pri_t reqtsupri;
tsparms_t *tsparmsp = (tsparms_t *)parmsp;
tsproc_t *tspp = (tsproc_t *)tx->t_cldata;
ASSERT(MUTEX_HELD(&(ttoproc(tx))->p_lock));
if (tsparmsp->ts_uprilim == TS_NOCHANGE)
reqtsuprilim = tspp->ts_uprilim;
else
reqtsuprilim = tsparmsp->ts_uprilim;
if (tsparmsp->ts_upri == TS_NOCHANGE)
reqtsupri = tspp->ts_upri;
else
reqtsupri = tsparmsp->ts_upri;
if (reqtsupri > reqtsuprilim)
reqtsupri = reqtsuprilim;
if (reqpcredp != NULL &&
reqtsuprilim > tspp->ts_uprilim &&
secpolicy_raisepriority(reqpcredp) != 0)
return (EPERM);
nice = NZERO - (reqtsupri * NZERO) / ts_maxupri;
if (nice >= 2 * NZERO)
nice = 2 * NZERO - 1;
thread_lock(tx);
tspp->ts_uprilim = reqtsuprilim;
tspp->ts_upri = reqtsupri;
TS_NEWUMDPRI(tspp);
tspp->ts_nice = nice;
tspp->ts_dispwait = 0;
ts_change_priority(tx, tspp);
thread_unlock(tx);
return (0);
}
static int
ia_parmsset(kthread_t *tx, void *parmsp, id_t reqpcid, cred_t *reqpcredp)
{
tsproc_t *tspp = (tsproc_t *)tx->t_cldata;
iaparms_t *iaparmsp = (iaparms_t *)parmsp;
proc_t *p;
pid_t pid, pgid, sid;
pid_t on, off;
struct stdata *stp;
int sess_held;
if (iaparmsp->ia_mode == IA_NOCHANGE)
return (ts_parmsset(tx, parmsp, reqpcid, reqpcredp));
if (reqpcredp != NULL && !groupmember(IA_gid, reqpcredp) &&
secpolicy_raisepriority(reqpcredp) != 0) {
return (0);
}
ASSERT(MUTEX_HELD(&pidlock));
if ((p = ttoproc(tx)) == NULL) {
return (0);
}
ASSERT(MUTEX_HELD(&p->p_lock));
if (p->p_stat == SIDL) {
return (0);
}
pid = p->p_pid;
sid = p->p_sessp->s_sid;
pgid = p->p_pgrp;
if (iaparmsp->ia_mode == IA_SET_INTERACTIVE) {
thread_lock(tx);
tspp->ts_flags |= TSIASET;
thread_unlock(tx);
}
mutex_enter(&p->p_sessp->s_lock);
sess_held = 1;
if ((pid == sid) && (p->p_sessp->s_vp != NULL) &&
((stp = p->p_sessp->s_vp->v_stream) != NULL)) {
if ((stp->sd_pgidp != NULL) && (stp->sd_sidp != NULL)) {
pgid = stp->sd_pgidp->pid_id;
sess_held = 0;
mutex_exit(&p->p_sessp->s_lock);
if (iaparmsp->ia_mode ==
IA_SET_INTERACTIVE) {
off = 0;
on = pgid;
} else {
off = pgid;
on = 0;
}
TRACE_3(TR_FAC_IA, TR_ACTIVE_CHAIN,
"active chain:pid %d gid %d %p",
pid, pgid, p);
ia_set_process_group(sid, off, on);
}
}
if (sess_held)
mutex_exit(&p->p_sessp->s_lock);
thread_lock(tx);
if (iaparmsp->ia_mode == IA_SET_INTERACTIVE) {
tspp->ts_flags |= TSIASET;
tspp->ts_boost = ia_boost;
} else {
tspp->ts_flags &= ~TSIASET;
tspp->ts_boost = -ia_boost;
}
thread_unlock(tx);
return (ts_parmsset(tx, parmsp, reqpcid, reqpcredp));
}
static void
ts_exit(kthread_t *t)
{
tsproc_t *tspp;
if (CPUCAPS_ON()) {
thread_lock(t);
tspp = (tsproc_t *)t->t_cldata;
(void) cpucaps_charge(t, &tspp->ts_caps, CPUCAPS_CHARGE_ONLY);
thread_unlock(t);
}
}
static pri_t
ts_globpri(kthread_t *t)
{
tsproc_t *tspp;
pri_t tspri;
ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
tspp = (tsproc_t *)t->t_cldata;
tspri = tsmedumdpri + tspp->ts_upri;
if (tspri > ts_maxumdpri)
tspri = ts_maxumdpri;
else if (tspri < 0)
tspri = 0;
return (ts_dptbl[tspri].ts_globpri);
}
static void
ts_preempt(kthread_t *t)
{
tsproc_t *tspp = (tsproc_t *)(t->t_cldata);
klwp_t *lwp = ttolwp(t);
pri_t oldpri = t->t_pri;
ASSERT(t == curthread);
ASSERT(THREAD_LOCK_HELD(curthread));
if (CPUCAPS_ON()) {
(void) cpucaps_charge(t, &tspp->ts_caps,
CPUCAPS_CHARGE_ENFORCE);
if (CPUCAPS_ENFORCE(t))
return;
}
ASSERT(t->t_schedflag & TS_DONT_SWAP);
if (lwp != NULL && lwp->lwp_state == LWP_USER)
t->t_schedflag &= ~TS_DONT_SWAP;
if (t->t_schedctl && schedctl_get_nopreempt(t)) {
if (tspp->ts_timeleft > -SC_MAX_TICKS) {
DTRACE_SCHED1(schedctl__nopreempt, kthread_t *, t);
if (!(tspp->ts_flags & TSRESTORE)) {
tspp->ts_scpri = t->t_pri;
tspp->ts_flags |= TSRESTORE;
}
THREAD_CHANGE_PRI(t, ts_maxumdpri);
t->t_schedflag |= TS_DONT_SWAP;
schedctl_set_yield(t, 1);
setfrontdq(t);
goto done;
} else {
if (tspp->ts_flags & TSRESTORE) {
THREAD_CHANGE_PRI(t, tspp->ts_scpri);
tspp->ts_flags &= ~TSRESTORE;
}
schedctl_set_nopreempt(t, 0);
DTRACE_SCHED1(schedctl__preempt, kthread_t *, t);
}
}
if ((tspp->ts_flags & TSBACKQ) != 0) {
tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum;
tspp->ts_dispwait = 0;
tspp->ts_flags &= ~TSBACKQ;
setbackdq(t);
} else {
setfrontdq(t);
}
done:
TRACE_2(TR_FAC_DISP, TR_PREEMPT,
"preempt:tid %p old pri %d", t, oldpri);
}
static void
ts_setrun(kthread_t *t)
{
tsproc_t *tspp = (tsproc_t *)(t->t_cldata);
ASSERT(THREAD_LOCK_HELD(t));
if (tspp->ts_dispwait > ts_dptbl[tspp->ts_umdpri].ts_maxwait) {
tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_slpret;
TS_NEWUMDPRI(tspp);
tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum;
tspp->ts_dispwait = 0;
THREAD_CHANGE_PRI(t, ts_dptbl[tspp->ts_umdpri].ts_globpri);
ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri);
}
tspp->ts_flags &= ~TSBACKQ;
if (tspp->ts_flags & TSIA) {
if (tspp->ts_flags & TSIASET)
setfrontdq(t);
else
setbackdq(t);
} else {
if (t->t_disp_time != ddi_get_lbolt())
setbackdq(t);
else
setfrontdq(t);
}
}
static void
ts_sleep(kthread_t *t)
{
tsproc_t *tspp = (tsproc_t *)(t->t_cldata);
pri_t old_pri = t->t_pri;
ASSERT(t == curthread);
ASSERT(THREAD_LOCK_HELD(t));
(void) CPUCAPS_CHARGE(t, &tspp->ts_caps, CPUCAPS_CHARGE_ENFORCE);
if (tspp->ts_dispwait > ts_dptbl[tspp->ts_umdpri].ts_maxwait) {
tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_slpret;
TS_NEWUMDPRI(tspp);
tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum;
tspp->ts_dispwait = 0;
THREAD_CHANGE_PRI(curthread,
ts_dptbl[tspp->ts_umdpri].ts_globpri);
ASSERT(curthread->t_pri >= 0 &&
curthread->t_pri <= ts_maxglobpri);
if (DISP_MUST_SURRENDER(curthread))
cpu_surrender(curthread);
}
t->t_stime = ddi_get_lbolt();
TRACE_2(TR_FAC_DISP, TR_SLEEP,
"sleep:tid %p old pri %d", t, old_pri);
}
static pri_t
ts_swapin(kthread_t *t, int flags)
{
tsproc_t *tspp = (tsproc_t *)(t->t_cldata);
long epri = -1;
proc_t *pp = ttoproc(t);
ASSERT(THREAD_LOCK_HELD(t));
if (t->t_state == TS_RUN && (t->t_schedflag & TS_LOAD) == 0) {
time_t swapout_time;
swapout_time = (ddi_get_lbolt() - t->t_stime) / hz;
if (INHERITED(t) || (tspp->ts_flags & TSIASET)) {
epri = (long)DISP_PRIO(t) + swapout_time;
} else {
epri = ts_dptbl[tspp->ts_umdpri].ts_globpri;
ASSERT(epri >= 0 && epri <= ts_maxumdpri);
epri += swapout_time - pp->p_swrss / nz(maxpgio)/2;
}
epri += SHRT_MAX/2;
if (epri < 0)
epri = 0;
else if (epri > SHRT_MAX)
epri = SHRT_MAX;
}
return ((pri_t)epri);
}
time_t ts_minrun = 2;
time_t ts_minslp = 2;
static pri_t
ts_swapout(kthread_t *t, int flags)
{
tsproc_t *tspp = (tsproc_t *)(t->t_cldata);
long epri = -1;
proc_t *pp = ttoproc(t);
time_t swapin_time;
ASSERT(THREAD_LOCK_HELD(t));
if (INHERITED(t) || (tspp->ts_flags & TSIASET) ||
(t->t_proc_flag & TP_LWPEXIT) ||
(t->t_state & (TS_ZOMB | TS_FREE | TS_STOPPED |
TS_ONPROC | TS_WAIT)) ||
!(t->t_schedflag & TS_LOAD) || !SWAP_OK(t))
return (-1);
ASSERT(t->t_state & (TS_SLEEP | TS_RUN));
swapin_time = (ddi_get_lbolt() - t->t_stime) / hz;
if (flags == SOFTSWAP) {
if (t->t_state == TS_SLEEP && swapin_time > maxslp) {
epri = 0;
} else {
return ((pri_t)epri);
}
} else {
pri_t pri;
if ((t->t_state == TS_SLEEP && swapin_time > ts_minslp) ||
(t->t_state == TS_RUN && swapin_time > ts_minrun)) {
pri = ts_dptbl[tspp->ts_umdpri].ts_globpri;
ASSERT(pri >= 0 && pri <= ts_maxumdpri);
epri = swapin_time -
(rm_asrss(pp->p_as) / nz(maxpgio)/2) - (long)pri;
} else {
return ((pri_t)epri);
}
}
epri += SHRT_MAX/2;
if (epri < 0)
epri = 0;
else if (epri > SHRT_MAX)
epri = SHRT_MAX;
return ((pri_t)epri);
}
static void
ts_tick(kthread_t *t)
{
tsproc_t *tspp = (tsproc_t *)(t->t_cldata);
klwp_t *lwp;
boolean_t call_cpu_surrender = B_FALSE;
pri_t oldpri = t->t_pri;
ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock));
thread_lock(t);
if (CPUCAPS_ON()) {
call_cpu_surrender = cpucaps_charge(t, &tspp->ts_caps,
CPUCAPS_CHARGE_ENFORCE);
}
if (--tspp->ts_timeleft <= 0) {
pri_t new_pri;
if (t->t_schedctl && schedctl_get_nopreempt(t)) {
if (tspp->ts_timeleft > -SC_MAX_TICKS) {
DTRACE_SCHED1(schedctl__nopreempt,
kthread_t *, t);
schedctl_set_yield(t, 1);
thread_unlock_nopreempt(t);
return;
}
DTRACE_SCHED1(schedctl__failsafe,
kthread_t *, t);
}
tspp->ts_flags &= ~TSRESTORE;
tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_tqexp;
TS_NEWUMDPRI(tspp);
tspp->ts_dispwait = 0;
new_pri = ts_dptbl[tspp->ts_umdpri].ts_globpri;
ASSERT(new_pri >= 0 && new_pri <= ts_maxglobpri);
if (thread_change_pri(t, new_pri, 0)) {
if ((t->t_schedflag & TS_LOAD) &&
(lwp = t->t_lwp) &&
lwp->lwp_state == LWP_USER)
t->t_schedflag &= ~TS_DONT_SWAP;
tspp->ts_timeleft =
ts_dptbl[tspp->ts_cpupri].ts_quantum;
} else {
call_cpu_surrender = B_TRUE;
}
TRACE_2(TR_FAC_DISP, TR_TICK,
"tick:tid %p old pri %d", t, oldpri);
} else if (t->t_state == TS_ONPROC &&
t->t_pri < t->t_disp_queue->disp_maxrunpri) {
call_cpu_surrender = B_TRUE;
}
if (call_cpu_surrender) {
tspp->ts_flags |= TSBACKQ;
cpu_surrender(t);
}
thread_unlock_nopreempt(t);
}
static void
ts_trapret(kthread_t *t)
{
tsproc_t *tspp = (tsproc_t *)t->t_cldata;
cpu_t *cp = CPU;
pri_t old_pri = curthread->t_pri;
ASSERT(THREAD_LOCK_HELD(t));
ASSERT(t == curthread);
ASSERT(cp->cpu_dispthread == t);
ASSERT(t->t_state == TS_ONPROC);
if (tspp->ts_dispwait > ts_dptbl[tspp->ts_umdpri].ts_maxwait) {
tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_slpret;
TS_NEWUMDPRI(tspp);
tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum;
tspp->ts_dispwait = 0;
THREAD_CHANGE_PRI(t, ts_dptbl[tspp->ts_umdpri].ts_globpri);
cp->cpu_dispatch_pri = DISP_PRIO(t);
ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri);
if (DISP_MUST_SURRENDER(t))
cpu_surrender(t);
}
if ((t->t_schedflag & TS_SWAPENQ) && !(tspp->ts_flags & TSIASET)) {
thread_unlock(t);
swapout_lwp(ttolwp(t));
thread_lock(t);
}
TRACE_2(TR_FAC_DISP, TR_TRAPRET,
"trapret:tid %p old pri %d", t, old_pri);
}
static void
ts_update(void *arg)
{
int i;
int new_marker = -1;
static int ts_update_marker;
i = ts_update_marker;
do {
if (ts_update_list(i) && new_marker == -1 &&
i != ts_update_marker) {
new_marker = i;
}
} while ((i = TS_LIST_NEXT(i)) != ts_update_marker);
if (new_marker != -1)
ts_update_marker = new_marker;
(void) timeout(ts_update, arg, hz);
}
static int
ts_update_list(int i)
{
tsproc_t *tspp;
kthread_t *tx;
int updated = 0;
mutex_enter(&ts_list_lock[i]);
for (tspp = ts_plisthead[i].ts_next; tspp != &ts_plisthead[i];
tspp = tspp->ts_next) {
tx = tspp->ts_tp;
thread_lock(tx);
if (tx->t_clfuncs != &ts_classfuncs.thread &&
tx->t_clfuncs != &ia_classfuncs.thread)
goto next;
tspp->ts_dispwait++;
if (tspp->ts_dispwait <= ts_dptbl[tspp->ts_umdpri].ts_maxwait)
goto next;
if (tx->t_schedctl && schedctl_get_nopreempt(tx))
goto next;
if (tx->t_state != TS_RUN && tx->t_state != TS_WAIT &&
(tx->t_state != TS_SLEEP || !ts_sleep_promote)) {
tx->t_trapret = 1;
aston(tx);
goto next;
}
tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_lwait;
TS_NEWUMDPRI(tspp);
tspp->ts_dispwait = 0;
updated = 1;
if (tx->t_pri != ts_dptbl[tspp->ts_umdpri].ts_globpri) {
pri_t oldpri = tx->t_pri;
ts_change_priority(tx, tspp);
TRACE_2(TR_FAC_DISP, TR_UPDATE,
"update:tid %p old pri %d", tx, oldpri);
}
next:
thread_unlock(tx);
}
mutex_exit(&ts_list_lock[i]);
return (updated);
}
static void
ts_wakeup(kthread_t *t)
{
tsproc_t *tspp = (tsproc_t *)(t->t_cldata);
ASSERT(THREAD_LOCK_HELD(t));
t->t_stime = ddi_get_lbolt();
if (tspp->ts_dispwait > ts_dptbl[tspp->ts_umdpri].ts_maxwait) {
tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_slpret;
TS_NEWUMDPRI(tspp);
tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum;
tspp->ts_dispwait = 0;
THREAD_CHANGE_PRI(t, ts_dptbl[tspp->ts_umdpri].ts_globpri);
ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri);
}
tspp->ts_flags &= ~TSBACKQ;
if (tspp->ts_flags & TSIA) {
if (tspp->ts_flags & TSIASET)
setfrontdq(t);
else
setbackdq(t);
} else {
if (t->t_disp_time != ddi_get_lbolt())
setbackdq(t);
else
setfrontdq(t);
}
}
static void
ts_yield(kthread_t *t)
{
tsproc_t *tspp = (tsproc_t *)(t->t_cldata);
ASSERT(t == curthread);
ASSERT(THREAD_LOCK_HELD(t));
(void) CPUCAPS_CHARGE(t, &tspp->ts_caps, CPUCAPS_CHARGE_ENFORCE);
if (t->t_schedctl)
schedctl_set_yield(t, 0);
if (tspp->ts_flags & TSRESTORE) {
THREAD_CHANGE_PRI(t, tspp->ts_scpri);
tspp->ts_flags &= ~TSRESTORE;
}
if (tspp->ts_timeleft <= 0) {
DTRACE_SCHED1(schedctl__yield, int, -tspp->ts_timeleft);
tspp->ts_cpupri = ts_dptbl[tspp->ts_cpupri].ts_tqexp;
TS_NEWUMDPRI(tspp);
tspp->ts_timeleft = ts_dptbl[tspp->ts_cpupri].ts_quantum;
tspp->ts_dispwait = 0;
THREAD_CHANGE_PRI(t, ts_dptbl[tspp->ts_umdpri].ts_globpri);
ASSERT(t->t_pri >= 0 && t->t_pri <= ts_maxglobpri);
}
tspp->ts_flags &= ~TSBACKQ;
setbackdq(t);
}
static int
ts_donice(kthread_t *t, cred_t *cr, int incr, int *retvalp)
{
int newnice;
tsproc_t *tspp = (tsproc_t *)(t->t_cldata);
tsparms_t tsparms;
ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock));
if (incr == 0) {
if (retvalp) {
*retvalp = tspp->ts_nice - NZERO;
}
return (0);
}
if ((incr < 0 || incr > 2 * NZERO) &&
secpolicy_raisepriority(cr) != 0)
return (EPERM);
if (incr > 2 * NZERO - 1)
incr = 2 * NZERO - 1;
newnice = tspp->ts_nice + incr;
if (newnice >= 2 * NZERO)
newnice = 2 * NZERO - 1;
else if (newnice < 0)
newnice = 0;
tsparms.ts_uprilim = tsparms.ts_upri =
-((newnice - NZERO) * ts_maxupri) / NZERO;
(void) ts_parmsset(t, (void *)&tsparms, (id_t)0, (cred_t *)NULL);
tspp->ts_nice = (char)newnice;
if (retvalp)
*retvalp = newnice - NZERO;
return (0);
}
static int
ts_doprio(kthread_t *t, cred_t *cr, int incr, int *retvalp)
{
int newpri;
tsproc_t *tspp = (tsproc_t *)(t->t_cldata);
tsparms_t tsparms;
ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock));
if (incr == 0) {
*retvalp = tspp->ts_upri;
return (0);
}
newpri = tspp->ts_upri + incr;
if (newpri > ts_maxupri || newpri < -ts_maxupri)
return (EINVAL);
*retvalp = newpri;
tsparms.ts_uprilim = tsparms.ts_upri = newpri;
return (ts_parmsset(t, &tsparms, 0, cr));
}
static void
ia_set_process_group(pid_t sid, pid_t bg_pgid, pid_t fg_pgid)
{
proc_t *leader, *fg, *bg;
tsproc_t *tspp;
kthread_t *tx;
int plocked = 0;
ASSERT(MUTEX_HELD(&pidlock));
if ((leader = (proc_t *)prfind(sid)) == NULL) {
return;
}
if (leader->p_stat == SIDL) {
return;
}
if ((tx = proctot(leader)) == NULL) {
return;
}
if (tx->t_cid != ia_cid) {
return;
}
tspp = tx->t_cldata;
mutex_enter(&leader->p_sessp->s_lock);
if (!(tspp->ts_flags & TSIASET) ||
(leader->p_sessp->s_vp == NULL) ||
(leader->p_sessp->s_vp->v_stream == NULL)) {
mutex_exit(&leader->p_sessp->s_lock);
return;
}
mutex_exit(&leader->p_sessp->s_lock);
if (mutex_owned(&leader->p_lock))
plocked = 1;
if (fg_pgid == 0)
goto skip;
for (fg = (proc_t *)pgfind(fg_pgid); fg != NULL; fg = fg->p_pglink) {
if (fg->p_stat == SIDL) {
continue;
}
if (fg->p_pid == fg->p_sessp->s_sid) {
continue;
}
TRACE_1(TR_FAC_IA, TR_GROUP_ON,
"group on:proc %p", fg);
if (plocked) {
if (mutex_tryenter(&fg->p_lock) == 0)
continue;
} else {
mutex_enter(&fg->p_lock);
}
if ((tx = proctot(fg)) == NULL) {
mutex_exit(&fg->p_lock);
continue;
}
do {
thread_lock(tx);
if (tx->t_cid != ia_cid) {
thread_unlock(tx);
continue;
}
tspp = tx->t_cldata;
tspp->ts_flags |= TSIASET;
tspp->ts_boost = ia_boost;
TS_NEWUMDPRI(tspp);
tspp->ts_dispwait = 0;
ts_change_priority(tx, tspp);
thread_unlock(tx);
} while ((tx = tx->t_forw) != fg->p_tlist);
mutex_exit(&fg->p_lock);
}
skip:
if (bg_pgid == 0)
return;
for (bg = (proc_t *)pgfind(bg_pgid); bg != NULL; bg = bg->p_pglink) {
if (bg->p_stat == SIDL) {
continue;
}
if (bg->p_pid == bg->p_sessp->s_sid) {
continue;
}
TRACE_1(TR_FAC_IA, TR_GROUP_OFF,
"group off:proc %p", bg);
if (plocked) {
if (mutex_tryenter(&bg->p_lock) == 0)
continue;
} else {
mutex_enter(&bg->p_lock);
}
if ((tx = proctot(bg)) == NULL) {
mutex_exit(&bg->p_lock);
continue;
}
do {
thread_lock(tx);
if (tx->t_cid != ia_cid) {
thread_unlock(tx);
continue;
}
tspp = tx->t_cldata;
tspp->ts_flags &= ~TSIASET;
tspp->ts_boost = -ia_boost;
TS_NEWUMDPRI(tspp);
tspp->ts_dispwait = 0;
ts_change_priority(tx, tspp);
thread_unlock(tx);
} while ((tx = tx->t_forw) != bg->p_tlist);
mutex_exit(&bg->p_lock);
}
}
static void
ts_change_priority(kthread_t *t, tsproc_t *tspp)
{
pri_t new_pri;
ASSERT(THREAD_LOCK_HELD(t));
new_pri = ts_dptbl[tspp->ts_umdpri].ts_globpri;
ASSERT(new_pri >= 0 && new_pri <= ts_maxglobpri);
tspp->ts_flags &= ~TSRESTORE;
t->t_cpri = tspp->ts_upri;
if (t == curthread || t->t_state == TS_ONPROC) {
cpu_t *cp = t->t_disp_queue->disp_cpu;
THREAD_CHANGE_PRI(t, new_pri);
if (t == cp->cpu_dispthread)
cp->cpu_dispatch_pri = DISP_PRIO(t);
if (DISP_MUST_SURRENDER(t)) {
tspp->ts_flags |= TSBACKQ;
cpu_surrender(t);
} else {
tspp->ts_timeleft =
ts_dptbl[tspp->ts_cpupri].ts_quantum;
}
} else {
int frontq;
frontq = (tspp->ts_flags & TSIASET) != 0;
if (thread_change_pri(t, new_pri, frontq)) {
tspp->ts_timeleft =
ts_dptbl[tspp->ts_cpupri].ts_quantum;
} else {
tspp->ts_flags |= TSBACKQ;
}
}
}
static int
ts_alloc(void **p, int flag)
{
void *bufp;
bufp = kmem_alloc(sizeof (tsproc_t), flag);
if (bufp == NULL) {
return (ENOMEM);
} else {
*p = bufp;
return (0);
}
}
static void
ts_free(void *bufp)
{
if (bufp)
kmem_free(bufp, sizeof (tsproc_t));
}