1*1408Sbill /* 10/14/12 3.21 kern_clock.c */ 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 209Sbill #define SCHMAG 9/10 219Sbill 221399Sbill /* 231399Sbill * Constant for decay filter for cpu usage. 241399Sbill */ 25*1408Sbill double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 269Sbill 279Sbill /* 281399Sbill * Clock is called straight from 299Sbill * the real time clock interrupt. 309Sbill * 319Sbill * Functions: 329Sbill * implement callouts 339Sbill * maintain user/system times 349Sbill * maintain date 359Sbill * profile 369Sbill * lightning bolt wakeup (every second) 379Sbill * alarm clock signals 389Sbill * jab the scheduler 399Sbill */ 409Sbill #ifdef KPROF 41104Sbill unsigned short kcount[20000]; 429Sbill #endif 439Sbill 44115Sbill /* 45115Sbill * We handle regular calls to the dh and dz silo input processors 46115Sbill * without using timeouts to save a little time. 47115Sbill */ 48142Sbill int rintvl = 0; /* every 1/60'th of sec check receivers */ 49115Sbill int rcnt; 50115Sbill 519Sbill clock(pc, ps) 529Sbill caddr_t pc; 539Sbill { 549Sbill register struct callo *p1, *p2; 559Sbill register struct proc *pp; 569Sbill register int s; 57*1408Sbill int a, cpstate, i; 589Sbill 599Sbill /* 609Sbill * reprime clock 619Sbill */ 629Sbill clkreld(); 639Sbill 649Sbill /* 659Sbill * callouts 669Sbill * else update first non-zero time 679Sbill */ 689Sbill 699Sbill if(callout[0].c_func == NULL) 709Sbill goto out; 719Sbill p2 = &callout[0]; 729Sbill while(p2->c_time<=0 && p2->c_func!=NULL) 739Sbill p2++; 749Sbill p2->c_time--; 759Sbill 769Sbill /* 779Sbill * if ps is high, just return 789Sbill */ 799Sbill if (BASEPRI(ps)) 809Sbill goto out; 819Sbill 829Sbill /* 839Sbill * callout 849Sbill */ 859Sbill 869Sbill if(callout[0].c_time <= 0) { 879Sbill p1 = &callout[0]; 889Sbill while(p1->c_func != 0 && p1->c_time <= 0) { 899Sbill (*p1->c_func)(p1->c_arg); 909Sbill p1++; 919Sbill } 929Sbill p2 = &callout[0]; 939Sbill while(p2->c_func = p1->c_func) { 949Sbill p2->c_time = p1->c_time; 959Sbill p2->c_arg = p1->c_arg; 969Sbill p1++; 979Sbill p2++; 989Sbill } 999Sbill } 1009Sbill 1019Sbill /* 1029Sbill * lightning bolt time-out 1039Sbill * and time of day 1049Sbill */ 1059Sbill out: 106138Sbill 107138Sbill /* 108138Sbill * In order to not take input character interrupts to use 109138Sbill * the input silo on DZ's we have to guarantee to echo 110138Sbill * characters regularly. This means that we have to 111138Sbill * call the timer routines predictably. Since blocking 112138Sbill * in these routines is at spl5(), we have to make spl5() 113138Sbill * really spl6() blocking off the clock to put this code 114138Sbill * here. Note also that it is critical that we run spl5() 115138Sbill * (i.e. really spl6()) in the receiver interrupt routines 116138Sbill * so we can't enter them recursively and transpose characters. 117138Sbill */ 118138Sbill if (rcnt >= rintvl) { 119138Sbill dhtimer(); 120138Sbill dztimer(); 121138Sbill rcnt = 0; 122138Sbill } else 123138Sbill rcnt++; 1249Sbill if (!noproc) { 1259Sbill s = u.u_procp->p_rssize; 1269Sbill u.u_vm.vm_idsrss += s; 1279Sbill if (u.u_procp->p_textp) { 1289Sbill register int xrss = u.u_procp->p_textp->x_rssize; 1299Sbill 1309Sbill s += xrss; 1319Sbill u.u_vm.vm_ixrss += xrss; 1329Sbill } 1339Sbill if (s > u.u_vm.vm_maxrss) 1349Sbill u.u_vm.vm_maxrss = s; 135375Sbill if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/HZ > u.u_limit[LIM_CPU]) { 136375Sbill psignal(u.u_procp, SIGXCPU); 137375Sbill if (u.u_limit[LIM_CPU] < INFINITY - 5) 138375Sbill u.u_limit[LIM_CPU] += 5; 139375Sbill } 1409Sbill } 1419Sbill if (USERMODE(ps)) { 1429Sbill u.u_vm.vm_utime++; 1439Sbill if(u.u_procp->p_nice > NZERO) 144305Sbill cpstate = CP_NICE; 145305Sbill else 146305Sbill cpstate = CP_USER; 1479Sbill } else { 148305Sbill cpstate = CP_SYS; 1499Sbill if (noproc) 150305Sbill cpstate = CP_IDLE; 1519Sbill else 1529Sbill u.u_vm.vm_stime++; 1539Sbill } 154*1408Sbill cp_time[cpstate]++; 155*1408Sbill for (i = 0; i < DK_NDRIVE; i++) 156*1408Sbill if (dk_busy&(1<<i)) 157*1408Sbill dk_time[i]++; 1589Sbill if (!noproc) { 1599Sbill pp = u.u_procp; 1601399Sbill pp->p_cpticks++; 1619Sbill if(++pp->p_cpu == 0) 1629Sbill pp->p_cpu--; 1639Sbill if(pp->p_cpu % 16 == 0) { 164125Sbill (void) setpri(pp); 1659Sbill if (pp->p_pri >= PUSER) 1669Sbill pp->p_pri = pp->p_usrpri; 1679Sbill } 1689Sbill } 1699Sbill ++lbolt; 1709Sbill if (lbolt % (HZ/4) == 0) { 1719Sbill vmpago(); 1729Sbill runrun++; 1739Sbill } 1749Sbill if (lbolt >= HZ) { 175877Sbill extern int hangcnt; 176877Sbill 1779Sbill if (BASEPRI(ps)) 1789Sbill return; 1799Sbill lbolt -= HZ; 1809Sbill ++time; 181125Sbill (void) spl1(); 182877Sbill /* 183877Sbill * machdep.c:unhang uses hangcnt to make sure uba 184877Sbill * doesn't forget to interrupt (this has been observed). 185877Sbill * This prevents an accumulation of < 5 second uba failures 186877Sbill * from summing to a uba reset. 187877Sbill */ 188877Sbill if (hangcnt) 189877Sbill hangcnt--; 1909Sbill runrun++; 1919Sbill wakeup((caddr_t)&lbolt); 1929Sbill for(pp = &proc[0]; pp < &proc[NPROC]; pp++) 193928Sbill if (pp->p_stat && pp->p_stat!=SZOMB) { 1949Sbill if(pp->p_time != 127) 1959Sbill pp->p_time++; 1969Sbill if(pp->p_clktim) 1979Sbill if(--pp->p_clktim == 0) 198101Sbill if (pp->p_flag & STIMO) { 199101Sbill s = spl6(); 200204Sbill switch (pp->p_stat) { 201204Sbill 202204Sbill case SSLEEP: 203101Sbill setrun(pp); 204204Sbill break; 205204Sbill 206204Sbill case SSTOP: 207204Sbill unsleep(pp); 208204Sbill break; 209204Sbill } 210101Sbill pp->p_flag &= ~STIMO; 211101Sbill splx(s); 212101Sbill } else 213166Sbill psignal(pp, SIGALRM); 2149Sbill if(pp->p_stat==SSLEEP||pp->p_stat==SSTOP) 2159Sbill if (pp->p_slptime != 127) 2169Sbill pp->p_slptime++; 2171399Sbill if (pp->p_flag&SLOAD) 2181399Sbill pp->p_pctcpu = ccpu * pp->p_pctcpu + 2191399Sbill (1.0 - ccpu) * (pp->p_cpticks/(float)HZ); 2201399Sbill pp->p_cpticks = 0; 2219Sbill a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO; 2229Sbill if(a < 0) 2239Sbill a = 0; 2249Sbill if(a > 255) 2259Sbill a = 255; 2269Sbill pp->p_cpu = a; 227125Sbill (void) setpri(pp); 2289Sbill s = spl6(); 2299Sbill if(pp->p_pri >= PUSER) { 2309Sbill if ((pp != u.u_procp || noproc) && 2319Sbill pp->p_stat == SRUN && 2329Sbill (pp->p_flag & SLOAD) && 2339Sbill pp->p_pri != pp->p_usrpri) { 2349Sbill remrq(pp); 2359Sbill pp->p_pri = pp->p_usrpri; 2369Sbill setrq(pp); 2379Sbill } else 2389Sbill pp->p_pri = pp->p_usrpri; 2399Sbill } 2409Sbill splx(s); 2419Sbill } 2429Sbill vmmeter(); 2439Sbill if(runin!=0) { 2449Sbill runin = 0; 2459Sbill wakeup((caddr_t)&runin); 2469Sbill } 2479Sbill /* 2489Sbill * If there are pages that have been cleaned, 2499Sbill * jolt the pageout daemon to process them. 2509Sbill * We do this here so that these pages will be 2519Sbill * freed if there is an abundance of memory and the 2529Sbill * daemon would not be awakened otherwise. 2539Sbill */ 2549Sbill if (bclnlist != NULL) 2559Sbill wakeup((caddr_t)&proc[2]); 2569Sbill if (USERMODE(ps)) { 2579Sbill pp = u.u_procp; 258362Sbill #ifdef ERNIE 2599Sbill if (pp->p_uid) 2609Sbill if (pp->p_nice == NZERO && u.u_vm.vm_utime > 600 * HZ) 2619Sbill pp->p_nice = NZERO+4; 262125Sbill (void) setpri(pp); 2639Sbill pp->p_pri = pp->p_usrpri; 264362Sbill #endif 2659Sbill } 2669Sbill } 267277Sbill if (!BASEPRI(ps)) 268277Sbill unhang(); 2699Sbill if (USERMODE(ps)) { 2709Sbill /* 2719Sbill * We do this last since it 2729Sbill * may block on a page fault in user space. 2739Sbill */ 2749Sbill if (u.u_prof.pr_scale) 2759Sbill addupc(pc, &u.u_prof, 1); 2769Sbill } 2779Sbill #ifdef KPROF 2789Sbill else if (!noproc) { 279104Sbill register int indx = ((int)pc & 0x7fffffff) / 4; 2809Sbill 2819Sbill if (indx >= 0 && indx < 20000) 282104Sbill if (++kcount[indx] == 0) 283104Sbill --kcount[indx]; 2849Sbill } 2859Sbill #endif 2869Sbill } 2879Sbill 2889Sbill /* 2899Sbill * timeout is called to arrange that 2909Sbill * fun(arg) is called in tim/HZ seconds. 2919Sbill * An entry is sorted into the callout 2929Sbill * structure. The time in each structure 2939Sbill * entry is the number of HZ's more 2949Sbill * than the previous entry. 2959Sbill * In this way, decrementing the 2969Sbill * first entry has the effect of 2979Sbill * updating all entries. 2989Sbill * 2999Sbill * The panic is there because there is nothing 3009Sbill * intelligent to be done if an entry won't fit. 3019Sbill */ 3029Sbill timeout(fun, arg, tim) 3039Sbill int (*fun)(); 3049Sbill caddr_t arg; 3059Sbill { 3069Sbill register struct callo *p1, *p2; 3079Sbill register int t; 3089Sbill int s; 3099Sbill 3109Sbill t = tim; 3119Sbill p1 = &callout[0]; 3129Sbill s = spl7(); 3139Sbill while(p1->c_func != 0 && p1->c_time <= t) { 3149Sbill t -= p1->c_time; 3159Sbill p1++; 3169Sbill } 3179Sbill if (p1 >= &callout[NCALL-1]) 3189Sbill panic("Timeout table overflow"); 3199Sbill p1->c_time -= t; 3209Sbill p2 = p1; 3219Sbill while(p2->c_func != 0) 3229Sbill p2++; 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