1*2450Swnj /* kern_clock.c 4.8 02/16/81 */ 29Sbill 39Sbill #include "../h/param.h" 49Sbill #include "../h/systm.h" 5329Sbill #include "../h/dk.h" 69Sbill #include "../h/callo.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" 199Sbill 201943Swnj #include "dh.h" 211943Swnj #include "dz.h" 221559Sbill 239Sbill #define SCHMAG 9/10 249Sbill 259Sbill 269Sbill /* 272442Swnj * Hardclock is called straight from 289Sbill * the real time clock interrupt. 292442Swnj * We limit the work we do at real clock interrupt time to: 302442Swnj * reloading clock 312442Swnj * decrementing time to callouts 322442Swnj * recording cpu time usage 33*2450Swnj * modifying priority of current process 342442Swnj * arrange for soft clock interrupt 352442Swnj * kernel pc profiling 369Sbill * 372442Swnj * At softclock interrupt time we: 389Sbill * implement callouts 399Sbill * maintain date 409Sbill * lightning bolt wakeup (every second) 419Sbill * alarm clock signals 429Sbill * jab the scheduler 432442Swnj * 442442Swnj * On the vax softclock interrupts are implemented by 452442Swnj * software interrupts. Note that we may have multiple softclock 462442Swnj * interrupts compressed into one (due to excessive interrupt load), 472442Swnj * but that hardclock interrupts should never be lost. 489Sbill */ 499Sbill 502442Swnj hardclock(pc, ps) 51*2450Swnj caddr_t pc; 529Sbill { 532442Swnj register struct callo *p1; 549Sbill register struct proc *pp; 552442Swnj register long *ip; 562442Swnj register int s, cpstate; 579Sbill 589Sbill /* 599Sbill * reprime clock 609Sbill */ 619Sbill clkreld(); 629Sbill 639Sbill /* 642442Swnj * update callout times 659Sbill */ 669Sbill if(callout[0].c_func == NULL) 679Sbill goto out; 682442Swnj p1 = &callout[0]; 692442Swnj while(p1->c_time<=0 && p1->c_func!=NULL) 702442Swnj p1++; 712442Swnj p1->c_time--; 729Sbill out: 73138Sbill 74138Sbill /* 752442Swnj * Maintain iostat and per-process cpu statistics 76138Sbill */ 779Sbill if (!noproc) { 789Sbill s = u.u_procp->p_rssize; 799Sbill u.u_vm.vm_idsrss += s; 809Sbill if (u.u_procp->p_textp) { 819Sbill register int xrss = u.u_procp->p_textp->x_rssize; 829Sbill 839Sbill s += xrss; 849Sbill u.u_vm.vm_ixrss += xrss; 859Sbill } 869Sbill if (s > u.u_vm.vm_maxrss) 879Sbill u.u_vm.vm_maxrss = s; 88375Sbill if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/HZ > u.u_limit[LIM_CPU]) { 89375Sbill psignal(u.u_procp, SIGXCPU); 90375Sbill if (u.u_limit[LIM_CPU] < INFINITY - 5) 91375Sbill u.u_limit[LIM_CPU] += 5; 92375Sbill } 939Sbill } 949Sbill if (USERMODE(ps)) { 959Sbill u.u_vm.vm_utime++; 969Sbill if(u.u_procp->p_nice > NZERO) 97305Sbill cpstate = CP_NICE; 98305Sbill else 99305Sbill cpstate = CP_USER; 1009Sbill } else { 101305Sbill cpstate = CP_SYS; 1029Sbill if (noproc) 103305Sbill cpstate = CP_IDLE; 1049Sbill else 1059Sbill u.u_vm.vm_stime++; 1069Sbill } 1071408Sbill cp_time[cpstate]++; 1082442Swnj for (s = 0; s < DK_NDRIVE; s++) 1092442Swnj if (dk_busy&(1<<s)) 1102442Swnj dk_time[s]++; 1119Sbill if (!noproc) { 1129Sbill pp = u.u_procp; 1131399Sbill pp->p_cpticks++; 1149Sbill if(++pp->p_cpu == 0) 1159Sbill pp->p_cpu--; 1169Sbill if(pp->p_cpu % 16 == 0) { 117125Sbill (void) setpri(pp); 1189Sbill if (pp->p_pri >= PUSER) 1199Sbill pp->p_pri = pp->p_usrpri; 1209Sbill } 1219Sbill } 1229Sbill ++lbolt; 1232442Swnj #if VAX==780 1242442Swnj if (!BASEPRI(ps)) 1252442Swnj unhang(); 1262442Swnj #endif 1272442Swnj setsoftclock(); 1282442Swnj } 1292442Swnj 1302442Swnj /* 1312442Swnj * Constant for decay filter for cpu usage. 1322442Swnj */ 1332442Swnj double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 1342442Swnj 1352442Swnj /* 1362442Swnj * Software clock interrupt. 1372442Swnj * This routine is blocked by spl1(), 1382442Swnj * which doesn't block device interrupts! 1392442Swnj */ 1402442Swnj softclock(pc, ps) 141*2450Swnj caddr_t pc; 1422442Swnj { 1432442Swnj register struct callo *p1, *p2; 1442442Swnj register struct proc *pp; 1452442Swnj register int a, s; 1462442Swnj 1472442Swnj /* 1482442Swnj * callout 1492442Swnj */ 1502442Swnj if(callout[0].c_time <= 0) { 1512442Swnj p1 = &callout[0]; 1522442Swnj while(p1->c_func != 0 && p1->c_time <= 0) { 1532442Swnj (*p1->c_func)(p1->c_arg); 1542442Swnj p1++; 1552442Swnj } 1562442Swnj p2 = &callout[0]; 1572442Swnj while(p2->c_func = p1->c_func) { 1582442Swnj p2->c_time = p1->c_time; 1592442Swnj p2->c_arg = p1->c_arg; 1602442Swnj p1++; 1612442Swnj p2++; 1622442Swnj } 1632442Swnj } 1642442Swnj 1652442Swnj /* 1662442Swnj * Drain silos. 1672442Swnj */ 1682442Swnj #if NDH11 > 0 1692442Swnj s = spl5(); dhtimer(); splx(s); 1702442Swnj #endif 1712442Swnj #if NDZ11 > 0 1722442Swnj s = spl5(); dztimer(); splx(s); 1732442Swnj #endif 1742442Swnj 1752442Swnj /* 176*2450Swnj * If idling and processes are waiting to swap in, 177*2450Swnj * check on them. 178*2450Swnj */ 179*2450Swnj if (noproc && runin) { 180*2450Swnj runin = 0; 181*2450Swnj wakeup((caddr_t)&runin); 182*2450Swnj } 183*2450Swnj 184*2450Swnj /* 1852442Swnj * Run paging daemon and reschedule every 1/4 sec. 1862442Swnj */ 1879Sbill if (lbolt % (HZ/4) == 0) { 1889Sbill vmpago(); 1899Sbill runrun++; 1902442Swnj aston(); 1919Sbill } 1922442Swnj 1932442Swnj /* 1942442Swnj * Lightning bolt every second: 1952442Swnj * sleep timeouts 1962442Swnj * process priority recomputation 1972442Swnj * process %cpu averaging 1982442Swnj * virtual memory metering 1992442Swnj * kick swapper if processes want in 2002442Swnj */ 2019Sbill if (lbolt >= HZ) { 2029Sbill if (BASEPRI(ps)) 2039Sbill return; 2049Sbill lbolt -= HZ; 2059Sbill ++time; 2069Sbill wakeup((caddr_t)&lbolt); 2079Sbill for(pp = &proc[0]; pp < &proc[NPROC]; pp++) 208928Sbill if (pp->p_stat && pp->p_stat!=SZOMB) { 2099Sbill if(pp->p_time != 127) 2109Sbill pp->p_time++; 2119Sbill if(pp->p_clktim) 2129Sbill if(--pp->p_clktim == 0) 213101Sbill if (pp->p_flag & STIMO) { 214101Sbill s = spl6(); 215204Sbill switch (pp->p_stat) { 216204Sbill 217204Sbill case SSLEEP: 218101Sbill setrun(pp); 219204Sbill break; 220204Sbill 221204Sbill case SSTOP: 222204Sbill unsleep(pp); 223204Sbill break; 224204Sbill } 225101Sbill pp->p_flag &= ~STIMO; 226101Sbill splx(s); 227101Sbill } else 228166Sbill psignal(pp, SIGALRM); 2299Sbill if(pp->p_stat==SSLEEP||pp->p_stat==SSTOP) 2309Sbill if (pp->p_slptime != 127) 2319Sbill pp->p_slptime++; 2321399Sbill if (pp->p_flag&SLOAD) 2331399Sbill pp->p_pctcpu = ccpu * pp->p_pctcpu + 2341399Sbill (1.0 - ccpu) * (pp->p_cpticks/(float)HZ); 2351399Sbill pp->p_cpticks = 0; 2369Sbill a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO; 2379Sbill if(a < 0) 2389Sbill a = 0; 2399Sbill if(a > 255) 2409Sbill a = 255; 2419Sbill pp->p_cpu = a; 242125Sbill (void) setpri(pp); 2439Sbill s = spl6(); 2449Sbill if(pp->p_pri >= PUSER) { 2459Sbill if ((pp != u.u_procp || noproc) && 2469Sbill pp->p_stat == SRUN && 2479Sbill (pp->p_flag & SLOAD) && 2489Sbill pp->p_pri != pp->p_usrpri) { 2499Sbill remrq(pp); 2509Sbill pp->p_pri = pp->p_usrpri; 2519Sbill setrq(pp); 2529Sbill } else 2539Sbill pp->p_pri = pp->p_usrpri; 2549Sbill } 2559Sbill splx(s); 2569Sbill } 2579Sbill vmmeter(); 2589Sbill if(runin!=0) { 2599Sbill runin = 0; 2609Sbill wakeup((caddr_t)&runin); 2619Sbill } 2629Sbill /* 2639Sbill * If there are pages that have been cleaned, 2649Sbill * jolt the pageout daemon to process them. 2659Sbill * We do this here so that these pages will be 2669Sbill * freed if there is an abundance of memory and the 2679Sbill * daemon would not be awakened otherwise. 2689Sbill */ 2699Sbill if (bclnlist != NULL) 2709Sbill wakeup((caddr_t)&proc[2]); 2719Sbill if (USERMODE(ps)) { 2729Sbill pp = u.u_procp; 2739Sbill if (pp->p_uid) 2749Sbill if (pp->p_nice == NZERO && u.u_vm.vm_utime > 600 * HZ) 2759Sbill pp->p_nice = NZERO+4; 276125Sbill (void) setpri(pp); 2779Sbill pp->p_pri = pp->p_usrpri; 2789Sbill } 2799Sbill } 2802442Swnj if (USERMODE(ps) && u.u_prof.pr_scale) { 2812442Swnj u.u_procp->p_flag |= SOWEUPC; 2822442Swnj aston(); 2839Sbill } 2849Sbill } 2859Sbill 2869Sbill /* 2879Sbill * timeout is called to arrange that 2889Sbill * fun(arg) is called in tim/HZ seconds. 2899Sbill * An entry is sorted into the callout 2909Sbill * structure. The time in each structure 2919Sbill * entry is the number of HZ's more 2929Sbill * than the previous entry. 2939Sbill * In this way, decrementing the 2949Sbill * first entry has the effect of 2959Sbill * updating all entries. 2969Sbill * 2979Sbill * The panic is there because there is nothing 2989Sbill * intelligent to be done if an entry won't fit. 2999Sbill */ 3009Sbill timeout(fun, arg, tim) 301*2450Swnj int (*fun)(); 302*2450Swnj caddr_t arg; 3039Sbill { 3042430Swnj register struct callo *p1, *p2, *p3; 3059Sbill register int t; 3069Sbill int s; 3079Sbill 3089Sbill t = tim; 3099Sbill p1 = &callout[0]; 3109Sbill s = spl7(); 3119Sbill while(p1->c_func != 0 && p1->c_time <= t) { 3129Sbill t -= p1->c_time; 3139Sbill p1++; 3149Sbill } 3159Sbill p1->c_time -= t; 3169Sbill p2 = p1; 3172430Swnj p3 = &callout[NCALL-2]; 3182430Swnj while(p2->c_func != 0) { 3192430Swnj if (p2 >= p3) 3202442Swnj panic("timeout"); 3219Sbill p2++; 3222430Swnj } 3239Sbill while(p2 >= p1) { 3249Sbill (p2+1)->c_time = p2->c_time; 3259Sbill (p2+1)->c_func = p2->c_func; 3269Sbill (p2+1)->c_arg = p2->c_arg; 3279Sbill p2--; 3289Sbill } 3299Sbill p1->c_time = t; 3309Sbill p1->c_func = fun; 3319Sbill p1->c_arg = arg; 3329Sbill splx(s); 3339Sbill } 334