diff options
Diffstat (limited to 'usr/src/uts/common/disp/fx.c')
-rw-r--r-- | usr/src/uts/common/disp/fx.c | 111 |
1 files changed, 44 insertions, 67 deletions
diff --git a/usr/src/uts/common/disp/fx.c b/usr/src/uts/common/disp/fx.c index 62b5eb1da2..53bfb46e2a 100644 --- a/usr/src/uts/common/disp/fx.c +++ b/usr/src/uts/common/disp/fx.c @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -54,6 +53,7 @@ #include <sys/policy.h> #include <sys/sdt.h> #include <sys/cpupart.h> +#include <sys/cpucaps.h> static pri_t fx_init(id_t, int, classfuncs_t **); @@ -85,40 +85,6 @@ static struct modlinkage modlinkage = { #define FX_MAX_UNPRIV_PRI 0 /* maximum unpriviledge priority */ /* - * The fxproc_t structures are kept in an array of circular doubly linked - * lists. A hash on the thread pointer is used to determine which list - * each fxproc structure should be placed. Each list has a dummy "head" which - * is never removed, so the list is never empty. - */ - -#define FX_LISTS 16 /* number of lists, must be power of 2 */ -#define FX_LIST_HASH(tp) (((uintptr_t)(tp) >> 9) & (FX_LISTS - 1)) - -#define FX_LIST_INSERT(fxpp) \ -{ \ - int index = FX_LIST_HASH(fxpp->fx_tp); \ - kmutex_t *lockp = &fx_list_lock[index]; \ - fxproc_t *headp = &fx_plisthead[index]; \ - mutex_enter(lockp); \ - fxpp->fx_next = headp->fx_next; \ - fxpp->fx_prev = headp; \ - headp->fx_next->fx_prev = fxpp; \ - headp->fx_next = fxpp; \ - mutex_exit(lockp); \ -} - -#define FX_LIST_DELETE(fxpp) \ -{ \ - int index = FX_LIST_HASH(fxpp->fx_tp); \ - kmutex_t *lockp = &fx_list_lock[index]; \ - mutex_enter(lockp); \ - fxpp->fx_prev->fx_next = fxpp->fx_next; \ - fxpp->fx_next->fx_prev = fxpp->fx_prev; \ - mutex_exit(lockp); \ -} - - -/* * The fxproc_t structures that have a registered callback vector, * are also kept in an array of circular doubly linked lists. A hash on * the thread id (from ddi_get_kt_did()) is used to determine which list @@ -192,10 +158,6 @@ static pri_t fx_maxglobpri; /* maximum global priority used by fx class */ static kmutex_t fx_dptblock; /* protects fixed priority dispatch table */ -static kmutex_t fx_list_lock[FX_LISTS]; /* protects fxproc lists */ -static fxproc_t fx_plisthead[FX_LISTS]; /* dummy fxproc at head of lists */ - - static kmutex_t fx_cb_list_lock[FX_CB_LISTS]; /* protects list of fxprocs */ /* that have callbacks */ static fxproc_t fx_cb_plisthead[FX_CB_LISTS]; /* dummy fxproc at head of */ @@ -316,14 +278,6 @@ fx_init(id_t cid, int clparmsz, classfuncs_t **clfuncspp) fx_cid = cid; /* Record our class ID */ /* - * Initialize the fxproc hash table - */ - for (i = 0; i < FX_LISTS; i++) { - fx_plisthead[i].fx_next = fx_plisthead[i].fx_prev = - &fx_plisthead[i]; - } - - /* * Initialize the hash table for fxprocs with callbacks */ for (i = 0; i < FX_CB_LISTS; i++) { @@ -477,7 +431,6 @@ fx_admin(caddr_t uaddr, cred_t *reqpcredp) return (0); } - /* * Allocate a fixed priority class specific thread structure and * initialize it with the parameters supplied. Also move the thread @@ -565,6 +518,7 @@ fx_enterclass(kthread_t *t, id_t cid, void *parmsp, cred_t *reqpcredp, } fxpp->fx_timeleft = fxpp->fx_pquantum; + cpucaps_sc_init(&fxpp->fx_caps); fxpp->fx_tp = t; thread_lock(t); /* get dispatcher lock on thread */ @@ -575,8 +529,6 @@ fx_enterclass(kthread_t *t, id_t cid, void *parmsp, cred_t *reqpcredp, fx_change_priority(t, fxpp); thread_unlock(t); - FX_LIST_INSERT(fxpp); - return (0); } @@ -591,6 +543,8 @@ fx_exit(kthread_t *t) thread_lock(t); fxpp = (fxproc_t *)(t->t_cldata); + (void) CPUCAPS_CHARGE(t, &fxpp->fx_caps, CPUCAPS_CHARGE_ONLY); + if (FX_HAS_CB(fxpp)) { FX_CB_EXIT(FX_CALLB(fxpp), fxpp->fx_cookie); fxpp->fx_callback = NULL; @@ -599,6 +553,7 @@ fx_exit(kthread_t *t) FX_CB_LIST_DELETE(fxpp); return; } + thread_unlock(t); } @@ -621,7 +576,6 @@ fx_exitclass(void *procp) FX_CB_LIST_DELETE(fxpp); } else thread_unlock(fxpp->fx_tp); - FX_LIST_DELETE(fxpp); kmem_free(fxpp, sizeof (fxproc_t)); } @@ -662,6 +616,7 @@ fx_fork(kthread_t *t, kthread_t *ct, void *bufp) cfxpp->fx_callback = NULL; cfxpp->fx_cookie = NULL; cfxpp->fx_flags = pfxpp->fx_flags & ~(FXBACKQ); + cpucaps_sc_init(&cfxpp->fx_caps); cfxpp->fx_tp = ct; ct->t_cldata = (void *)cfxpp; @@ -670,7 +625,6 @@ fx_fork(kthread_t *t, kthread_t *ct, void *bufp) /* * Link new structure into fxproc list. */ - FX_LIST_INSERT(cfxpp); return (0); } @@ -1157,13 +1111,12 @@ static void fx_preempt(kthread_t *t) { fxproc_t *fxpp = (fxproc_t *)(t->t_cldata); -#ifdef KSLICE - extern int kslice; -#endif ASSERT(t == curthread); ASSERT(THREAD_LOCK_HELD(curthread)); + (void) CPUCAPS_CHARGE(t, &fxpp->fx_caps, CPUCAPS_CHARGE_ONLY); + /* * Check to see if we're doing "preemption control" here. If * we are, and if the user has requested that this thread not @@ -1209,17 +1162,20 @@ fx_preempt(kthread_t *t) THREAD_CHANGE_PRI(t, fx_dptbl[fxpp->fx_pri].fx_globpri); } + /* + * This thread may be placed on wait queue by CPU Caps. In this case we + * do not need to do anything until it is removed from the wait queue. + */ + if (CPUCAPS_ENFORCE(t)) { + return; + } + if ((fxpp->fx_flags & (FXBACKQ)) == FXBACKQ) { fxpp->fx_timeleft = fxpp->fx_pquantum; fxpp->fx_flags &= ~FXBACKQ; setbackdq(t); } else { -#ifdef KSLICE - if (kslice) - setbackdq(t); - else -#endif - setfrontdq(t); + setfrontdq(t); } } @@ -1250,6 +1206,11 @@ fx_sleep(kthread_t *t) ASSERT(t == curthread); ASSERT(THREAD_LOCK_HELD(t)); + /* + * Account for time spent on CPU before going to sleep. + */ + (void) CPUCAPS_CHARGE(t, &fxpp->fx_caps, CPUCAPS_CHARGE_ONLY); + if (FX_HAS_CB(fxpp)) { FX_CB_SLEEP(FX_CALLB(fxpp), fxpp->fx_cookie); } @@ -1318,6 +1279,7 @@ fx_stop(kthread_t *t, int why, int what) static void fx_tick(kthread_t *t) { + boolean_t call_cpu_surrender = B_FALSE; fxproc_t *fxpp; ASSERT(MUTEX_HELD(&(ttoproc(t))->p_lock)); @@ -1342,6 +1304,14 @@ fx_tick(kthread_t *t) fx_change_priority(t, fxpp); } } + + /* + * Keep track of thread's project CPU usage. Note that projects + * get charged even when threads are running in the kernel. + */ + call_cpu_surrender = CPUCAPS_CHARGE(t, &fxpp->fx_caps, + CPUCAPS_CHARGE_ENFORCE); + if ((fxpp->fx_pquantum != FX_TQINF) && (--fxpp->fx_timeleft <= 0)) { pri_t new_pri; @@ -1379,15 +1349,17 @@ fx_tick(kthread_t *t) if (thread_change_pri(t, new_pri, 0)) { fxpp->fx_timeleft = fxpp->fx_pquantum; } else { - fxpp->fx_flags |= FXBACKQ; - cpu_surrender(t); + call_cpu_surrender = B_TRUE; } } 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) { fxpp->fx_flags |= FXBACKQ; cpu_surrender(t); } - thread_unlock_nopreempt(t); /* clock thread can't be preempted */ } @@ -1453,6 +1425,11 @@ fx_yield(kthread_t *t) ASSERT(t == curthread); ASSERT(THREAD_LOCK_HELD(t)); + /* + * Collect CPU usage spent before yielding CPU. + */ + (void) CPUCAPS_CHARGE(t, &fxpp->fx_caps, CPUCAPS_CHARGE_ONLY); + if (FX_HAS_CB(fxpp)) { clock_t new_quantum = (clock_t)fxpp->fx_pquantum; pri_t newpri = fxpp->fx_pri; |