1*2872Swnj /* kern_clock.c 4.15 03/02/81 */ 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 #define SCHMAG 9/10 259Sbill 269Sbill 279Sbill /* 282442Swnj * Hardclock is called straight from 299Sbill * the real time clock interrupt. 302442Swnj * We limit the work we do at real clock interrupt time to: 312442Swnj * reloading clock 322442Swnj * decrementing time to callouts 332442Swnj * recording cpu time usage 342450Swnj * modifying priority of current process 352442Swnj * arrange for soft clock interrupt 362442Swnj * kernel pc profiling 379Sbill * 382442Swnj * At softclock interrupt time we: 399Sbill * implement callouts 409Sbill * maintain date 419Sbill * lightning bolt wakeup (every second) 429Sbill * alarm clock signals 439Sbill * jab the scheduler 442442Swnj * 452442Swnj * On the vax softclock interrupts are implemented by 462442Swnj * software interrupts. Note that we may have multiple softclock 472442Swnj * interrupts compressed into one (due to excessive interrupt load), 482442Swnj * but that hardclock interrupts should never be lost. 499Sbill */ 509Sbill 512609Swnj /*ARGSUSED*/ 522442Swnj hardclock(pc, ps) 532450Swnj caddr_t pc; 549Sbill { 552768Swnj register struct callout *p1; 569Sbill register struct proc *pp; 572442Swnj register int s, cpstate; 589Sbill 599Sbill /* 609Sbill * reprime clock 619Sbill */ 629Sbill clkreld(); 639Sbill 649Sbill /* 652442Swnj * update callout times 669Sbill */ 679Sbill if(callout[0].c_func == NULL) 689Sbill goto out; 692442Swnj p1 = &callout[0]; 702442Swnj while(p1->c_time<=0 && p1->c_func!=NULL) 712442Swnj p1++; 722442Swnj p1->c_time--; 739Sbill out: 74138Sbill 75138Sbill /* 762442Swnj * Maintain iostat and per-process cpu statistics 77138Sbill */ 789Sbill if (!noproc) { 799Sbill s = u.u_procp->p_rssize; 809Sbill u.u_vm.vm_idsrss += s; 819Sbill if (u.u_procp->p_textp) { 829Sbill register int xrss = u.u_procp->p_textp->x_rssize; 839Sbill 849Sbill s += xrss; 859Sbill u.u_vm.vm_ixrss += xrss; 869Sbill } 879Sbill if (s > u.u_vm.vm_maxrss) 889Sbill u.u_vm.vm_maxrss = s; 892768Swnj if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/hz > u.u_limit[LIM_CPU]) { 90375Sbill psignal(u.u_procp, SIGXCPU); 91375Sbill if (u.u_limit[LIM_CPU] < INFINITY - 5) 92375Sbill u.u_limit[LIM_CPU] += 5; 93375Sbill } 949Sbill } 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]++; 1129Sbill if (!noproc) { 1139Sbill pp = u.u_procp; 1141399Sbill pp->p_cpticks++; 1159Sbill if(++pp->p_cpu == 0) 1169Sbill pp->p_cpu--; 1179Sbill if(pp->p_cpu % 16 == 0) { 118125Sbill (void) setpri(pp); 1199Sbill if (pp->p_pri >= PUSER) 1209Sbill pp->p_pri = pp->p_usrpri; 1219Sbill } 1229Sbill } 1239Sbill ++lbolt; 1242689Swnj #if VAX780 125*2872Swnj if (cpu == VAX_780 && panicstr == 0 && !BASEPRI(ps)) 1262442Swnj unhang(); 1272442Swnj #endif 1282442Swnj setsoftclock(); 1292442Swnj } 1302442Swnj 1312442Swnj /* 1322442Swnj * Constant for decay filter for cpu usage. 1332442Swnj */ 1342442Swnj double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 1352442Swnj 1362442Swnj /* 1372442Swnj * Software clock interrupt. 1382442Swnj * This routine is blocked by spl1(), 1392442Swnj * which doesn't block device interrupts! 1402442Swnj */ 1412609Swnj /*ARGSUSED*/ 1422442Swnj softclock(pc, ps) 1432450Swnj caddr_t pc; 1442442Swnj { 1452768Swnj register struct callout *p1, *p2; 1462442Swnj register struct proc *pp; 1472442Swnj register int a, s; 1482442Swnj 1492442Swnj /* 150*2872Swnj * Perform callouts (but not after panic's!) 1512442Swnj */ 152*2872Swnj if (panicstr == 0 && callout[0].c_time <= 0) { 1532442Swnj p1 = &callout[0]; 154*2872Swnj while (p1->c_func != 0 && p1->c_time <= 0) { 1552442Swnj (*p1->c_func)(p1->c_arg); 1562442Swnj p1++; 1572442Swnj } 1582442Swnj p2 = &callout[0]; 159*2872Swnj while (p2->c_func = p1->c_func) { 1602442Swnj p2->c_time = p1->c_time; 1612442Swnj p2->c_arg = p1->c_arg; 1622442Swnj p1++; 1632442Swnj p2++; 1642442Swnj } 1652442Swnj } 1662442Swnj 1672442Swnj /* 1682442Swnj * Drain silos. 1692442Swnj */ 1702647Swnj #if NDH > 0 1712442Swnj s = spl5(); dhtimer(); splx(s); 1722442Swnj #endif 1732647Swnj #if NDZ > 0 1742442Swnj s = spl5(); dztimer(); splx(s); 1752442Swnj #endif 1762442Swnj 1772442Swnj /* 1782450Swnj * If idling and processes are waiting to swap in, 1792450Swnj * check on them. 1802450Swnj */ 1812450Swnj if (noproc && runin) { 1822450Swnj runin = 0; 1832450Swnj wakeup((caddr_t)&runin); 1842450Swnj } 1852450Swnj 1862450Swnj /* 1872442Swnj * Run paging daemon and reschedule every 1/4 sec. 1882442Swnj */ 1892768Swnj if (lbolt % (hz/4) == 0) { 1909Sbill vmpago(); 1919Sbill runrun++; 1922442Swnj aston(); 1939Sbill } 1942442Swnj 1952442Swnj /* 1962442Swnj * Lightning bolt every second: 1972442Swnj * sleep timeouts 1982442Swnj * process priority recomputation 1992442Swnj * process %cpu averaging 2002442Swnj * virtual memory metering 2012442Swnj * kick swapper if processes want in 2022442Swnj */ 2032768Swnj if (lbolt >= hz) { 204*2872Swnj /* 205*2872Swnj * This doesn't mean much since we run at 206*2872Swnj * software interrupt time... if hardclock() 207*2872Swnj * calls softclock() directly, it prevents 208*2872Swnj * this code from running when the priority 209*2872Swnj * was raised when the clock interrupt occurred. 210*2872Swnj */ 2119Sbill if (BASEPRI(ps)) 2129Sbill return; 213*2872Swnj 214*2872Swnj /* 215*2872Swnj * If we didn't run a few times because of 216*2872Swnj * long blockage at high ipl, we don't 217*2872Swnj * really want to run this code several times, 218*2872Swnj * so squish out all multiples of hz here. 219*2872Swnj */ 220*2872Swnj time += lbolt / hz; 221*2872Swnj lbolt %= hz; 222*2872Swnj 223*2872Swnj /* 224*2872Swnj * Wakeup lightning bolt sleepers. 225*2872Swnj * Processes sleep on lbolt to wait 226*2872Swnj * for short amounts of time (e.g. 1 second). 227*2872Swnj */ 2289Sbill wakeup((caddr_t)&lbolt); 229*2872Swnj 230*2872Swnj /* 231*2872Swnj * Recompute process priority and process 232*2872Swnj * sleep() system calls as well as internal 233*2872Swnj * sleeps with timeouts (tsleep() kernel routine). 234*2872Swnj */ 235*2872Swnj for (pp = proc; pp < procNPROC; pp++) 236928Sbill if (pp->p_stat && pp->p_stat!=SZOMB) { 237*2872Swnj /* 238*2872Swnj * Increase resident time, to max of 127 seconds 239*2872Swnj * (it is kept in a character.) For 240*2872Swnj * loaded processes this is time in core; for 241*2872Swnj * swapped processes, this is time on drum. 242*2872Swnj */ 243*2872Swnj if (pp->p_time != 127) 2449Sbill pp->p_time++; 245*2872Swnj /* 246*2872Swnj * If process has clock counting down, and it 247*2872Swnj * expires, set it running (if this is a tsleep()), 248*2872Swnj * or give it an SIGALRM (if the user process 249*2872Swnj * is using alarm signals. 250*2872Swnj */ 251*2872Swnj if (pp->p_clktim && --pp->p_clktim == 0) 252*2872Swnj if (pp->p_flag & STIMO) { 253*2872Swnj s = spl6(); 254*2872Swnj switch (pp->p_stat) { 255204Sbill 256*2872Swnj case SSLEEP: 257*2872Swnj setrun(pp); 258*2872Swnj break; 259204Sbill 260*2872Swnj case SSTOP: 261*2872Swnj unsleep(pp); 262*2872Swnj break; 263*2872Swnj } 264*2872Swnj pp->p_flag &= ~STIMO; 265*2872Swnj splx(s); 266*2872Swnj } else 267*2872Swnj psignal(pp, SIGALRM); 268*2872Swnj /* 269*2872Swnj * If process is blocked, increment computed 270*2872Swnj * time blocked. This is used in swap scheduling. 271*2872Swnj */ 272*2872Swnj if (pp->p_stat==SSLEEP || pp->p_stat==SSTOP) 2739Sbill if (pp->p_slptime != 127) 2749Sbill pp->p_slptime++; 275*2872Swnj /* 276*2872Swnj * Update digital filter estimation of process 277*2872Swnj * cpu utilization for loaded processes. 278*2872Swnj */ 2791399Sbill if (pp->p_flag&SLOAD) 2801399Sbill pp->p_pctcpu = ccpu * pp->p_pctcpu + 2812768Swnj (1.0 - ccpu) * (pp->p_cpticks/(float)hz); 282*2872Swnj /* 283*2872Swnj * Recompute process priority. The number p_cpu 284*2872Swnj * is a weighted estimate of cpu time consumed. 285*2872Swnj * A process which consumes cpu time has this 286*2872Swnj * increase regularly. We here decrease it by 287*2872Swnj * a fraction (SCHMAG is 90%), giving a digital 288*2872Swnj * decay filter which damps out in about 10 seconds. 289*2872Swnj * 290*2872Swnj * If a process is niced, then the nice directly 291*2872Swnj * affects the new priority. The final priority 292*2872Swnj * is in the range 0 to 255, to fit in a character. 293*2872Swnj */ 2941399Sbill pp->p_cpticks = 0; 2959Sbill a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO; 296*2872Swnj if (a < 0) 2979Sbill a = 0; 298*2872Swnj if (a > 255) 2999Sbill a = 255; 3009Sbill pp->p_cpu = a; 301125Sbill (void) setpri(pp); 302*2872Swnj /* 303*2872Swnj * Now have computed new process priority 304*2872Swnj * in p->p_usrpri. Carefully change p->p_pri. 305*2872Swnj * A process is on a run queue associated with 306*2872Swnj * this priority, so we must block out process 307*2872Swnj * state changes during the transition. 308*2872Swnj */ 3099Sbill s = spl6(); 310*2872Swnj if (pp->p_pri >= PUSER) { 3119Sbill if ((pp != u.u_procp || noproc) && 3129Sbill pp->p_stat == SRUN && 3139Sbill (pp->p_flag & SLOAD) && 3149Sbill pp->p_pri != pp->p_usrpri) { 3159Sbill remrq(pp); 3169Sbill pp->p_pri = pp->p_usrpri; 3179Sbill setrq(pp); 3189Sbill } else 3199Sbill pp->p_pri = pp->p_usrpri; 3209Sbill } 3219Sbill splx(s); 3229Sbill } 323*2872Swnj 324*2872Swnj /* 325*2872Swnj * Perform virtual memory metering. 326*2872Swnj */ 3279Sbill vmmeter(); 328*2872Swnj 329*2872Swnj /* 330*2872Swnj * If the swap process is trying to bring 331*2872Swnj * a process in, have it look again to see 332*2872Swnj * if it is possible now. 333*2872Swnj */ 334*2872Swnj if (runin!=0) { 3359Sbill runin = 0; 3369Sbill wakeup((caddr_t)&runin); 3379Sbill } 338*2872Swnj 3399Sbill /* 3409Sbill * If there are pages that have been cleaned, 3419Sbill * jolt the pageout daemon to process them. 3429Sbill * We do this here so that these pages will be 3439Sbill * freed if there is an abundance of memory and the 3449Sbill * daemon would not be awakened otherwise. 3459Sbill */ 3469Sbill if (bclnlist != NULL) 3479Sbill wakeup((caddr_t)&proc[2]); 348*2872Swnj 349*2872Swnj /* 350*2872Swnj * If the trap occurred from usermode, 351*2872Swnj * then check to see if it has now been 352*2872Swnj * running more than 10 minutes of user time 353*2872Swnj * and should thus run with reduced priority 354*2872Swnj * to give other processes a chance. 355*2872Swnj */ 3569Sbill if (USERMODE(ps)) { 3579Sbill pp = u.u_procp; 358*2872Swnj if (pp->p_uid && pp->p_nice == NZERO && 359*2872Swnj u.u_vm.vm_utime > 600 * hz) 360*2872Swnj pp->p_nice = NZERO+4; 361125Sbill (void) setpri(pp); 3629Sbill pp->p_pri = pp->p_usrpri; 3639Sbill } 3649Sbill } 365*2872Swnj /* 366*2872Swnj * If trapped user-mode, give it a profiling tick. 367*2872Swnj */ 3682442Swnj if (USERMODE(ps) && u.u_prof.pr_scale) { 3692442Swnj u.u_procp->p_flag |= SOWEUPC; 3702442Swnj aston(); 3719Sbill } 3729Sbill } 3739Sbill 3749Sbill /* 3759Sbill * timeout is called to arrange that 3762768Swnj * fun(arg) is called in tim/hz seconds. 3779Sbill * An entry is sorted into the callout 3789Sbill * structure. The time in each structure 3792768Swnj * entry is the number of hz's more 3809Sbill * than the previous entry. 3819Sbill * In this way, decrementing the 3829Sbill * first entry has the effect of 3839Sbill * updating all entries. 3849Sbill * 3859Sbill * The panic is there because there is nothing 3869Sbill * intelligent to be done if an entry won't fit. 3879Sbill */ 3889Sbill timeout(fun, arg, tim) 3892450Swnj int (*fun)(); 3902450Swnj caddr_t arg; 3919Sbill { 3922768Swnj register struct callout *p1, *p2, *p3; 3939Sbill register int t; 3949Sbill int s; 3959Sbill 3969Sbill t = tim; 3979Sbill p1 = &callout[0]; 3989Sbill s = spl7(); 3999Sbill while(p1->c_func != 0 && p1->c_time <= t) { 4009Sbill t -= p1->c_time; 4019Sbill p1++; 4029Sbill } 4039Sbill p1->c_time -= t; 4049Sbill p2 = p1; 4052768Swnj p3 = callout+(ncallout-2); 4062430Swnj while(p2->c_func != 0) { 4072430Swnj if (p2 >= p3) 4082442Swnj panic("timeout"); 4099Sbill p2++; 4102430Swnj } 4119Sbill while(p2 >= p1) { 4129Sbill (p2+1)->c_time = p2->c_time; 4139Sbill (p2+1)->c_func = p2->c_func; 4149Sbill (p2+1)->c_arg = p2->c_arg; 4159Sbill p2--; 4169Sbill } 4179Sbill p1->c_time = t; 4189Sbill p1->c_func = fun; 4199Sbill p1->c_arg = arg; 4209Sbill splx(s); 4219Sbill } 422