1*3110Swnj /* kern_clock.c 4.16 81/03/09 */ 29Sbill 39Sbill #include "../h/param.h" 49Sbill #include "../h/systm.h" 5329Sbill #include "../h/dk.h" 62768Swnj #include "../h/callout.h" 79Sbill #include "../h/seg.h" 89Sbill #include "../h/dir.h" 99Sbill #include "../h/user.h" 109Sbill #include "../h/proc.h" 119Sbill #include "../h/reg.h" 129Sbill #include "../h/psl.h" 139Sbill #include "../h/vm.h" 149Sbill #include "../h/buf.h" 159Sbill #include "../h/text.h" 16877Sbill #include "../h/vlimit.h" 17877Sbill #include "../h/mtpr.h" 18877Sbill #include "../h/clock.h" 192689Swnj #include "../h/cpu.h" 209Sbill 211943Swnj #include "dh.h" 221943Swnj #include "dz.h" 231559Sbill 249Sbill /* 252442Swnj * Hardclock is called straight from 269Sbill * the real time clock interrupt. 272442Swnj * We limit the work we do at real clock interrupt time to: 282442Swnj * reloading clock 292442Swnj * decrementing time to callouts 302442Swnj * recording cpu time usage 312450Swnj * modifying priority of current process 322442Swnj * arrange for soft clock interrupt 332442Swnj * kernel pc profiling 349Sbill * 35*3110Swnj * At software (softclock) interrupt time we: 369Sbill * implement callouts 379Sbill * maintain date 389Sbill * lightning bolt wakeup (every second) 399Sbill * alarm clock signals 409Sbill * jab the scheduler 412442Swnj * 422442Swnj * On the vax softclock interrupts are implemented by 432442Swnj * software interrupts. Note that we may have multiple softclock 442442Swnj * interrupts compressed into one (due to excessive interrupt load), 452442Swnj * but that hardclock interrupts should never be lost. 469Sbill */ 479Sbill 482609Swnj /*ARGSUSED*/ 492442Swnj hardclock(pc, ps) 502450Swnj caddr_t pc; 519Sbill { 522768Swnj register struct callout *p1; 539Sbill register struct proc *pp; 542442Swnj register int s, cpstate; 559Sbill 569Sbill /* 579Sbill * reprime clock 589Sbill */ 599Sbill clkreld(); 609Sbill 619Sbill /* 622442Swnj * update callout times 639Sbill */ 64*3110Swnj if (callout[0].c_func == NULL) 659Sbill goto out; 662442Swnj p1 = &callout[0]; 67*3110Swnj while (p1->c_time<=0 && p1->c_func!=NULL) 682442Swnj p1++; 692442Swnj p1->c_time--; 709Sbill out: 71138Sbill 72138Sbill /* 732442Swnj * Maintain iostat and per-process cpu statistics 74138Sbill */ 759Sbill if (!noproc) { 769Sbill s = u.u_procp->p_rssize; 779Sbill u.u_vm.vm_idsrss += s; 789Sbill if (u.u_procp->p_textp) { 799Sbill register int xrss = u.u_procp->p_textp->x_rssize; 809Sbill 819Sbill s += xrss; 829Sbill u.u_vm.vm_ixrss += xrss; 839Sbill } 849Sbill if (s > u.u_vm.vm_maxrss) 859Sbill u.u_vm.vm_maxrss = s; 862768Swnj if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/hz > u.u_limit[LIM_CPU]) { 87375Sbill psignal(u.u_procp, SIGXCPU); 88375Sbill if (u.u_limit[LIM_CPU] < INFINITY - 5) 89375Sbill u.u_limit[LIM_CPU] += 5; 90375Sbill } 919Sbill } 92*3110Swnj /* 93*3110Swnj * Update iostat information. 94*3110Swnj */ 959Sbill if (USERMODE(ps)) { 969Sbill u.u_vm.vm_utime++; 979Sbill if(u.u_procp->p_nice > NZERO) 98305Sbill cpstate = CP_NICE; 99305Sbill else 100305Sbill cpstate = CP_USER; 1019Sbill } else { 102305Sbill cpstate = CP_SYS; 1039Sbill if (noproc) 104305Sbill cpstate = CP_IDLE; 1059Sbill else 1069Sbill u.u_vm.vm_stime++; 1079Sbill } 1081408Sbill cp_time[cpstate]++; 1092442Swnj for (s = 0; s < DK_NDRIVE; s++) 1102442Swnj if (dk_busy&(1<<s)) 1112442Swnj dk_time[s]++; 112*3110Swnj /* 113*3110Swnj * Adjust priority of current process. 114*3110Swnj */ 1159Sbill if (!noproc) { 1169Sbill pp = u.u_procp; 1171399Sbill pp->p_cpticks++; 1189Sbill if(++pp->p_cpu == 0) 1199Sbill pp->p_cpu--; 1209Sbill if(pp->p_cpu % 16 == 0) { 121125Sbill (void) setpri(pp); 1229Sbill if (pp->p_pri >= PUSER) 1239Sbill pp->p_pri = pp->p_usrpri; 1249Sbill } 1259Sbill } 126*3110Swnj /* 127*3110Swnj * Time moves on. 128*3110Swnj */ 1299Sbill ++lbolt; 1302689Swnj #if VAX780 131*3110Swnj /* 132*3110Swnj * On 780's, impelement a fast UBA watcher, 133*3110Swnj * to make sure uba's don't get stuck. 134*3110Swnj */ 1352872Swnj if (cpu == VAX_780 && panicstr == 0 && !BASEPRI(ps)) 1362442Swnj unhang(); 1372442Swnj #endif 138*3110Swnj /* 139*3110Swnj * Schedule a software interrupt for the rest 140*3110Swnj * of clock activities. 141*3110Swnj */ 1422442Swnj setsoftclock(); 1432442Swnj } 1442442Swnj 1452442Swnj /* 146*3110Swnj * SCHMAG is the constant in the digital decay cpu 147*3110Swnj * usage priority assignment. Each second we multiply 148*3110Swnj * the previous cpu usage estimate by SCHMAG. At 9/10 149*3110Swnj * it tends to decay away all knowledge of previous activity 150*3110Swnj * in about 10 seconds. 1512442Swnj */ 152*3110Swnj #define SCHMAG 9/10 153*3110Swnj 154*3110Swnj /* 155*3110Swnj * Constant for decay filter for cpu usage field 156*3110Swnj * in process table (used by ps au). 157*3110Swnj */ 1582442Swnj double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 1592442Swnj 1602442Swnj /* 1612442Swnj * Software clock interrupt. 162*3110Swnj * This routine runs at lower priority than device interrupts. 1632442Swnj */ 1642609Swnj /*ARGSUSED*/ 1652442Swnj softclock(pc, ps) 1662450Swnj caddr_t pc; 1672442Swnj { 1682768Swnj register struct callout *p1, *p2; 1692442Swnj register struct proc *pp; 1702442Swnj register int a, s; 1712442Swnj 1722442Swnj /* 1732872Swnj * Perform callouts (but not after panic's!) 1742442Swnj */ 1752872Swnj if (panicstr == 0 && callout[0].c_time <= 0) { 1762442Swnj p1 = &callout[0]; 1772872Swnj while (p1->c_func != 0 && p1->c_time <= 0) { 1782442Swnj (*p1->c_func)(p1->c_arg); 1792442Swnj p1++; 1802442Swnj } 1812442Swnj p2 = &callout[0]; 1822872Swnj while (p2->c_func = p1->c_func) { 1832442Swnj p2->c_time = p1->c_time; 1842442Swnj p2->c_arg = p1->c_arg; 1852442Swnj p1++; 1862442Swnj p2++; 1872442Swnj } 1882442Swnj } 1892442Swnj 1902442Swnj /* 1912442Swnj * Drain silos. 1922442Swnj */ 1932647Swnj #if NDH > 0 1942442Swnj s = spl5(); dhtimer(); splx(s); 1952442Swnj #endif 1962647Swnj #if NDZ > 0 1972442Swnj s = spl5(); dztimer(); splx(s); 1982442Swnj #endif 1992442Swnj 2002442Swnj /* 2012450Swnj * If idling and processes are waiting to swap in, 2022450Swnj * check on them. 2032450Swnj */ 2042450Swnj if (noproc && runin) { 2052450Swnj runin = 0; 2062450Swnj wakeup((caddr_t)&runin); 2072450Swnj } 2082450Swnj 2092450Swnj /* 2102442Swnj * Run paging daemon and reschedule every 1/4 sec. 2112442Swnj */ 2122768Swnj if (lbolt % (hz/4) == 0) { 2139Sbill vmpago(); 2149Sbill runrun++; 2152442Swnj aston(); 2169Sbill } 2172442Swnj 2182442Swnj /* 2192442Swnj * Lightning bolt every second: 2202442Swnj * sleep timeouts 2212442Swnj * process priority recomputation 2222442Swnj * process %cpu averaging 2232442Swnj * virtual memory metering 2242442Swnj * kick swapper if processes want in 2252442Swnj */ 2262768Swnj if (lbolt >= hz) { 2272872Swnj /* 228*3110Swnj * This doesn't mean much on VAX since we run at 2292872Swnj * software interrupt time... if hardclock() 2302872Swnj * calls softclock() directly, it prevents 2312872Swnj * this code from running when the priority 2322872Swnj * was raised when the clock interrupt occurred. 2332872Swnj */ 2349Sbill if (BASEPRI(ps)) 2359Sbill return; 2362872Swnj 2372872Swnj /* 2382872Swnj * If we didn't run a few times because of 2392872Swnj * long blockage at high ipl, we don't 2402872Swnj * really want to run this code several times, 2412872Swnj * so squish out all multiples of hz here. 2422872Swnj */ 2432872Swnj time += lbolt / hz; 2442872Swnj lbolt %= hz; 2452872Swnj 2462872Swnj /* 2472872Swnj * Wakeup lightning bolt sleepers. 2482872Swnj * Processes sleep on lbolt to wait 2492872Swnj * for short amounts of time (e.g. 1 second). 2502872Swnj */ 2519Sbill wakeup((caddr_t)&lbolt); 2522872Swnj 2532872Swnj /* 2542872Swnj * Recompute process priority and process 2552872Swnj * sleep() system calls as well as internal 2562872Swnj * sleeps with timeouts (tsleep() kernel routine). 2572872Swnj */ 2582872Swnj for (pp = proc; pp < procNPROC; pp++) 259928Sbill if (pp->p_stat && pp->p_stat!=SZOMB) { 2602872Swnj /* 2612872Swnj * Increase resident time, to max of 127 seconds 2622872Swnj * (it is kept in a character.) For 2632872Swnj * loaded processes this is time in core; for 2642872Swnj * swapped processes, this is time on drum. 2652872Swnj */ 2662872Swnj if (pp->p_time != 127) 2679Sbill pp->p_time++; 2682872Swnj /* 2692872Swnj * If process has clock counting down, and it 2702872Swnj * expires, set it running (if this is a tsleep()), 2712872Swnj * or give it an SIGALRM (if the user process 2722872Swnj * is using alarm signals. 2732872Swnj */ 2742872Swnj if (pp->p_clktim && --pp->p_clktim == 0) 2752872Swnj if (pp->p_flag & STIMO) { 2762872Swnj s = spl6(); 2772872Swnj switch (pp->p_stat) { 278204Sbill 2792872Swnj case SSLEEP: 2802872Swnj setrun(pp); 2812872Swnj break; 282204Sbill 2832872Swnj case SSTOP: 2842872Swnj unsleep(pp); 2852872Swnj break; 2862872Swnj } 2872872Swnj pp->p_flag &= ~STIMO; 2882872Swnj splx(s); 2892872Swnj } else 2902872Swnj psignal(pp, SIGALRM); 2912872Swnj /* 2922872Swnj * If process is blocked, increment computed 2932872Swnj * time blocked. This is used in swap scheduling. 2942872Swnj */ 2952872Swnj if (pp->p_stat==SSLEEP || pp->p_stat==SSTOP) 2969Sbill if (pp->p_slptime != 127) 2979Sbill pp->p_slptime++; 2982872Swnj /* 2992872Swnj * Update digital filter estimation of process 3002872Swnj * cpu utilization for loaded processes. 3012872Swnj */ 3021399Sbill if (pp->p_flag&SLOAD) 3031399Sbill pp->p_pctcpu = ccpu * pp->p_pctcpu + 3042768Swnj (1.0 - ccpu) * (pp->p_cpticks/(float)hz); 3052872Swnj /* 3062872Swnj * Recompute process priority. The number p_cpu 3072872Swnj * is a weighted estimate of cpu time consumed. 3082872Swnj * A process which consumes cpu time has this 3092872Swnj * increase regularly. We here decrease it by 3102872Swnj * a fraction (SCHMAG is 90%), giving a digital 3112872Swnj * decay filter which damps out in about 10 seconds. 3122872Swnj * 3132872Swnj * If a process is niced, then the nice directly 3142872Swnj * affects the new priority. The final priority 3152872Swnj * is in the range 0 to 255, to fit in a character. 3162872Swnj */ 3171399Sbill pp->p_cpticks = 0; 3189Sbill a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO; 3192872Swnj if (a < 0) 3209Sbill a = 0; 3212872Swnj if (a > 255) 3229Sbill a = 255; 3239Sbill pp->p_cpu = a; 324125Sbill (void) setpri(pp); 3252872Swnj /* 3262872Swnj * Now have computed new process priority 3272872Swnj * in p->p_usrpri. Carefully change p->p_pri. 3282872Swnj * A process is on a run queue associated with 3292872Swnj * this priority, so we must block out process 3302872Swnj * state changes during the transition. 3312872Swnj */ 3329Sbill s = spl6(); 3332872Swnj if (pp->p_pri >= PUSER) { 3349Sbill if ((pp != u.u_procp || noproc) && 3359Sbill pp->p_stat == SRUN && 3369Sbill (pp->p_flag & SLOAD) && 3379Sbill pp->p_pri != pp->p_usrpri) { 3389Sbill remrq(pp); 3399Sbill pp->p_pri = pp->p_usrpri; 3409Sbill setrq(pp); 3419Sbill } else 3429Sbill pp->p_pri = pp->p_usrpri; 3439Sbill } 3449Sbill splx(s); 3459Sbill } 3462872Swnj 3472872Swnj /* 3482872Swnj * Perform virtual memory metering. 3492872Swnj */ 3509Sbill vmmeter(); 3512872Swnj 3522872Swnj /* 3532872Swnj * If the swap process is trying to bring 3542872Swnj * a process in, have it look again to see 3552872Swnj * if it is possible now. 3562872Swnj */ 3572872Swnj if (runin!=0) { 3589Sbill runin = 0; 3599Sbill wakeup((caddr_t)&runin); 3609Sbill } 3612872Swnj 3629Sbill /* 3639Sbill * If there are pages that have been cleaned, 3649Sbill * jolt the pageout daemon to process them. 3659Sbill * We do this here so that these pages will be 3669Sbill * freed if there is an abundance of memory and the 3679Sbill * daemon would not be awakened otherwise. 3689Sbill */ 3699Sbill if (bclnlist != NULL) 3709Sbill wakeup((caddr_t)&proc[2]); 3712872Swnj 3722872Swnj /* 3732872Swnj * If the trap occurred from usermode, 3742872Swnj * then check to see if it has now been 3752872Swnj * running more than 10 minutes of user time 3762872Swnj * and should thus run with reduced priority 3772872Swnj * to give other processes a chance. 3782872Swnj */ 3799Sbill if (USERMODE(ps)) { 3809Sbill pp = u.u_procp; 3812872Swnj if (pp->p_uid && pp->p_nice == NZERO && 3822872Swnj u.u_vm.vm_utime > 600 * hz) 3832872Swnj pp->p_nice = NZERO+4; 384125Sbill (void) setpri(pp); 3859Sbill pp->p_pri = pp->p_usrpri; 3869Sbill } 3879Sbill } 3882872Swnj /* 3892872Swnj * If trapped user-mode, give it a profiling tick. 3902872Swnj */ 3912442Swnj if (USERMODE(ps) && u.u_prof.pr_scale) { 3922442Swnj u.u_procp->p_flag |= SOWEUPC; 3932442Swnj aston(); 3949Sbill } 3959Sbill } 3969Sbill 3979Sbill /* 398*3110Swnj * Timeout is called to arrange that 3992768Swnj * fun(arg) is called in tim/hz seconds. 4009Sbill * An entry is sorted into the callout 401*3110Swnj * structure. The time in each structure 4022768Swnj * entry is the number of hz's more 4039Sbill * than the previous entry. 4049Sbill * In this way, decrementing the 4059Sbill * first entry has the effect of 4069Sbill * updating all entries. 4079Sbill * 4089Sbill * The panic is there because there is nothing 4099Sbill * intelligent to be done if an entry won't fit. 4109Sbill */ 4119Sbill timeout(fun, arg, tim) 4122450Swnj int (*fun)(); 4132450Swnj caddr_t arg; 4149Sbill { 4152768Swnj register struct callout *p1, *p2, *p3; 4169Sbill register int t; 4179Sbill int s; 4189Sbill 4199Sbill t = tim; 4209Sbill p1 = &callout[0]; 4219Sbill s = spl7(); 422*3110Swnj while (p1->c_func != 0 && p1->c_time <= t) { 4239Sbill t -= p1->c_time; 4249Sbill p1++; 4259Sbill } 4269Sbill p1->c_time -= t; 4279Sbill p2 = p1; 4282768Swnj p3 = callout+(ncallout-2); 429*3110Swnj while (p2->c_func != 0) { 4302430Swnj if (p2 >= p3) 4312442Swnj panic("timeout"); 4329Sbill p2++; 4332430Swnj } 434*3110Swnj while (p2 >= p1) { 4359Sbill (p2+1)->c_time = p2->c_time; 4369Sbill (p2+1)->c_func = p2->c_func; 4379Sbill (p2+1)->c_arg = p2->c_arg; 4389Sbill p2--; 4399Sbill } 4409Sbill p1->c_time = t; 4419Sbill p1->c_func = fun; 4429Sbill p1->c_arg = arg; 4439Sbill splx(s); 4449Sbill } 445