1*2430Swnj /* kern_clock.c 4.6 02/15/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++; 1312208Swnj #ifdef CHAOS 1322208Swnj ch_clock(); 1332208Swnj #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) { 1859Sbill if (BASEPRI(ps)) 1869Sbill return; 1879Sbill lbolt -= HZ; 1889Sbill ++time; 189125Sbill (void) spl1(); 190*2430Swnj #if VAX780 191*2430Swnj ubawatch(); /* should be a timeout */ 1921888Swnj #endif 1939Sbill runrun++; 1949Sbill wakeup((caddr_t)&lbolt); 1959Sbill for(pp = &proc[0]; pp < &proc[NPROC]; pp++) 196928Sbill if (pp->p_stat && pp->p_stat!=SZOMB) { 1979Sbill if(pp->p_time != 127) 1989Sbill pp->p_time++; 1999Sbill if(pp->p_clktim) 2009Sbill if(--pp->p_clktim == 0) 201101Sbill if (pp->p_flag & STIMO) { 202101Sbill s = spl6(); 203204Sbill switch (pp->p_stat) { 204204Sbill 205204Sbill case SSLEEP: 206101Sbill setrun(pp); 207204Sbill break; 208204Sbill 209204Sbill case SSTOP: 210204Sbill unsleep(pp); 211204Sbill break; 212204Sbill } 213101Sbill pp->p_flag &= ~STIMO; 214101Sbill splx(s); 215101Sbill } else 216166Sbill psignal(pp, SIGALRM); 2179Sbill if(pp->p_stat==SSLEEP||pp->p_stat==SSTOP) 2189Sbill if (pp->p_slptime != 127) 2199Sbill pp->p_slptime++; 2201399Sbill if (pp->p_flag&SLOAD) 2211399Sbill pp->p_pctcpu = ccpu * pp->p_pctcpu + 2221399Sbill (1.0 - ccpu) * (pp->p_cpticks/(float)HZ); 2231399Sbill pp->p_cpticks = 0; 2249Sbill a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO; 2259Sbill if(a < 0) 2269Sbill a = 0; 2279Sbill if(a > 255) 2289Sbill a = 255; 2299Sbill pp->p_cpu = a; 230125Sbill (void) setpri(pp); 2319Sbill s = spl6(); 2329Sbill if(pp->p_pri >= PUSER) { 2339Sbill if ((pp != u.u_procp || noproc) && 2349Sbill pp->p_stat == SRUN && 2359Sbill (pp->p_flag & SLOAD) && 2369Sbill pp->p_pri != pp->p_usrpri) { 2379Sbill remrq(pp); 2389Sbill pp->p_pri = pp->p_usrpri; 2399Sbill setrq(pp); 2409Sbill } else 2419Sbill pp->p_pri = pp->p_usrpri; 2429Sbill } 2439Sbill splx(s); 2449Sbill } 2459Sbill vmmeter(); 2469Sbill if(runin!=0) { 2479Sbill runin = 0; 2489Sbill wakeup((caddr_t)&runin); 2499Sbill } 2509Sbill /* 2519Sbill * If there are pages that have been cleaned, 2529Sbill * jolt the pageout daemon to process them. 2539Sbill * We do this here so that these pages will be 2549Sbill * freed if there is an abundance of memory and the 2559Sbill * daemon would not be awakened otherwise. 2569Sbill */ 2579Sbill if (bclnlist != NULL) 2589Sbill wakeup((caddr_t)&proc[2]); 2599Sbill if (USERMODE(ps)) { 2609Sbill pp = u.u_procp; 2619Sbill if (pp->p_uid) 2629Sbill if (pp->p_nice == NZERO && u.u_vm.vm_utime > 600 * HZ) 2639Sbill pp->p_nice = NZERO+4; 264125Sbill (void) setpri(pp); 2659Sbill pp->p_pri = pp->p_usrpri; 2669Sbill } 2679Sbill } 2681888Swnj #if VAX==780 269277Sbill if (!BASEPRI(ps)) 270277Sbill unhang(); 2711888Swnj #endif 2729Sbill if (USERMODE(ps)) { 2739Sbill /* 2749Sbill * We do this last since it 2759Sbill * may block on a page fault in user space. 2769Sbill */ 2779Sbill if (u.u_prof.pr_scale) 2789Sbill addupc(pc, &u.u_prof, 1); 2799Sbill } 2809Sbill #ifdef KPROF 2819Sbill else if (!noproc) { 282104Sbill register int indx = ((int)pc & 0x7fffffff) / 4; 2839Sbill 2849Sbill if (indx >= 0 && indx < 20000) 285104Sbill if (++kcount[indx] == 0) 286104Sbill --kcount[indx]; 2879Sbill } 2889Sbill #endif 2899Sbill } 2909Sbill 2919Sbill /* 2929Sbill * timeout is called to arrange that 2939Sbill * fun(arg) is called in tim/HZ seconds. 2949Sbill * An entry is sorted into the callout 2959Sbill * structure. The time in each structure 2969Sbill * entry is the number of HZ's more 2979Sbill * than the previous entry. 2989Sbill * In this way, decrementing the 2999Sbill * first entry has the effect of 3009Sbill * updating all entries. 3019Sbill * 3029Sbill * The panic is there because there is nothing 3039Sbill * intelligent to be done if an entry won't fit. 3049Sbill */ 3059Sbill timeout(fun, arg, tim) 3069Sbill int (*fun)(); 3079Sbill caddr_t arg; 3089Sbill { 309*2430Swnj register struct callo *p1, *p2, *p3; 3109Sbill register int t; 3119Sbill int s; 3129Sbill 3139Sbill t = tim; 3149Sbill p1 = &callout[0]; 3159Sbill s = spl7(); 3169Sbill while(p1->c_func != 0 && p1->c_time <= t) { 3179Sbill t -= p1->c_time; 3189Sbill p1++; 3199Sbill } 3209Sbill p1->c_time -= t; 3219Sbill p2 = p1; 322*2430Swnj p3 = &callout[NCALL-2]; 323*2430Swnj while(p2->c_func != 0) { 324*2430Swnj if (p2 >= p3) 325*2430Swnj panic("Timeout table overflow"); 3269Sbill p2++; 327*2430Swnj } 3289Sbill while(p2 >= p1) { 3299Sbill (p2+1)->c_time = p2->c_time; 3309Sbill (p2+1)->c_func = p2->c_func; 3319Sbill (p2+1)->c_arg = p2->c_arg; 3329Sbill p2--; 3339Sbill } 3349Sbill p1->c_time = t; 3359Sbill p1->c_func = fun; 3369Sbill p1->c_arg = arg; 3379Sbill splx(s); 3389Sbill } 339