1*2208Swnj /* kern_clock.c 4.4 01/20/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 251399Sbill /* 261399Sbill * Constant for decay filter for cpu usage. 271399Sbill */ 281408Sbill double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 299Sbill 309Sbill /* 311399Sbill * Clock is called straight from 329Sbill * the real time clock interrupt. 339Sbill * 349Sbill * Functions: 359Sbill * implement callouts 369Sbill * maintain user/system times 379Sbill * maintain date 389Sbill * profile 399Sbill * lightning bolt wakeup (every second) 409Sbill * alarm clock signals 419Sbill * jab the scheduler 429Sbill */ 439Sbill #ifdef KPROF 44104Sbill unsigned short kcount[20000]; 459Sbill #endif 469Sbill 47115Sbill /* 48115Sbill * We handle regular calls to the dh and dz silo input processors 49115Sbill * without using timeouts to save a little time. 50115Sbill */ 51142Sbill int rintvl = 0; /* every 1/60'th of sec check receivers */ 52115Sbill int rcnt; 53115Sbill 549Sbill clock(pc, ps) 559Sbill caddr_t pc; 569Sbill { 579Sbill register struct callo *p1, *p2; 589Sbill register struct proc *pp; 599Sbill register int s; 601408Sbill int a, cpstate, i; 619Sbill 629Sbill /* 639Sbill * reprime clock 649Sbill */ 659Sbill clkreld(); 669Sbill 679Sbill /* 689Sbill * callouts 699Sbill * else update first non-zero time 709Sbill */ 719Sbill 729Sbill if(callout[0].c_func == NULL) 739Sbill goto out; 749Sbill p2 = &callout[0]; 759Sbill while(p2->c_time<=0 && p2->c_func!=NULL) 769Sbill p2++; 779Sbill p2->c_time--; 789Sbill 799Sbill /* 809Sbill * if ps is high, just return 819Sbill */ 829Sbill if (BASEPRI(ps)) 839Sbill goto out; 849Sbill 859Sbill /* 869Sbill * callout 879Sbill */ 889Sbill 899Sbill if(callout[0].c_time <= 0) { 909Sbill p1 = &callout[0]; 919Sbill while(p1->c_func != 0 && p1->c_time <= 0) { 929Sbill (*p1->c_func)(p1->c_arg); 939Sbill p1++; 949Sbill } 959Sbill p2 = &callout[0]; 969Sbill while(p2->c_func = p1->c_func) { 979Sbill p2->c_time = p1->c_time; 989Sbill p2->c_arg = p1->c_arg; 999Sbill p1++; 1009Sbill p2++; 1019Sbill } 1029Sbill } 1039Sbill 1049Sbill /* 1059Sbill * lightning bolt time-out 1069Sbill * and time of day 1079Sbill */ 1089Sbill out: 109138Sbill 110138Sbill /* 111138Sbill * In order to not take input character interrupts to use 112138Sbill * the input silo on DZ's we have to guarantee to echo 113138Sbill * characters regularly. This means that we have to 114138Sbill * call the timer routines predictably. Since blocking 115138Sbill * in these routines is at spl5(), we have to make spl5() 116138Sbill * really spl6() blocking off the clock to put this code 117138Sbill * here. Note also that it is critical that we run spl5() 118138Sbill * (i.e. really spl6()) in the receiver interrupt routines 119138Sbill * so we can't enter them recursively and transpose characters. 120138Sbill */ 121138Sbill if (rcnt >= rintvl) { 1221559Sbill #if NDH11 > 0 123138Sbill dhtimer(); 1241559Sbill #endif 1251559Sbill #if NDZ11 > 0 126138Sbill dztimer(); 1271559Sbill #endif 128138Sbill rcnt = 0; 129138Sbill } else 130138Sbill rcnt++; 131*2208Swnj #ifdef CHAOS 132*2208Swnj ch_clock(); 133*2208Swnj #endif 1349Sbill if (!noproc) { 1359Sbill s = u.u_procp->p_rssize; 1369Sbill u.u_vm.vm_idsrss += s; 1379Sbill if (u.u_procp->p_textp) { 1389Sbill register int xrss = u.u_procp->p_textp->x_rssize; 1399Sbill 1409Sbill s += xrss; 1419Sbill u.u_vm.vm_ixrss += xrss; 1429Sbill } 1439Sbill if (s > u.u_vm.vm_maxrss) 1449Sbill u.u_vm.vm_maxrss = s; 145375Sbill if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/HZ > u.u_limit[LIM_CPU]) { 146375Sbill psignal(u.u_procp, SIGXCPU); 147375Sbill if (u.u_limit[LIM_CPU] < INFINITY - 5) 148375Sbill u.u_limit[LIM_CPU] += 5; 149375Sbill } 1509Sbill } 1519Sbill if (USERMODE(ps)) { 1529Sbill u.u_vm.vm_utime++; 1539Sbill if(u.u_procp->p_nice > NZERO) 154305Sbill cpstate = CP_NICE; 155305Sbill else 156305Sbill cpstate = CP_USER; 1579Sbill } else { 158305Sbill cpstate = CP_SYS; 1599Sbill if (noproc) 160305Sbill cpstate = CP_IDLE; 1619Sbill else 1629Sbill u.u_vm.vm_stime++; 1639Sbill } 1641408Sbill cp_time[cpstate]++; 1651408Sbill for (i = 0; i < DK_NDRIVE; i++) 1661408Sbill if (dk_busy&(1<<i)) 1671408Sbill dk_time[i]++; 1689Sbill if (!noproc) { 1699Sbill pp = u.u_procp; 1701399Sbill pp->p_cpticks++; 1719Sbill if(++pp->p_cpu == 0) 1729Sbill pp->p_cpu--; 1739Sbill if(pp->p_cpu % 16 == 0) { 174125Sbill (void) setpri(pp); 1759Sbill if (pp->p_pri >= PUSER) 1769Sbill pp->p_pri = pp->p_usrpri; 1779Sbill } 1789Sbill } 1799Sbill ++lbolt; 1809Sbill if (lbolt % (HZ/4) == 0) { 1819Sbill vmpago(); 1829Sbill runrun++; 1839Sbill } 1849Sbill if (lbolt >= HZ) { 1851888Swnj #if VAX==780 186877Sbill extern int hangcnt; 1871888Swnj #endif 188877Sbill 1899Sbill if (BASEPRI(ps)) 1909Sbill return; 1919Sbill lbolt -= HZ; 1929Sbill ++time; 193125Sbill (void) spl1(); 1941888Swnj #if VAX==780 195877Sbill /* 196877Sbill * machdep.c:unhang uses hangcnt to make sure uba 197877Sbill * doesn't forget to interrupt (this has been observed). 198877Sbill * This prevents an accumulation of < 5 second uba failures 199877Sbill * from summing to a uba reset. 200877Sbill */ 201877Sbill if (hangcnt) 202877Sbill hangcnt--; 2031888Swnj #endif 2049Sbill runrun++; 2059Sbill wakeup((caddr_t)&lbolt); 2069Sbill for(pp = &proc[0]; pp < &proc[NPROC]; pp++) 207928Sbill if (pp->p_stat && pp->p_stat!=SZOMB) { 2089Sbill if(pp->p_time != 127) 2099Sbill pp->p_time++; 2109Sbill if(pp->p_clktim) 2119Sbill if(--pp->p_clktim == 0) 212101Sbill if (pp->p_flag & STIMO) { 213101Sbill s = spl6(); 214204Sbill switch (pp->p_stat) { 215204Sbill 216204Sbill case SSLEEP: 217101Sbill setrun(pp); 218204Sbill break; 219204Sbill 220204Sbill case SSTOP: 221204Sbill unsleep(pp); 222204Sbill break; 223204Sbill } 224101Sbill pp->p_flag &= ~STIMO; 225101Sbill splx(s); 226101Sbill } else 227166Sbill psignal(pp, SIGALRM); 2289Sbill if(pp->p_stat==SSLEEP||pp->p_stat==SSTOP) 2299Sbill if (pp->p_slptime != 127) 2309Sbill pp->p_slptime++; 2311399Sbill if (pp->p_flag&SLOAD) 2321399Sbill pp->p_pctcpu = ccpu * pp->p_pctcpu + 2331399Sbill (1.0 - ccpu) * (pp->p_cpticks/(float)HZ); 2341399Sbill pp->p_cpticks = 0; 2359Sbill a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO; 2369Sbill if(a < 0) 2379Sbill a = 0; 2389Sbill if(a > 255) 2399Sbill a = 255; 2409Sbill pp->p_cpu = a; 241125Sbill (void) setpri(pp); 2429Sbill s = spl6(); 2439Sbill if(pp->p_pri >= PUSER) { 2449Sbill if ((pp != u.u_procp || noproc) && 2459Sbill pp->p_stat == SRUN && 2469Sbill (pp->p_flag & SLOAD) && 2479Sbill pp->p_pri != pp->p_usrpri) { 2489Sbill remrq(pp); 2499Sbill pp->p_pri = pp->p_usrpri; 2509Sbill setrq(pp); 2519Sbill } else 2529Sbill pp->p_pri = pp->p_usrpri; 2539Sbill } 2549Sbill splx(s); 2559Sbill } 2569Sbill vmmeter(); 2579Sbill if(runin!=0) { 2589Sbill runin = 0; 2599Sbill wakeup((caddr_t)&runin); 2609Sbill } 2619Sbill /* 2629Sbill * If there are pages that have been cleaned, 2639Sbill * jolt the pageout daemon to process them. 2649Sbill * We do this here so that these pages will be 2659Sbill * freed if there is an abundance of memory and the 2669Sbill * daemon would not be awakened otherwise. 2679Sbill */ 2689Sbill if (bclnlist != NULL) 2699Sbill wakeup((caddr_t)&proc[2]); 2709Sbill if (USERMODE(ps)) { 2719Sbill pp = u.u_procp; 272362Sbill #ifdef ERNIE 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; 278362Sbill #endif 2799Sbill } 2809Sbill } 2811888Swnj #if VAX==780 282277Sbill if (!BASEPRI(ps)) 283277Sbill unhang(); 2841888Swnj #endif 2859Sbill if (USERMODE(ps)) { 2869Sbill /* 2879Sbill * We do this last since it 2889Sbill * may block on a page fault in user space. 2899Sbill */ 2909Sbill if (u.u_prof.pr_scale) 2919Sbill addupc(pc, &u.u_prof, 1); 2929Sbill } 2939Sbill #ifdef KPROF 2949Sbill else if (!noproc) { 295104Sbill register int indx = ((int)pc & 0x7fffffff) / 4; 2969Sbill 2979Sbill if (indx >= 0 && indx < 20000) 298104Sbill if (++kcount[indx] == 0) 299104Sbill --kcount[indx]; 3009Sbill } 3019Sbill #endif 3029Sbill } 3039Sbill 3049Sbill /* 3059Sbill * timeout is called to arrange that 3069Sbill * fun(arg) is called in tim/HZ seconds. 3079Sbill * An entry is sorted into the callout 3089Sbill * structure. The time in each structure 3099Sbill * entry is the number of HZ's more 3109Sbill * than the previous entry. 3119Sbill * In this way, decrementing the 3129Sbill * first entry has the effect of 3139Sbill * updating all entries. 3149Sbill * 3159Sbill * The panic is there because there is nothing 3169Sbill * intelligent to be done if an entry won't fit. 3179Sbill */ 3189Sbill timeout(fun, arg, tim) 3199Sbill int (*fun)(); 3209Sbill caddr_t arg; 3219Sbill { 3229Sbill register struct callo *p1, *p2; 3239Sbill register int t; 3249Sbill int s; 3259Sbill 3269Sbill t = tim; 3279Sbill p1 = &callout[0]; 3289Sbill s = spl7(); 3299Sbill while(p1->c_func != 0 && p1->c_time <= t) { 3309Sbill t -= p1->c_time; 3319Sbill p1++; 3329Sbill } 3339Sbill if (p1 >= &callout[NCALL-1]) 3349Sbill panic("Timeout table overflow"); 3359Sbill p1->c_time -= t; 3369Sbill p2 = p1; 3379Sbill while(p2->c_func != 0) 3389Sbill p2++; 3399Sbill while(p2 >= p1) { 3409Sbill (p2+1)->c_time = p2->c_time; 3419Sbill (p2+1)->c_func = p2->c_func; 3429Sbill (p2+1)->c_arg = p2->c_arg; 3439Sbill p2--; 3449Sbill } 3459Sbill p1->c_time = t; 3469Sbill p1->c_func = fun; 3479Sbill p1->c_arg = arg; 3489Sbill splx(s); 3499Sbill } 350