1*3511Sroot /* kern_clock.c 4.19 81/04/13 */ 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 21*3511Sroot #include "bk.h" 221943Swnj #include "dh.h" 231943Swnj #include "dz.h" 241559Sbill 259Sbill /* 262442Swnj * Hardclock is called straight from 279Sbill * the real time clock interrupt. 282442Swnj * We limit the work we do at real clock interrupt time to: 292442Swnj * reloading clock 302442Swnj * decrementing time to callouts 312442Swnj * recording cpu time usage 322450Swnj * modifying priority of current process 332442Swnj * arrange for soft clock interrupt 342442Swnj * kernel pc profiling 359Sbill * 363110Swnj * At software (softclock) interrupt time we: 379Sbill * implement callouts 389Sbill * maintain date 399Sbill * lightning bolt wakeup (every second) 409Sbill * alarm clock signals 419Sbill * jab the scheduler 422442Swnj * 432442Swnj * On the vax softclock interrupts are implemented by 442442Swnj * software interrupts. Note that we may have multiple softclock 452442Swnj * interrupts compressed into one (due to excessive interrupt load), 462442Swnj * but that hardclock interrupts should never be lost. 479Sbill */ 489Sbill 492609Swnj /*ARGSUSED*/ 502442Swnj hardclock(pc, ps) 512450Swnj caddr_t pc; 529Sbill { 532768Swnj register struct callout *p1; 549Sbill register struct proc *pp; 552442Swnj register int s, cpstate; 569Sbill 579Sbill /* 589Sbill * reprime clock 599Sbill */ 609Sbill clkreld(); 619Sbill 629Sbill /* 632442Swnj * update callout times 649Sbill */ 653110Swnj if (callout[0].c_func == NULL) 669Sbill goto out; 672442Swnj p1 = &callout[0]; 683110Swnj while (p1->c_time<=0 && p1->c_func!=NULL) 692442Swnj p1++; 702442Swnj p1->c_time--; 719Sbill out: 72138Sbill 73138Sbill /* 742442Swnj * Maintain iostat and per-process cpu statistics 75138Sbill */ 769Sbill if (!noproc) { 779Sbill s = u.u_procp->p_rssize; 789Sbill u.u_vm.vm_idsrss += s; 799Sbill if (u.u_procp->p_textp) { 809Sbill register int xrss = u.u_procp->p_textp->x_rssize; 819Sbill 829Sbill s += xrss; 839Sbill u.u_vm.vm_ixrss += xrss; 849Sbill } 859Sbill if (s > u.u_vm.vm_maxrss) 869Sbill u.u_vm.vm_maxrss = s; 872768Swnj if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/hz > u.u_limit[LIM_CPU]) { 88375Sbill psignal(u.u_procp, SIGXCPU); 89375Sbill if (u.u_limit[LIM_CPU] < INFINITY - 5) 90375Sbill u.u_limit[LIM_CPU] += 5; 91375Sbill } 929Sbill } 933110Swnj /* 943110Swnj * Update iostat information. 953110Swnj */ 969Sbill if (USERMODE(ps)) { 979Sbill u.u_vm.vm_utime++; 989Sbill if(u.u_procp->p_nice > NZERO) 99305Sbill cpstate = CP_NICE; 100305Sbill else 101305Sbill cpstate = CP_USER; 1029Sbill } else { 103305Sbill cpstate = CP_SYS; 1049Sbill if (noproc) 105305Sbill cpstate = CP_IDLE; 1069Sbill else 1079Sbill u.u_vm.vm_stime++; 1089Sbill } 1091408Sbill cp_time[cpstate]++; 1102442Swnj for (s = 0; s < DK_NDRIVE; s++) 1112442Swnj if (dk_busy&(1<<s)) 1122442Swnj dk_time[s]++; 1133110Swnj /* 1143110Swnj * Adjust priority of current process. 1153110Swnj */ 1169Sbill if (!noproc) { 1179Sbill pp = u.u_procp; 1181399Sbill pp->p_cpticks++; 1199Sbill if(++pp->p_cpu == 0) 1209Sbill pp->p_cpu--; 1219Sbill if(pp->p_cpu % 16 == 0) { 122125Sbill (void) setpri(pp); 1239Sbill if (pp->p_pri >= PUSER) 1249Sbill pp->p_pri = pp->p_usrpri; 1259Sbill } 1269Sbill } 1273110Swnj /* 1283110Swnj * Time moves on. 1293110Swnj */ 1309Sbill ++lbolt; 1312689Swnj #if VAX780 1323110Swnj /* 1333110Swnj * On 780's, impelement a fast UBA watcher, 1343110Swnj * to make sure uba's don't get stuck. 1353110Swnj */ 1362872Swnj if (cpu == VAX_780 && panicstr == 0 && !BASEPRI(ps)) 1372442Swnj unhang(); 1382442Swnj #endif 1393110Swnj /* 1403110Swnj * Schedule a software interrupt for the rest 1413110Swnj * of clock activities. 1423110Swnj */ 1432442Swnj setsoftclock(); 1442442Swnj } 1452442Swnj 1462442Swnj /* 1473110Swnj * SCHMAG is the constant in the digital decay cpu 1483110Swnj * usage priority assignment. Each second we multiply 1493110Swnj * the previous cpu usage estimate by SCHMAG. At 9/10 1503110Swnj * it tends to decay away all knowledge of previous activity 1513110Swnj * in about 10 seconds. 1522442Swnj */ 1533110Swnj #define SCHMAG 9/10 1543110Swnj 1553110Swnj /* 1563110Swnj * Constant for decay filter for cpu usage field 1573110Swnj * in process table (used by ps au). 1583110Swnj */ 1592442Swnj double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 1602442Swnj 1612442Swnj /* 1622442Swnj * Software clock interrupt. 1633110Swnj * This routine runs at lower priority than device interrupts. 1642442Swnj */ 1652609Swnj /*ARGSUSED*/ 1662442Swnj softclock(pc, ps) 1672450Swnj caddr_t pc; 1682442Swnj { 1692768Swnj register struct callout *p1, *p2; 1702442Swnj register struct proc *pp; 1712442Swnj register int a, s; 1722442Swnj 1732442Swnj /* 1742872Swnj * Perform callouts (but not after panic's!) 1752442Swnj */ 1762872Swnj if (panicstr == 0 && callout[0].c_time <= 0) { 1772442Swnj p1 = &callout[0]; 1782872Swnj while (p1->c_func != 0 && p1->c_time <= 0) { 1792442Swnj (*p1->c_func)(p1->c_arg); 1802442Swnj p1++; 1812442Swnj } 1822442Swnj p2 = &callout[0]; 1832872Swnj while (p2->c_func = p1->c_func) { 1842442Swnj p2->c_time = p1->c_time; 1852442Swnj p2->c_arg = p1->c_arg; 1862442Swnj p1++; 1872442Swnj p2++; 1882442Swnj } 1892442Swnj } 1902442Swnj 1912442Swnj /* 1922442Swnj * Drain silos. 1932442Swnj */ 194*3511Sroot #if NBK > 0 1952647Swnj #if NDH > 0 1962442Swnj s = spl5(); dhtimer(); splx(s); 1972442Swnj #endif 1982647Swnj #if NDZ > 0 1992442Swnj s = spl5(); dztimer(); splx(s); 2002442Swnj #endif 201*3511Sroot #endif 2022442Swnj 2032442Swnj /* 2042450Swnj * If idling and processes are waiting to swap in, 2052450Swnj * check on them. 2062450Swnj */ 2072450Swnj if (noproc && runin) { 2082450Swnj runin = 0; 2092450Swnj wakeup((caddr_t)&runin); 2102450Swnj } 2112450Swnj 2122450Swnj /* 2132442Swnj * Run paging daemon and reschedule every 1/4 sec. 2142442Swnj */ 2152768Swnj if (lbolt % (hz/4) == 0) { 2169Sbill vmpago(); 2179Sbill runrun++; 2182442Swnj aston(); 2199Sbill } 2202442Swnj 2212442Swnj /* 2222442Swnj * Lightning bolt every second: 2232442Swnj * sleep timeouts 2242442Swnj * process priority recomputation 2252442Swnj * process %cpu averaging 2262442Swnj * virtual memory metering 2272442Swnj * kick swapper if processes want in 2282442Swnj */ 2292768Swnj if (lbolt >= hz) { 2302872Swnj /* 2313110Swnj * This doesn't mean much on VAX since we run at 2322872Swnj * software interrupt time... if hardclock() 2332872Swnj * calls softclock() directly, it prevents 2342872Swnj * this code from running when the priority 2352872Swnj * was raised when the clock interrupt occurred. 2362872Swnj */ 2379Sbill if (BASEPRI(ps)) 2389Sbill return; 2392872Swnj 2402872Swnj /* 2412872Swnj * If we didn't run a few times because of 2422872Swnj * long blockage at high ipl, we don't 2432872Swnj * really want to run this code several times, 2442872Swnj * so squish out all multiples of hz here. 2452872Swnj */ 2462872Swnj time += lbolt / hz; 2472872Swnj lbolt %= hz; 2482872Swnj 2492872Swnj /* 2502872Swnj * Wakeup lightning bolt sleepers. 2512872Swnj * Processes sleep on lbolt to wait 2522872Swnj * for short amounts of time (e.g. 1 second). 2532872Swnj */ 2549Sbill wakeup((caddr_t)&lbolt); 2552872Swnj 2562872Swnj /* 2572872Swnj * Recompute process priority and process 2582872Swnj * sleep() system calls as well as internal 2592872Swnj * sleeps with timeouts (tsleep() kernel routine). 2602872Swnj */ 2612872Swnj for (pp = proc; pp < procNPROC; pp++) 262928Sbill if (pp->p_stat && pp->p_stat!=SZOMB) { 2632872Swnj /* 2642872Swnj * Increase resident time, to max of 127 seconds 2652872Swnj * (it is kept in a character.) For 2662872Swnj * loaded processes this is time in core; for 2672872Swnj * swapped processes, this is time on drum. 2682872Swnj */ 2692872Swnj if (pp->p_time != 127) 2709Sbill pp->p_time++; 2712872Swnj /* 2722872Swnj * If process has clock counting down, and it 2732872Swnj * expires, set it running (if this is a tsleep()), 2742872Swnj * or give it an SIGALRM (if the user process 2752872Swnj * is using alarm signals. 2762872Swnj */ 2772872Swnj if (pp->p_clktim && --pp->p_clktim == 0) 2782872Swnj if (pp->p_flag & STIMO) { 2792872Swnj s = spl6(); 2802872Swnj switch (pp->p_stat) { 281204Sbill 2822872Swnj case SSLEEP: 2832872Swnj setrun(pp); 2842872Swnj break; 285204Sbill 2862872Swnj case SSTOP: 2872872Swnj unsleep(pp); 2882872Swnj break; 2892872Swnj } 2902872Swnj pp->p_flag &= ~STIMO; 2912872Swnj splx(s); 2922872Swnj } else 2932872Swnj psignal(pp, SIGALRM); 2942872Swnj /* 2952872Swnj * If process is blocked, increment computed 2962872Swnj * time blocked. This is used in swap scheduling. 2972872Swnj */ 2982872Swnj if (pp->p_stat==SSLEEP || pp->p_stat==SSTOP) 2999Sbill if (pp->p_slptime != 127) 3009Sbill pp->p_slptime++; 3012872Swnj /* 3022872Swnj * Update digital filter estimation of process 3032872Swnj * cpu utilization for loaded processes. 3042872Swnj */ 3051399Sbill if (pp->p_flag&SLOAD) 3061399Sbill pp->p_pctcpu = ccpu * pp->p_pctcpu + 3072768Swnj (1.0 - ccpu) * (pp->p_cpticks/(float)hz); 3082872Swnj /* 3092872Swnj * Recompute process priority. The number p_cpu 3102872Swnj * is a weighted estimate of cpu time consumed. 3112872Swnj * A process which consumes cpu time has this 3122872Swnj * increase regularly. We here decrease it by 3132872Swnj * a fraction (SCHMAG is 90%), giving a digital 3142872Swnj * decay filter which damps out in about 10 seconds. 3152872Swnj * 3162872Swnj * If a process is niced, then the nice directly 3172872Swnj * affects the new priority. The final priority 3182872Swnj * is in the range 0 to 255, to fit in a character. 3192872Swnj */ 3201399Sbill pp->p_cpticks = 0; 3219Sbill a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO; 3222872Swnj if (a < 0) 3239Sbill a = 0; 3242872Swnj if (a > 255) 3259Sbill a = 255; 3269Sbill pp->p_cpu = a; 327125Sbill (void) setpri(pp); 3282872Swnj /* 3292872Swnj * Now have computed new process priority 3302872Swnj * in p->p_usrpri. Carefully change p->p_pri. 3312872Swnj * A process is on a run queue associated with 3322872Swnj * this priority, so we must block out process 3332872Swnj * state changes during the transition. 3342872Swnj */ 3359Sbill s = spl6(); 3362872Swnj if (pp->p_pri >= PUSER) { 3379Sbill if ((pp != u.u_procp || noproc) && 3389Sbill pp->p_stat == SRUN && 3399Sbill (pp->p_flag & SLOAD) && 3409Sbill pp->p_pri != pp->p_usrpri) { 3419Sbill remrq(pp); 3429Sbill pp->p_pri = pp->p_usrpri; 3439Sbill setrq(pp); 3449Sbill } else 3459Sbill pp->p_pri = pp->p_usrpri; 3469Sbill } 3479Sbill splx(s); 3489Sbill } 3492872Swnj 3502872Swnj /* 3512872Swnj * Perform virtual memory metering. 3522872Swnj */ 3539Sbill vmmeter(); 3542872Swnj 3552872Swnj /* 3562872Swnj * If the swap process is trying to bring 3572872Swnj * a process in, have it look again to see 3582872Swnj * if it is possible now. 3592872Swnj */ 3602872Swnj if (runin!=0) { 3619Sbill runin = 0; 3629Sbill wakeup((caddr_t)&runin); 3639Sbill } 3642872Swnj 3659Sbill /* 3669Sbill * If there are pages that have been cleaned, 3679Sbill * jolt the pageout daemon to process them. 3689Sbill * We do this here so that these pages will be 3699Sbill * freed if there is an abundance of memory and the 3709Sbill * daemon would not be awakened otherwise. 3719Sbill */ 3729Sbill if (bclnlist != NULL) 3739Sbill wakeup((caddr_t)&proc[2]); 3742872Swnj 3752872Swnj /* 3762872Swnj * If the trap occurred from usermode, 3772872Swnj * then check to see if it has now been 3782872Swnj * running more than 10 minutes of user time 3792872Swnj * and should thus run with reduced priority 3802872Swnj * to give other processes a chance. 3812872Swnj */ 3829Sbill if (USERMODE(ps)) { 3839Sbill pp = u.u_procp; 3842872Swnj if (pp->p_uid && pp->p_nice == NZERO && 3852872Swnj u.u_vm.vm_utime > 600 * hz) 3862872Swnj pp->p_nice = NZERO+4; 387125Sbill (void) setpri(pp); 3889Sbill pp->p_pri = pp->p_usrpri; 3899Sbill } 3909Sbill } 3912872Swnj /* 3922872Swnj * If trapped user-mode, give it a profiling tick. 3932872Swnj */ 3942442Swnj if (USERMODE(ps) && u.u_prof.pr_scale) { 3952442Swnj u.u_procp->p_flag |= SOWEUPC; 3962442Swnj aston(); 3979Sbill } 3989Sbill } 3999Sbill 4009Sbill /* 4013110Swnj * Timeout is called to arrange that 4022768Swnj * fun(arg) is called in tim/hz seconds. 4039Sbill * An entry is sorted into the callout 4043110Swnj * structure. The time in each structure 4052768Swnj * entry is the number of hz's more 4069Sbill * than the previous entry. 4079Sbill * In this way, decrementing the 4089Sbill * first entry has the effect of 4099Sbill * updating all entries. 4109Sbill * 4119Sbill * The panic is there because there is nothing 4129Sbill * intelligent to be done if an entry won't fit. 4139Sbill */ 4149Sbill timeout(fun, arg, tim) 4152450Swnj int (*fun)(); 4162450Swnj caddr_t arg; 4179Sbill { 4182768Swnj register struct callout *p1, *p2, *p3; 4199Sbill register int t; 4209Sbill int s; 4219Sbill 4223446Sroot /* DEBUGGING CODE */ 4233446Sroot int ttrstrt(); 4243446Sroot 4253446Sroot if (fun == ttrstrt && arg == 0) 4263446Sroot panic("timeout ttrstr arg"); 4273446Sroot /* END DEBUGGING CODE */ 4289Sbill t = tim; 4299Sbill p1 = &callout[0]; 4309Sbill s = spl7(); 4313110Swnj while (p1->c_func != 0 && p1->c_time <= t) { 4329Sbill t -= p1->c_time; 4339Sbill p1++; 4349Sbill } 4359Sbill p1->c_time -= t; 4369Sbill p2 = p1; 4372768Swnj p3 = callout+(ncallout-2); 4383110Swnj while (p2->c_func != 0) { 4392430Swnj if (p2 >= p3) 4403481Sroot panic("timeout table overflow"); 4419Sbill p2++; 4422430Swnj } 4433110Swnj while (p2 >= p1) { 4449Sbill (p2+1)->c_time = p2->c_time; 4459Sbill (p2+1)->c_func = p2->c_func; 4469Sbill (p2+1)->c_arg = p2->c_arg; 4479Sbill p2--; 4489Sbill } 4499Sbill p1->c_time = t; 4509Sbill p1->c_func = fun; 4519Sbill p1->c_arg = arg; 4529Sbill splx(s); 4539Sbill } 454