--- //depot/projects/smpng/sys/alpha/osf1/osf1_misc.c 2004/08/25 00:34:56 +++ //depot/user/jhb/proc/alpha/osf1/osf1_misc.c 2004/09/24 01:51:30 @@ -1335,29 +1335,16 @@ struct thread *td; struct osf1_getrusage_args *uap; { - struct proc *p; - struct rusage *rup; struct osf1_rusage oru; + struct rusage ru; + int error; - p = td->td_proc; - switch (uap->who) { - case RUSAGE_SELF: - rup = &p->p_stats->p_ru; - mtx_lock_spin(&sched_lock); - calcru(p, &rup->ru_utime, &rup->ru_stime, NULL); - mtx_unlock_spin(&sched_lock); - break; - - case RUSAGE_CHILDREN: - rup = &p->p_stats->p_cru; - break; - - default: - return (EINVAL); - } - TV_CP(rup->ru_utime, oru.ru_utime); - TV_CP(rup->ru_stime, oru.ru_stime); - bcopy(&(rup->ru_first), &(oru.ru_first), + error = kern_getrusage(td, uap->who, &ru); + if (error) + return (error); + TV_CP(ru.ru_utime, oru.ru_utime); + TV_CP(ru.ru_stime, oru.ru_stime); + bcopy(&(ru.ru_first), &(oru.ru_first), (&(oru.ru_last) - &(oru.ru_first))); return (copyout((caddr_t)&oru, (caddr_t)uap->rusage, @@ -1372,9 +1359,13 @@ { int error, status; struct osf1_rusage oru; - struct rusage ru; + struct rusage ru, *rup; - error = kern_wait(td, uap->pid, &status, uap->options, &ru); + if (uap->rusage != NULL) + rup = &ru; + else + rup = NULL; + error = kern_wait(td, uap->pid, &status, uap->options, rup); if (error) return (error); if (uap->status != NULL) --- //depot/projects/smpng/sys/amd64/linux32/linux32_machdep.c 2004/09/03 14:14:21 +++ //depot/user/jhb/proc/amd64/linux32/linux32_machdep.c 2004/09/24 01:51:30 @@ -940,24 +940,14 @@ int linux_getrusage(struct thread *td, struct linux_getrusage_args *uap) { + struct l_rusage s32; + struct rusage s; int error; - caddr_t sg; - struct l_rusage *p32, s32; - struct rusage *p = NULL, s; - p32 = uap->rusage; - if (p32 != NULL) { - sg = stackgap_init(); - p = stackgap_alloc(&sg, sizeof(struct rusage)); - uap->rusage = (struct l_rusage *)p; - } - error = getrusage(td, (struct getrusage_args *) uap); + error = kern_getrusage(td, uap->who, &s); if (error != 0) return (error); - if (p32 != NULL) { - error = copyin(p, &s, sizeof(s)); - if (error != 0) - return (error); + if (uap->rusage != NULL) { s32.ru_utime.tv_sec = s.ru_utime.tv_sec; s32.ru_utime.tv_usec = s.ru_utime.tv_usec; s32.ru_stime.tv_sec = s.ru_stime.tv_sec; @@ -976,7 +966,7 @@ s32.ru_nsignals = s.ru_nsignals; s32.ru_nvcsw = s.ru_nvcsw; s32.ru_nivcsw = s.ru_nivcsw; - error = copyout(&s32, p32, sizeof(s32)); + error = copyout(&s32, uap->rusage, sizeof(s32)); } return (error); } --- //depot/projects/smpng/sys/compat/freebsd32/freebsd32_misc.c 2004/06/23 20:40:08 +++ //depot/user/jhb/proc/compat/freebsd32/freebsd32_misc.c 2004/09/24 01:51:30 @@ -91,9 +91,13 @@ { int error, status; struct rusage32 ru32; - struct rusage ru; + struct rusage ru, *rup; - error = kern_wait(td, uap->pid, &status, uap->options, &ru); + if (uap->rusage != NULL) + rup = &ru; + else + rup = NULL; + error = kern_wait(td, uap->pid, &status, uap->options, rup); if (error) return (error); if (uap->status != NULL) @@ -639,24 +643,14 @@ int freebsd32_getrusage(struct thread *td, struct freebsd32_getrusage_args *uap) { + struct rusage32 s32; + struct rusage s; int error; - caddr_t sg; - struct rusage32 *p32, s32; - struct rusage *p = NULL, s; - p32 = uap->rusage; - if (p32) { - sg = stackgap_init(); - p = stackgap_alloc(&sg, sizeof(struct rusage)); - uap->rusage = (struct rusage32 *)p; - } - error = getrusage(td, (struct getrusage_args *) uap); + error = kern_getrusage(td, uap->who, &s); if (error) return (error); - if (p32) { - error = copyin(p, &s, sizeof(s)); - if (error) - return (error); + if (uap->rusage != NULL) { TV_CP(s, s32, ru_utime); TV_CP(s, s32, ru_stime); CP(s, s32, ru_maxrss); @@ -673,7 +667,7 @@ CP(s, s32, ru_nsignals); CP(s, s32, ru_nvcsw); CP(s, s32, ru_nivcsw); - error = copyout(&s32, p32, sizeof(s32)); + error = copyout(&s32, uap->rusage, sizeof(s32)); } return (error); } --- //depot/projects/smpng/sys/compat/linux/linux_misc.c 2004/08/20 17:10:02 +++ //depot/user/jhb/proc/compat/linux/linux_misc.c 2004/09/24 01:51:30 @@ -689,9 +689,9 @@ int linux_times(struct thread *td, struct linux_times_args *args) { - struct timeval tv; + struct timeval tv, utime, stime, cutime, cstime; struct l_times_argv tms; - struct rusage ru; + struct proc *p; int error; #ifdef DEBUG @@ -699,15 +699,17 @@ printf(ARGS(times, "*")); #endif - mtx_lock_spin(&sched_lock); - calcru(td->td_proc, &ru.ru_utime, &ru.ru_stime, NULL); - mtx_unlock_spin(&sched_lock); + p = td->td_proc; + PROC_LOCK(p); + calcru(p, &utime, &stime); + calccru(p, &cutime, &cstime); + PROC_UNLOCK(p); - tms.tms_utime = CONVTCK(ru.ru_utime); - tms.tms_stime = CONVTCK(ru.ru_stime); + tms.tms_utime = CONVTCK(utime); + tms.tms_stime = CONVTCK(stime); - tms.tms_cutime = CONVTCK(td->td_proc->p_stats->p_cru.ru_utime); - tms.tms_cstime = CONVTCK(td->td_proc->p_stats->p_cru.ru_stime); + tms.tms_cutime = CONVTCK(cutime); + tms.tms_cstime = CONVTCK(cstime); if ((error = copyout(&tms, args->buf, sizeof(tms)))) return error; @@ -851,7 +853,7 @@ linux_wait4(struct thread *td, struct linux_wait4_args *args) { int error, options, tmpstat; - struct rusage ru; + struct rusage ru, *rup; struct proc *p; #ifdef DEBUG @@ -866,7 +868,11 @@ if (args->options & __WCLONE) options |= WLINUXCLONE; - error = kern_wait(td, args->pid, &tmpstat, options, &ru); + if (args->rusage != NULL) + rup = &ru; + else + rup = NULL; + error = kern_wait(td, args->pid, &tmpstat, options, rup); if (error) return error; --- //depot/projects/smpng/sys/compat/svr4/svr4_misc.c 2004/10/01 14:25:19 +++ //depot/user/jhb/proc/compat/svr4/svr4_misc.c 2004/10/01 14:29:17 @@ -861,44 +861,30 @@ struct thread *td; struct svr4_sys_times_args *uap; { - int error, *retval = td->td_retval; - struct tms tms; - struct timeval t; - struct rusage *ru; - struct rusage r; - struct getrusage_args ga; + struct timeval tv, utime, stime, cutime, cstime; + struct tms tms; + struct proc *p; + int error; - caddr_t sg = stackgap_init(); - ru = stackgap_alloc(&sg, sizeof(struct rusage)); + p = td->td_proc; + PROC_LOCK(p); + calcru(p, &utime, &stime); + calccru(p, &cutime, &cstime); + PROC_UNLOCK(p); - ga.who = RUSAGE_SELF; - ga.rusage = ru; + tms.tms_utime = timeval_to_clock_t(&utime); + tms.tms_stime = timeval_to_clock_t(&stime); - error = getrusage(td, &ga); - if (error) - return error; + tms.tms_cutime = timeval_to_clock_t(&cutime); + tms.tms_cstime = timeval_to_clock_t(&cstime); - if ((error = copyin(ru, &r, sizeof r)) != 0) - return error; - - tms.tms_utime = timeval_to_clock_t(&r.ru_utime); - tms.tms_stime = timeval_to_clock_t(&r.ru_stime); - - ga.who = RUSAGE_CHILDREN; - error = getrusage(td, &ga); + error = copyout(&tms, uap->tp, sizeof(tms)); if (error) - return error; + return (error); - if ((error = copyin(ru, &r, sizeof r)) != 0) - return error; - - tms.tms_cutime = timeval_to_clock_t(&r.ru_utime); - tms.tms_cstime = timeval_to_clock_t(&r.ru_stime); - - microtime(&t); - *retval = timeval_to_clock_t(&t); - - return copyout(&tms, uap->tp, sizeof(tms)); + microtime(&tv); + td->td_retval[0] = (int)timeval_to_clock_t(&tv); + return (0); } @@ -1149,6 +1135,7 @@ int st; svr4_siginfo_t *s; { + struct timeval utime, stime; svr4_siginfo_t i; int sig; @@ -1159,16 +1146,11 @@ if (p) { i.si_pid = p->p_pid; - mtx_lock_spin(&sched_lock); - if (p->p_state == PRS_ZOMBIE) { - i.si_stime = p->p_ru->ru_stime.tv_sec; - i.si_utime = p->p_ru->ru_utime.tv_sec; - } - else { - i.si_stime = p->p_stats->p_ru.ru_stime.tv_sec; - i.si_utime = p->p_stats->p_ru.ru_utime.tv_sec; - } - mtx_unlock_spin(&sched_lock); + PROC_LOCK(p); + calcru(p, &utime, &stime); + PROC_UNLOCK(p); + i.si_stime = stime.tv_sec; + i.si_utime = utime.tv_sec; } if (WIFEXITED(st)) { @@ -1296,7 +1278,8 @@ PROC_UNLOCK(q); sx_xunlock(&proctree_lock); q->p_xstat = 0; - ruadd(&p->p_stats->p_cru, q->p_ru); + ruadd(&p->p_stats->p_cru, &p->p_crux, q->p_ru, + &q->p_rux); FREE(q->p_ru, M_ZOMBIE); q->p_ru = NULL; --- //depot/projects/smpng/sys/fs/procfs/procfs_status.c 2004/04/16 18:42:25 +++ //depot/user/jhb/proc/fs/procfs/procfs_status.c 2004/09/23 23:28:18 @@ -124,12 +124,12 @@ } else wmesg = "nochan"; } + mtx_unlock_spin(&sched_lock); if (p->p_sflag & PS_INMEM) { struct timeval start, ut, st; - calcru(p, &ut, &st, (struct timeval *) NULL); - mtx_unlock_spin(&sched_lock); + calcru(p, &ut, &st); start = p->p_stats->p_start; timevaladd(&start, &boottime); sbuf_printf(sb, " %ld,%ld %ld,%ld %ld,%ld", @@ -137,7 +137,6 @@ ut.tv_sec, ut.tv_usec, st.tv_sec, st.tv_usec); } else { - mtx_unlock_spin(&sched_lock); sbuf_printf(sb, " -1,-1 -1,-1 -1,-1"); } --- //depot/projects/smpng/sys/kern/init_main.c 2004/09/10 21:09:16 +++ //depot/user/jhb/proc/kern/init_main.c 2004/09/24 02:01:00 @@ -468,8 +468,8 @@ sx_slock(&allproc_lock); LIST_FOREACH(p, &allproc, p_list) { microuptime(&p->p_stats->p_start); - p->p_runtime.sec = 0; - p->p_runtime.frac = 0; + p->p_rux.rux_runtime.sec = 0; + p->p_rux.rux_runtime.frac = 0; } sx_sunlock(&allproc_lock); binuptime(PCPU_PTR(switchtime)); --- //depot/projects/smpng/sys/kern/kern_acct.c 2004/06/23 20:40:08 +++ //depot/user/jhb/proc/kern/kern_acct.c 2004/09/23 23:28:18 @@ -249,9 +249,7 @@ bcopy(p->p_comm, acct.ac_comm, sizeof acct.ac_comm); /* (2) The amount of user and system time that was used */ - mtx_lock_spin(&sched_lock); - calcru(p, &ut, &st, NULL); - mtx_unlock_spin(&sched_lock); + calcru(p, &ut, &st); acct.ac_utime = encode_comp_t(ut.tv_sec, ut.tv_usec); acct.ac_stime = encode_comp_t(st.tv_sec, st.tv_usec); --- //depot/projects/smpng/sys/kern/kern_clock.c 2004/07/16 20:38:04 +++ //depot/user/jhb/proc/kern/kern_clock.c 2004/09/24 02:01:00 @@ -363,7 +363,7 @@ * Statistics clock. Grab profile sample, and if divider reaches 0, * do process and kernel statistics. Most of the statistics are only * used by user-level statistics programs. The main exceptions are - * ke->ke_uticks, p->p_sticks, p->p_iticks, and p->p_estcpu. + * ke->ke_uticks, p->p_rux.rux_sticks, p->p_rux.rux_iticks, and p->p_estcpu. * This should be called by all active processors. */ void @@ -386,7 +386,7 @@ */ if (p->p_flag & P_SA) thread_statclock(1); - p->p_uticks++; + p->p_rux.rux_uticks++; if (p->p_nice > NZERO) cp_time[CP_NICE]++; else @@ -405,13 +405,13 @@ * in ``non-process'' (i.e., interrupt) work. */ if ((td->td_ithd != NULL) || td->td_intr_nesting_level >= 2) { - p->p_iticks++; + p->p_rux.rux_iticks++; cp_time[CP_INTR]++; } else { if (p->p_flag & P_SA) thread_statclock(0); td->td_sticks++; - p->p_sticks++; + p->p_rux.rux_sticks++; if (p != PCPU_GET(idlethread)->td_proc) cp_time[CP_SYS]++; else --- //depot/projects/smpng/sys/kern/kern_exit.c 2004/10/01 14:25:19 +++ //depot/user/jhb/proc/kern/kern_exit.c 2004/10/01 14:29:17 @@ -410,20 +413,16 @@ } /* - * Save exit status and final rusage info, adding in child rusage - * info and self times. + * Save exit status and finalize rusage info except for times, + * adding in child rusage info. */ - mtx_lock(&Giant); PROC_LOCK(p); p->p_xstat = rv; p->p_xthread = td; + p->p_stats->p_ru.ru_nvcsw++; *p->p_ru = p->p_stats->p_ru; - mtx_lock_spin(&sched_lock); - calcru(p, &p->p_ru->ru_utime, &p->p_ru->ru_stime, NULL); - mtx_unlock_spin(&sched_lock); - ruadd(p->p_ru, &p->p_stats->p_cru); + ruadd(p->p_ru, &p->p_rux, &p->p_stats->p_cru, &p->p_crux); - mtx_unlock(&Giant); /* * Notify interested parties of our demise. */ @@ -487,9 +486,6 @@ PROC_LOCK(p->p_pptr); sx_xunlock(&proctree_lock); - while (mtx_owned(&Giant)) - mtx_unlock(&Giant); - /* * We have to wait until after acquiring all locks before * changing p_state. We need to avoid all possible context @@ -508,8 +504,8 @@ /* Do the same timestamp bookkeeping that mi_switch() would do. */ binuptime(&new_switchtime); - bintime_add(&p->p_runtime, &new_switchtime); - bintime_sub(&p->p_runtime, PCPU_PTR(switchtime)); + bintime_add(&p->p_rux.rux_runtime, &new_switchtime); + bintime_sub(&p->p_rux.rux_runtime, PCPU_PTR(switchtime)); PCPU_SET(switchtime, new_switchtime); PCPU_SET(switchticks, ticks); cnt.v_swtch++; @@ -556,10 +552,14 @@ int wait4(struct thread *td, struct wait_args *uap) { - struct rusage ru; + struct rusage ru, *rup; int error, status; - error = kern_wait(td, uap->pid, &status, uap->options, &ru); + if (uap->rusage != NULL) + rup = &ru; + else + rup = NULL; + error = kern_wait(td, uap->pid, &status, uap->options, rup); if (uap->status != NULL && error == 0) error = copyout(&status, uap->status, sizeof(status)); if (uap->rusage != NULL && error == 0) @@ -612,8 +614,10 @@ td->td_retval[0] = p->p_pid; if (status) *status = p->p_xstat; /* convert to int */ - if (rusage) + if (rusage) { bcopy(p->p_ru, rusage, sizeof(struct rusage)); + calcru(p, &rusage->ru_utime, &rusage->ru_stime); + } /* * If we got the child via a ptrace 'attach', @@ -648,16 +652,15 @@ * all other writes to this proc are visible now, so * no more locking is needed for p. */ - mtx_lock(&Giant); PROC_LOCK(p); p->p_xstat = 0; /* XXX: why? */ PROC_UNLOCK(p); PROC_LOCK(q); - ruadd(&q->p_stats->p_cru, p->p_ru); + ruadd(&q->p_stats->p_cru, &q->p_crux, p->p_ru, + &p->p_rux); PROC_UNLOCK(q); FREE(p->p_ru, M_ZOMBIE); p->p_ru = NULL; - mtx_unlock(&Giant); /* * Decrement the count of procs running with this uid. --- //depot/projects/smpng/sys/kern/kern_proc.c 2004/09/22 15:31:15 +++ //depot/user/jhb/proc/kern/kern_proc.c 2004/09/24 02:01:00 @@ -674,23 +674,11 @@ kp->ki_dsize = vm->vm_dsize; kp->ki_ssize = vm->vm_ssize; } - if ((p->p_sflag & PS_INMEM) && p->p_stats) { - kp->ki_start = p->p_stats->p_start; - timevaladd(&kp->ki_start, &boottime); - kp->ki_rusage = p->p_stats->p_ru; - calcru(p, &kp->ki_rusage.ru_utime, &kp->ki_rusage.ru_stime, - NULL); - kp->ki_childstime = p->p_stats->p_cru.ru_stime; - kp->ki_childutime = p->p_stats->p_cru.ru_utime; - /* Some callers want child-times in a single value */ - kp->ki_childtime = kp->ki_childstime; - timevaladd(&kp->ki_childtime, &kp->ki_childutime); - } kp->ki_sflag = p->p_sflag; kp->ki_swtime = p->p_swtime; kp->ki_pid = p->p_pid; kp->ki_nice = p->p_nice; - bintime2timeval(&p->p_runtime, &tv); + bintime2timeval(&p->p_rux.rux_runtime, &tv); kp->ki_runtime = tv.tv_sec * (u_int64_t)1000000 + tv.tv_usec; if (p->p_state != PRS_ZOMBIE) { #if 0 @@ -758,6 +746,17 @@ kp->ki_stat = SZOMB; } mtx_unlock_spin(&sched_lock); + if ((p->p_sflag & PS_INMEM) && p->p_stats != NULL) { + kp->ki_start = p->p_stats->p_start; + timevaladd(&kp->ki_start, &boottime); + kp->ki_rusage = p->p_stats->p_ru; + calcru(p, &kp->ki_rusage.ru_utime, &kp->ki_rusage.ru_stime); + calccru(p, &kp->ki_childutime, &kp->ki_childstime); + + /* Some callers want child-times in a single value */ + kp->ki_childtime = kp->ki_childstime; + timevaladd(&kp->ki_childtime, &kp->ki_childutime); + } sp = NULL; tp = NULL; if (p->p_pgrp) { --- //depot/projects/smpng/sys/kern/kern_resource.c 2004/10/01 14:25:19 +++ //depot/user/jhb/proc/kern/kern_resource.c 2004/10/01 14:29:17 @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,8 @@ static LIST_HEAD(uihashhead, uidinfo) *uihashtbl; static u_long uihash; /* size of hash table - 1 */ +static void calcru1(struct proc *p, struct rusage_ext *ruxp, + struct timeval *up, struct timeval *sp); static int donice(struct thread *td, struct proc *chgp, int n); static struct uidinfo *uilookup(uid_t uid); @@ -691,65 +694,94 @@ * system, and interrupt time usage. */ void -calcru(p, up, sp, ip) +calcru(p, up, sp) struct proc *p; struct timeval *up; struct timeval *sp; - struct timeval *ip; { - struct bintime bt, rt; - struct timeval tv; + struct bintime bt; + struct rusage_ext rux; struct thread *td; - /* {user, system, interrupt, total} {ticks, usec}; previous tu: */ - u_int64_t ut, uu, st, su, it, iu, tt, tu, ptu; - int problemcase; - mtx_assert(&sched_lock, MA_OWNED); - /* XXX: why spl-protect ? worst case is an off-by-one report */ - - ut = p->p_uticks; - st = p->p_sticks; - it = p->p_iticks; - - tt = ut + st + it; - if (tt == 0) { - st = 1; - tt = 1; - } - rt = p->p_runtime; - problemcase = 0; + PROC_LOCK_ASSERT(p, MA_OWNED); + mtx_assert(&sched_lock, MA_NOTOWNED); + mtx_lock_spin(&sched_lock); + rux = p->p_rux; FOREACH_THREAD_IN_PROC(p, td) { /* * Adjust for the current time slice. This is actually fairly * important since the error here is on the order of a time * quantum, which is much greater than the sampling error. + * This is easy for the currently executing thread. */ if (td == curthread) { binuptime(&bt); bintime_sub(&bt, PCPU_PTR(switchtime)); - bintime_add(&rt, &bt); + bintime_add(&rux.rux_runtime, &bt); } else if (TD_IS_RUNNING(td)) { + struct pcpu *pc; + /* - * XXX: this case should add the difference between - * the current time and the switch time as above, - * but the switch time is inaccessible, so we can't - * do the adjustment and will end up with a wrong - * runtime. A previous call with a different - * curthread may have obtained a (right or wrong) - * runtime that is in advance of ours. Just set a - * flag to avoid warning about this known problem. + * For threads executing on another CPU, try to + * get the switchtime for that other CPU if we can. + * If we can't manage to do that successfully, then + * we might get a wrong runtime. I don't think + * this case can actually occur however. If it + * does show up in the future, then we can pass a + * flag to calcru1() to quiet the warning. */ - problemcase = 1; + if (td->td_oncpu != NOCPU) { + pc = pcpu_find(td->td_oncpu); + binuptime(&bt); + bintime_sub(&bt, &pc->pc_switchtime); + bintime_add(&rux.rux_runtime, &bt); + } } } - bintime2timeval(&rt, &tv); + mtx_unlock_spin(&sched_lock); + calcru1(p, &rux, up, sp); + p->p_rux.rux_uu = rux.rux_uu; + p->p_rux.rux_su = rux.rux_su; + p->p_rux.rux_iu = rux.rux_iu; +} + +void +calccru(p, up, sp) + struct proc *p; + struct timeval *up; + struct timeval *sp; +{ + + PROC_LOCK_ASSERT(p, MA_OWNED); + calcru1(p, &p->p_crux, up, sp); +} + +static void +calcru1(p, ruxp, up, sp) + struct proc *p; + struct rusage_ext *ruxp; + struct timeval *up; + struct timeval *sp; +{ + struct timeval tv; + /* {user, system, interrupt, total} {ticks, usec}; previous tu: */ + u_int64_t ut, uu, st, su, it, iu, tt, tu, ptu; + + ut = ruxp->rux_uticks; + st = ruxp->rux_sticks; + it = ruxp->rux_iticks; + tt = ut + st + it; + if (tt == 0) { + st = 1; + tt = 1; + } + bintime2timeval(&ruxp->rux_runtime, &tv); tu = (u_int64_t)tv.tv_sec * 1000000 + tv.tv_usec; - ptu = p->p_uu + p->p_su + p->p_iu; + ptu = ruxp->rux_uu + ruxp->rux_su + ruxp->rux_iu; if (tu < ptu) { - if (!problemcase) - printf( + printf( "calcru: runtime went backwards from %ju usec to %ju usec for pid %d (%s)\n", - (uintmax_t)ptu, (uintmax_t)tu, p->p_pid, p->p_comm); + (uintmax_t)ptu, (uintmax_t)tu, p->p_pid, p->p_comm); tu = ptu; } if ((int64_t)tu < 0) { @@ -764,38 +796,34 @@ iu = tu - uu - su; /* Enforce monotonicity. */ - if (uu < p->p_uu || su < p->p_su || iu < p->p_iu) { - if (uu < p->p_uu) - uu = p->p_uu; - else if (uu + p->p_su + p->p_iu > tu) - uu = tu - p->p_su - p->p_iu; + if (uu < ruxp->rux_uu || su < ruxp->rux_su || iu < ruxp->rux_iu) { + if (uu < ruxp->rux_uu) + uu = ruxp->rux_uu; + else if (uu + ruxp->rux_su + ruxp->rux_iu > tu) + uu = tu - ruxp->rux_su - ruxp->rux_iu; if (st == 0) - su = p->p_su; + su = ruxp->rux_su; else { su = ((tu - uu) * st) / (st + it); - if (su < p->p_su) - su = p->p_su; - else if (uu + su + p->p_iu > tu) - su = tu - uu - p->p_iu; + if (su < ruxp->rux_su) + su = ruxp->rux_su; + else if (uu + su + ruxp->rux_iu > tu) + su = tu - uu - ruxp->rux_iu; } - KASSERT(uu + su + p->p_iu <= tu, + KASSERT(uu + su + ruxp->rux_iu <= tu, ("calcru: monotonisation botch 1")); iu = tu - uu - su; - KASSERT(iu >= p->p_iu, + KASSERT(iu >= ruxp->rux_iu, ("calcru: monotonisation botch 2")); } - p->p_uu = uu; - p->p_su = su; - p->p_iu = iu; + ruxp->rux_uu = uu; + ruxp->rux_su = su; + ruxp->rux_iu = iu; up->tv_sec = uu / 1000000; up->tv_usec = uu % 1000000; sp->tv_sec = su / 1000000; sp->tv_usec = su % 1000000; - if (ip != NULL) { - ip->tv_sec = iu / 1000000; - ip->tv_usec = iu % 1000000; - } } #ifndef _SYS_SYSPROTO_H_ @@ -807,51 +835,67 @@ /* * MPSAFE */ -/* ARGSUSED */ int getrusage(td, uap) register struct thread *td; register struct getrusage_args *uap; { struct rusage ru; + int error; + + error = kern_getrusage(td, uap->who, &ru); + if (error == 0) + error = copyout(&ru, uap->rusage, sizeof(struct rusage)); + return (error); +} + +int +kern_getrusage(td, who, rup) + struct thread *td; + int who; + struct rusage *rup; +{ struct proc *p; p = td->td_proc; - switch (uap->who) { + PROC_LOCK(p); + switch (who) { case RUSAGE_SELF: - mtx_lock(&Giant); - mtx_lock_spin(&sched_lock); - calcru(p, &p->p_stats->p_ru.ru_utime, &p->p_stats->p_ru.ru_stime, - NULL); - mtx_unlock_spin(&sched_lock); - ru = p->p_stats->p_ru; - mtx_unlock(&Giant); + *rup = p->p_stats->p_ru; + calcru(p, &rup->ru_utime, &rup->ru_stime); break; case RUSAGE_CHILDREN: - mtx_lock(&Giant); - ru = p->p_stats->p_cru; - mtx_unlock(&Giant); + *rup = p->p_stats->p_cru; + calccru(p, &rup->ru_utime, &rup->ru_stime); break; default: + PROC_UNLOCK(p); return (EINVAL); - break; } - return (copyout(&ru, uap->rusage, sizeof(struct rusage))); + PROC_UNLOCK(p); + return (0); } void -ruadd(ru, ru2) +ruadd(ru, rux, ru2, rux2) struct rusage *ru; + struct rusage_ext *rux; struct rusage *ru2; + struct rusage_ext *rux2; { register long *ip, *ip2; register int i; - timevaladd(&ru->ru_utime, &ru2->ru_utime); - timevaladd(&ru->ru_stime, &ru2->ru_stime); + bintime_add(&rux->rux_runtime, &rux2->rux_runtime); + rux->rux_uticks += rux2->rux_uticks; + rux->rux_sticks += rux2->rux_sticks; + rux->rux_iticks += rux2->rux_iticks; + rux->rux_uu += rux2->rux_uu; + rux->rux_su += rux2->rux_su; + rux->rux_iu += rux2->rux_iu; if (ru->ru_maxrss < ru2->ru_maxrss) ru->ru_maxrss = ru2->ru_maxrss; ip = &ru->ru_first; --- //depot/projects/smpng/sys/kern/kern_synch.c 2004/09/22 15:31:15 +++ //depot/user/jhb/proc/kern/kern_synch.c 2004/09/24 02:01:00 @@ -302,8 +302,8 @@ * process was running, and add that to its total so far. */ binuptime(&new_switchtime); - bintime_add(&p->p_runtime, &new_switchtime); - bintime_sub(&p->p_runtime, PCPU_PTR(switchtime)); + bintime_add(&p->p_rux.rux_runtime, &new_switchtime); + bintime_sub(&p->p_rux.rux_runtime, PCPU_PTR(switchtime)); td->td_generation++; /* bump preempt-detect counter */ @@ -322,7 +322,7 @@ * over max, arrange to kill the process in ast(). */ if (p->p_cpulimit != RLIM_INFINITY && - p->p_runtime.sec > p->p_cpulimit) { + p->p_rux.rux_runtime.sec > p->p_cpulimit) { p->p_sflag |= PS_XCPU; td->td_flags |= TDF_ASTPENDING; } --- //depot/projects/smpng/sys/kern/kern_time.c 2004/06/23 20:40:08 +++ //depot/user/jhb/proc/kern/kern_time.c 2004/09/23 23:28:18 @@ -157,21 +157,23 @@ { struct timespec ats; struct timeval sys, user; + struct proc *p; + p = td->td_proc; switch (uap->clock_id) { case CLOCK_REALTIME: nanotime(&ats); break; case CLOCK_VIRTUAL: - mtx_lock_spin(&sched_lock); - calcru(td->td_proc, &user, &sys, NULL); - mtx_unlock_spin(&sched_lock); + PROC_LOCK(p); + calcru(p, &user, &sys); + PROC_UNLOCK(p); TIMEVAL_TO_TIMESPEC(&user, &ats); break; case CLOCK_PROF: - mtx_lock_spin(&sched_lock); - calcru(td->td_proc, &user, &sys, NULL); - mtx_unlock_spin(&sched_lock); + PROC_LOCK(p); + calcru(p, &user, &sys); + PROC_UNLOCK(p); timevaladd(&user, &sys); TIMEVAL_TO_TIMESPEC(&user, &ats); break; --- //depot/projects/smpng/sys/kern/subr_trap.c 2004/09/23 21:43:29 +++ //depot/user/jhb/proc/kern/subr_trap.c 2004/09/24 02:01:00 @@ -221,7 +221,7 @@ PROC_LOCK(p); lim_rlimit(p, RLIMIT_CPU, &rlim); mtx_lock_spin(&sched_lock); - if (p->p_runtime.sec >= rlim.rlim_max) { + if (p->p_rux.rux_runtime.sec >= rlim.rlim_max) { mtx_unlock_spin(&sched_lock); killproc(p, "exceeded maximum CPU limit"); } else { --- //depot/projects/smpng/sys/kern/tty.c 2004/10/01 14:25:19 +++ //depot/user/jhb/proc/kern/tty.c 2004/10/01 14:29:17 @@ -2603,13 +2622,15 @@ state = "intrwait"; else state = "unknown"; - calcru(pick, &utime, &stime, NULL); pctcpu = (sched_pctcpu(td) * 10000 + FSCALE / 2) >> FSHIFT; if (pick->p_state == PRS_NEW || pick->p_state == PRS_ZOMBIE) rss = 0; else rss = pgtok(vmspace_resident_count(pick->p_vmspace)); mtx_unlock_spin(&sched_lock); + PROC_LOCK(pick); + calcru(pick, &utime, &stime); + PROC_UNLOCK(pick); /* Print command, pid, state, utime, stime, %cpu, and rss. */ ttyprintf(tp, --- //depot/projects/smpng/sys/sys/proc.h 2004/10/01 14:25:19 +++ //depot/user/jhb/proc/sys/proc.h 2004/10/01 14:29:17 @@ -482,11 +482,31 @@ u_char kg_pri_class; /* (j) Scheduling class. */ u_char kg_user_pri; /* (j) User pri from estcpu and nice. */ #define kg_endcopy kg_numthreads int kg_numthreads; /* (j) Num threads in total. */ struct kg_sched *kg_sched; /* (*) Scheduler-specific data. */ }; /* + * XXX: Does this belong in resource.h or resourcevar.h instead? + * Resource usage extension. The times in rusage structs in the kernel are + * never up to date. The actual times are kept as runtimes and tick counts + * (with control info in the "previous" times), and are converted when + * userland asks for rusage info. Backwards compatibility prevents putting + * this directly in the user-visible rusage struct. + * + * Locking: (cj) means (j) for p_rux and (c) for p_crux. + */ +struct rusage_ext { + struct bintime rux_runtime; /* (cj) Real time. */ + u_int64_t rux_uticks; /* (cj) Statclock hits in user mode. */ + u_int64_t rux_sticks; /* (cj) Statclock hits in sys mode. */ + u_int64_t rux_iticks; /* (cj) Statclock hits in intr mode. */ + u_int64_t rux_uu; /* (c) Previous user time in usec. */ + u_int64_t rux_su; /* (c) Previous sys time in usec. */ + u_int64_t rux_iu; /* (c) Previous intr time in usec. */ +}; + +/* * The old fashionned process. May have multiple threads, KSEGRPs * and KSEs. Starts off with a single embedded KSEGRP and THREAD. */ @@ -530,13 +550,8 @@ struct vmspace *p_vmspace; /* (b) Address space. */ u_int p_swtime; /* (j) Time swapped in or out. */ struct itimerval p_realtimer; /* (c) Alarm timer. */ - struct bintime p_runtime; /* (j) Real time. */ - u_int64_t p_uu; /* (j) Previous user time in usec. */ - u_int64_t p_su; /* (j) Previous system time in usec. */ - u_int64_t p_iu; /* (j) Previous intr time in usec. */ - u_int64_t p_uticks; /* (j) Statclock hits in user mode. */ - u_int64_t p_sticks; /* (j) Statclock hits in system mode. */ - u_int64_t p_iticks; /* (j) Statclock hits in intr. */ + struct rusage_ext p_rux; /* (cj) Internal resource usage. */ + struct rusage_ext p_crux; /* (c) Internal child resource usage. */ int p_profthreads; /* (c) Num threads in addupc_task. */ int p_maxthrwaits; /* (c) Max threads num waiters */ int p_traceflag; /* (o) Kernel trace points. */ --- //depot/projects/smpng/sys/sys/resourcevar.h 2004/08/10 18:03:16 +++ //depot/user/jhb/proc/sys/resourcevar.h 2004/09/23 23:28:18 @@ -106,12 +106,13 @@ #define UIDINFO_UNLOCK(ui) mtx_unlock((ui)->ui_mtxp) struct proc; +struct rusage_ext; struct thread; void addupc_intr(struct thread *td, uintptr_t pc, u_int ticks); void addupc_task(struct thread *td, uintptr_t pc, u_int ticks); -void calcru(struct proc *p, struct timeval *up, struct timeval *sp, - struct timeval *ip); +void calccru(struct proc *p, struct timeval *up, struct timeval *sp); +void calcru(struct proc *p, struct timeval *up, struct timeval *sp); int chgproccnt(struct uidinfo *uip, int diff, int maxval); int chgsbsize(struct uidinfo *uip, u_int *hiwat, u_int to, rlim_t maxval); @@ -125,7 +126,8 @@ *lim_hold(struct plimit *limp); rlim_t lim_max(struct proc *p, int which); void lim_rlimit(struct proc *p, int which, struct rlimit *rlp); -void ruadd(struct rusage *ru, struct rusage *ru2); +void ruadd(struct rusage *ru, struct rusage_ext *rux, struct rusage *ru2, + struct rusage_ext *rux2); int suswintr(void *base, int word); struct uidinfo *uifind(uid_t uid); --- //depot/projects/smpng/sys/sys/syscallsubr.h 2004/10/01 14:25:19 +++ //depot/user/jhb/proc/sys/syscallsubr.h 2004/10/01 14:29:17 @@ -34,6 +34,7 @@ struct mbuf; struct msghdr; +struct rusage; struct sockaddr; int kern___getcwd(struct thread *td, u_char *buf, enum uio_seg bufseg, @@ -50,6 +51,7 @@ int kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg); int kern_futimes(struct thread *td, int fd, struct timeval *tptr, enum uio_seg tptrseg); +int kern_getrusage(struct thread *td, int who, struct rusage *rup); int kern_getsockopt(struct thread *td, int s, int level, int name, void *optval, enum uio_seg valseg, socklen_t *valsize); int kern_lchown(struct thread *td, char *path, enum uio_seg pathseg,