1*1888Swnj /* kern_clock.c 4.2 12/16/80 */ 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 201559Sbill #include "../conf/dh.h" 211559Sbill #include "../conf/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++; 1319Sbill if (!noproc) { 1329Sbill s = u.u_procp->p_rssize; 1339Sbill u.u_vm.vm_idsrss += s; 1349Sbill if (u.u_procp->p_textp) { 1359Sbill register int xrss = u.u_procp->p_textp->x_rssize; 1369Sbill 1379Sbill s += xrss; 1389Sbill u.u_vm.vm_ixrss += xrss; 1399Sbill } 1409Sbill if (s > u.u_vm.vm_maxrss) 1419Sbill u.u_vm.vm_maxrss = s; 142375Sbill if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/HZ > u.u_limit[LIM_CPU]) { 143375Sbill psignal(u.u_procp, SIGXCPU); 144375Sbill if (u.u_limit[LIM_CPU] < INFINITY - 5) 145375Sbill u.u_limit[LIM_CPU] += 5; 146375Sbill } 1479Sbill } 1489Sbill if (USERMODE(ps)) { 1499Sbill u.u_vm.vm_utime++; 1509Sbill if(u.u_procp->p_nice > NZERO) 151305Sbill cpstate = CP_NICE; 152305Sbill else 153305Sbill cpstate = CP_USER; 1549Sbill } else { 155305Sbill cpstate = CP_SYS; 1569Sbill if (noproc) 157305Sbill cpstate = CP_IDLE; 1589Sbill else 1599Sbill u.u_vm.vm_stime++; 1609Sbill } 1611408Sbill cp_time[cpstate]++; 1621408Sbill for (i = 0; i < DK_NDRIVE; i++) 1631408Sbill if (dk_busy&(1<<i)) 1641408Sbill dk_time[i]++; 1659Sbill if (!noproc) { 1669Sbill pp = u.u_procp; 1671399Sbill pp->p_cpticks++; 1689Sbill if(++pp->p_cpu == 0) 1699Sbill pp->p_cpu--; 1709Sbill if(pp->p_cpu % 16 == 0) { 171125Sbill (void) setpri(pp); 1729Sbill if (pp->p_pri >= PUSER) 1739Sbill pp->p_pri = pp->p_usrpri; 1749Sbill } 1759Sbill } 1769Sbill ++lbolt; 1779Sbill if (lbolt % (HZ/4) == 0) { 1789Sbill vmpago(); 1799Sbill runrun++; 1809Sbill } 1819Sbill if (lbolt >= HZ) { 182*1888Swnj #if VAX==780 183877Sbill extern int hangcnt; 184*1888Swnj #endif 185877Sbill 1869Sbill if (BASEPRI(ps)) 1879Sbill return; 1889Sbill lbolt -= HZ; 1899Sbill ++time; 190125Sbill (void) spl1(); 191*1888Swnj #if VAX==780 192877Sbill /* 193877Sbill * machdep.c:unhang uses hangcnt to make sure uba 194877Sbill * doesn't forget to interrupt (this has been observed). 195877Sbill * This prevents an accumulation of < 5 second uba failures 196877Sbill * from summing to a uba reset. 197877Sbill */ 198877Sbill if (hangcnt) 199877Sbill hangcnt--; 200*1888Swnj #endif 2019Sbill runrun++; 2029Sbill wakeup((caddr_t)&lbolt); 2039Sbill for(pp = &proc[0]; pp < &proc[NPROC]; pp++) 204928Sbill if (pp->p_stat && pp->p_stat!=SZOMB) { 2059Sbill if(pp->p_time != 127) 2069Sbill pp->p_time++; 2079Sbill if(pp->p_clktim) 2089Sbill if(--pp->p_clktim == 0) 209101Sbill if (pp->p_flag & STIMO) { 210101Sbill s = spl6(); 211204Sbill switch (pp->p_stat) { 212204Sbill 213204Sbill case SSLEEP: 214101Sbill setrun(pp); 215204Sbill break; 216204Sbill 217204Sbill case SSTOP: 218204Sbill unsleep(pp); 219204Sbill break; 220204Sbill } 221101Sbill pp->p_flag &= ~STIMO; 222101Sbill splx(s); 223101Sbill } else 224166Sbill psignal(pp, SIGALRM); 2259Sbill if(pp->p_stat==SSLEEP||pp->p_stat==SSTOP) 2269Sbill if (pp->p_slptime != 127) 2279Sbill pp->p_slptime++; 2281399Sbill if (pp->p_flag&SLOAD) 2291399Sbill pp->p_pctcpu = ccpu * pp->p_pctcpu + 2301399Sbill (1.0 - ccpu) * (pp->p_cpticks/(float)HZ); 2311399Sbill pp->p_cpticks = 0; 2329Sbill a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO; 2339Sbill if(a < 0) 2349Sbill a = 0; 2359Sbill if(a > 255) 2369Sbill a = 255; 2379Sbill pp->p_cpu = a; 238125Sbill (void) setpri(pp); 2399Sbill s = spl6(); 2409Sbill if(pp->p_pri >= PUSER) { 2419Sbill if ((pp != u.u_procp || noproc) && 2429Sbill pp->p_stat == SRUN && 2439Sbill (pp->p_flag & SLOAD) && 2449Sbill pp->p_pri != pp->p_usrpri) { 2459Sbill remrq(pp); 2469Sbill pp->p_pri = pp->p_usrpri; 2479Sbill setrq(pp); 2489Sbill } else 2499Sbill pp->p_pri = pp->p_usrpri; 2509Sbill } 2519Sbill splx(s); 2529Sbill } 2539Sbill vmmeter(); 2549Sbill if(runin!=0) { 2559Sbill runin = 0; 2569Sbill wakeup((caddr_t)&runin); 2579Sbill } 2589Sbill /* 2599Sbill * If there are pages that have been cleaned, 2609Sbill * jolt the pageout daemon to process them. 2619Sbill * We do this here so that these pages will be 2629Sbill * freed if there is an abundance of memory and the 2639Sbill * daemon would not be awakened otherwise. 2649Sbill */ 2659Sbill if (bclnlist != NULL) 2669Sbill wakeup((caddr_t)&proc[2]); 2679Sbill if (USERMODE(ps)) { 2689Sbill pp = u.u_procp; 269362Sbill #ifdef ERNIE 2709Sbill if (pp->p_uid) 2719Sbill if (pp->p_nice == NZERO && u.u_vm.vm_utime > 600 * HZ) 2729Sbill pp->p_nice = NZERO+4; 273125Sbill (void) setpri(pp); 2749Sbill pp->p_pri = pp->p_usrpri; 275362Sbill #endif 2769Sbill } 2779Sbill } 278*1888Swnj #if VAX==780 279277Sbill if (!BASEPRI(ps)) 280277Sbill unhang(); 281*1888Swnj #endif 2829Sbill if (USERMODE(ps)) { 2839Sbill /* 2849Sbill * We do this last since it 2859Sbill * may block on a page fault in user space. 2869Sbill */ 2879Sbill if (u.u_prof.pr_scale) 2889Sbill addupc(pc, &u.u_prof, 1); 2899Sbill } 2909Sbill #ifdef KPROF 2919Sbill else if (!noproc) { 292104Sbill register int indx = ((int)pc & 0x7fffffff) / 4; 2939Sbill 2949Sbill if (indx >= 0 && indx < 20000) 295104Sbill if (++kcount[indx] == 0) 296104Sbill --kcount[indx]; 2979Sbill } 2989Sbill #endif 2999Sbill } 3009Sbill 3019Sbill /* 3029Sbill * timeout is called to arrange that 3039Sbill * fun(arg) is called in tim/HZ seconds. 3049Sbill * An entry is sorted into the callout 3059Sbill * structure. The time in each structure 3069Sbill * entry is the number of HZ's more 3079Sbill * than the previous entry. 3089Sbill * In this way, decrementing the 3099Sbill * first entry has the effect of 3109Sbill * updating all entries. 3119Sbill * 3129Sbill * The panic is there because there is nothing 3139Sbill * intelligent to be done if an entry won't fit. 3149Sbill */ 3159Sbill timeout(fun, arg, tim) 3169Sbill int (*fun)(); 3179Sbill caddr_t arg; 3189Sbill { 3199Sbill register struct callo *p1, *p2; 3209Sbill register int t; 3219Sbill int s; 3229Sbill 3239Sbill t = tim; 3249Sbill p1 = &callout[0]; 3259Sbill s = spl7(); 3269Sbill while(p1->c_func != 0 && p1->c_time <= t) { 3279Sbill t -= p1->c_time; 3289Sbill p1++; 3299Sbill } 3309Sbill if (p1 >= &callout[NCALL-1]) 3319Sbill panic("Timeout table overflow"); 3329Sbill p1->c_time -= t; 3339Sbill p2 = p1; 3349Sbill while(p2->c_func != 0) 3359Sbill p2++; 3369Sbill while(p2 >= p1) { 3379Sbill (p2+1)->c_time = p2->c_time; 3389Sbill (p2+1)->c_func = p2->c_func; 3399Sbill (p2+1)->c_arg = p2->c_arg; 3409Sbill p2--; 3419Sbill } 3429Sbill p1->c_time = t; 3439Sbill p1->c_func = fun; 3449Sbill p1->c_arg = arg; 3459Sbill splx(s); 3469Sbill } 347