1*877Sbill /* 10/14/12 3.18 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" 16*877Sbill #include "../h/vlimit.h" 17*877Sbill #include "../h/mtpr.h" 18*877Sbill #include "../h/clock.h" 199Sbill 209Sbill #define SCHMAG 9/10 219Sbill 229Sbill 239Sbill /* 249Sbill * clock is called straight from 259Sbill * the real time clock interrupt. 269Sbill * 279Sbill * Functions: 289Sbill * implement callouts 299Sbill * maintain user/system times 309Sbill * maintain date 319Sbill * profile 329Sbill * lightning bolt wakeup (every second) 339Sbill * alarm clock signals 349Sbill * jab the scheduler 359Sbill */ 369Sbill #ifdef KPROF 37104Sbill unsigned short kcount[20000]; 389Sbill #endif 399Sbill 40115Sbill /* 41115Sbill * We handle regular calls to the dh and dz silo input processors 42115Sbill * without using timeouts to save a little time. 43115Sbill */ 44142Sbill int rintvl = 0; /* every 1/60'th of sec check receivers */ 45115Sbill int rcnt; 46115Sbill 479Sbill clock(pc, ps) 489Sbill caddr_t pc; 499Sbill { 509Sbill register struct callo *p1, *p2; 519Sbill register struct proc *pp; 529Sbill register int s; 53305Sbill int a, cpstate; 549Sbill 559Sbill /* 569Sbill * reprime clock 579Sbill */ 589Sbill clkreld(); 599Sbill 609Sbill /* 619Sbill * callouts 629Sbill * else update first non-zero time 639Sbill */ 649Sbill 659Sbill if(callout[0].c_func == NULL) 669Sbill goto out; 679Sbill p2 = &callout[0]; 689Sbill while(p2->c_time<=0 && p2->c_func!=NULL) 699Sbill p2++; 709Sbill p2->c_time--; 719Sbill 729Sbill /* 739Sbill * if ps is high, just return 749Sbill */ 759Sbill if (BASEPRI(ps)) 769Sbill goto out; 779Sbill 789Sbill /* 799Sbill * callout 809Sbill */ 819Sbill 829Sbill if(callout[0].c_time <= 0) { 839Sbill p1 = &callout[0]; 849Sbill while(p1->c_func != 0 && p1->c_time <= 0) { 859Sbill (*p1->c_func)(p1->c_arg); 869Sbill p1++; 879Sbill } 889Sbill p2 = &callout[0]; 899Sbill while(p2->c_func = p1->c_func) { 909Sbill p2->c_time = p1->c_time; 919Sbill p2->c_arg = p1->c_arg; 929Sbill p1++; 939Sbill p2++; 949Sbill } 959Sbill } 969Sbill 979Sbill /* 989Sbill * lightning bolt time-out 999Sbill * and time of day 1009Sbill */ 1019Sbill out: 102138Sbill 103138Sbill /* 104138Sbill * In order to not take input character interrupts to use 105138Sbill * the input silo on DZ's we have to guarantee to echo 106138Sbill * characters regularly. This means that we have to 107138Sbill * call the timer routines predictably. Since blocking 108138Sbill * in these routines is at spl5(), we have to make spl5() 109138Sbill * really spl6() blocking off the clock to put this code 110138Sbill * here. Note also that it is critical that we run spl5() 111138Sbill * (i.e. really spl6()) in the receiver interrupt routines 112138Sbill * so we can't enter them recursively and transpose characters. 113138Sbill */ 114138Sbill if (rcnt >= rintvl) { 115138Sbill dhtimer(); 116138Sbill dztimer(); 117138Sbill rcnt = 0; 118138Sbill } else 119138Sbill rcnt++; 1209Sbill if (!noproc) { 1219Sbill s = u.u_procp->p_rssize; 1229Sbill u.u_vm.vm_idsrss += s; 1239Sbill if (u.u_procp->p_textp) { 1249Sbill register int xrss = u.u_procp->p_textp->x_rssize; 1259Sbill 1269Sbill s += xrss; 1279Sbill u.u_vm.vm_ixrss += xrss; 1289Sbill } 1299Sbill if (s > u.u_vm.vm_maxrss) 1309Sbill u.u_vm.vm_maxrss = s; 131375Sbill if ((u.u_vm.vm_utime+u.u_vm.vm_stime+1)/HZ > u.u_limit[LIM_CPU]) { 132375Sbill psignal(u.u_procp, SIGXCPU); 133375Sbill if (u.u_limit[LIM_CPU] < INFINITY - 5) 134375Sbill u.u_limit[LIM_CPU] += 5; 135375Sbill } 1369Sbill } 1379Sbill if (USERMODE(ps)) { 1389Sbill u.u_vm.vm_utime++; 1399Sbill if(u.u_procp->p_nice > NZERO) 140305Sbill cpstate = CP_NICE; 141305Sbill else 142305Sbill cpstate = CP_USER; 1439Sbill } else { 144305Sbill cpstate = CP_SYS; 1459Sbill if (noproc) 146305Sbill cpstate = CP_IDLE; 1479Sbill else 1489Sbill u.u_vm.vm_stime++; 1499Sbill } 150305Sbill dk_time[cpstate][dk_busy&(DK_NSTATES-1)]++; 1519Sbill if (!noproc) { 1529Sbill pp = u.u_procp; 1539Sbill if(++pp->p_cpu == 0) 1549Sbill pp->p_cpu--; 1559Sbill if(pp->p_cpu % 16 == 0) { 156125Sbill (void) setpri(pp); 1579Sbill if (pp->p_pri >= PUSER) 1589Sbill pp->p_pri = pp->p_usrpri; 1599Sbill } 1609Sbill } 1619Sbill ++lbolt; 1629Sbill if (lbolt % (HZ/4) == 0) { 1639Sbill vmpago(); 1649Sbill runrun++; 1659Sbill } 1669Sbill if (lbolt >= HZ) { 167*877Sbill extern int hangcnt; 168*877Sbill 1699Sbill if (BASEPRI(ps)) 1709Sbill return; 1719Sbill lbolt -= HZ; 1729Sbill ++time; 173125Sbill (void) spl1(); 174*877Sbill /* 175*877Sbill * machdep.c:unhang uses hangcnt to make sure uba 176*877Sbill * doesn't forget to interrupt (this has been observed). 177*877Sbill * This prevents an accumulation of < 5 second uba failures 178*877Sbill * from summing to a uba reset. 179*877Sbill */ 180*877Sbill if (hangcnt) 181*877Sbill hangcnt--; 1829Sbill runrun++; 1839Sbill wakeup((caddr_t)&lbolt); 1849Sbill for(pp = &proc[0]; pp < &proc[NPROC]; pp++) 1859Sbill if (pp->p_stat && pp->p_stat<SZOMB) { 1869Sbill if(pp->p_time != 127) 1879Sbill pp->p_time++; 1889Sbill if(pp->p_clktim) 1899Sbill if(--pp->p_clktim == 0) 190101Sbill if (pp->p_flag & STIMO) { 191101Sbill s = spl6(); 192204Sbill switch (pp->p_stat) { 193204Sbill 194204Sbill case SSLEEP: 195101Sbill setrun(pp); 196204Sbill break; 197204Sbill 198204Sbill case SSTOP: 199204Sbill unsleep(pp); 200204Sbill break; 201204Sbill } 202101Sbill pp->p_flag &= ~STIMO; 203101Sbill splx(s); 204101Sbill } else 205166Sbill psignal(pp, SIGALRM); 2069Sbill if(pp->p_stat==SSLEEP||pp->p_stat==SSTOP) 2079Sbill if (pp->p_slptime != 127) 2089Sbill pp->p_slptime++; 2099Sbill if(pp->p_flag&SLOAD) { 2109Sbill ave(pp->p_aveflt, pp->p_faults, 5); 2119Sbill pp->p_faults = 0; 2129Sbill } 2139Sbill a = (pp->p_cpu & 0377)*SCHMAG + pp->p_nice - NZERO; 2149Sbill if(a < 0) 2159Sbill a = 0; 2169Sbill if(a > 255) 2179Sbill a = 255; 2189Sbill pp->p_cpu = a; 219125Sbill (void) setpri(pp); 2209Sbill s = spl6(); 2219Sbill if(pp->p_pri >= PUSER) { 2229Sbill if ((pp != u.u_procp || noproc) && 2239Sbill pp->p_stat == SRUN && 2249Sbill (pp->p_flag & SLOAD) && 2259Sbill pp->p_pri != pp->p_usrpri) { 2269Sbill remrq(pp); 2279Sbill pp->p_pri = pp->p_usrpri; 2289Sbill setrq(pp); 2299Sbill } else 2309Sbill pp->p_pri = pp->p_usrpri; 2319Sbill } 2329Sbill splx(s); 2339Sbill } 2349Sbill vmmeter(); 2359Sbill if(runin!=0) { 2369Sbill runin = 0; 2379Sbill wakeup((caddr_t)&runin); 2389Sbill } 2399Sbill /* 2409Sbill * If there are pages that have been cleaned, 2419Sbill * jolt the pageout daemon to process them. 2429Sbill * We do this here so that these pages will be 2439Sbill * freed if there is an abundance of memory and the 2449Sbill * daemon would not be awakened otherwise. 2459Sbill */ 2469Sbill if (bclnlist != NULL) 2479Sbill wakeup((caddr_t)&proc[2]); 2489Sbill if (USERMODE(ps)) { 2499Sbill pp = u.u_procp; 250362Sbill #ifdef ERNIE 2519Sbill if (pp->p_uid) 2529Sbill if (pp->p_nice == NZERO && u.u_vm.vm_utime > 600 * HZ) 2539Sbill pp->p_nice = NZERO+4; 254125Sbill (void) setpri(pp); 2559Sbill pp->p_pri = pp->p_usrpri; 256362Sbill #endif 2579Sbill } 2589Sbill } 259277Sbill if (!BASEPRI(ps)) 260277Sbill unhang(); 2619Sbill if (USERMODE(ps)) { 2629Sbill /* 2639Sbill * We do this last since it 2649Sbill * may block on a page fault in user space. 2659Sbill */ 2669Sbill if (u.u_prof.pr_scale) 2679Sbill addupc(pc, &u.u_prof, 1); 2689Sbill } 2699Sbill #ifdef KPROF 2709Sbill else if (!noproc) { 271104Sbill register int indx = ((int)pc & 0x7fffffff) / 4; 2729Sbill 2739Sbill if (indx >= 0 && indx < 20000) 274104Sbill if (++kcount[indx] == 0) 275104Sbill --kcount[indx]; 2769Sbill } 2779Sbill #endif 2789Sbill } 2799Sbill 2809Sbill /* 2819Sbill * timeout is called to arrange that 2829Sbill * fun(arg) is called in tim/HZ seconds. 2839Sbill * An entry is sorted into the callout 2849Sbill * structure. The time in each structure 2859Sbill * entry is the number of HZ's more 2869Sbill * than the previous entry. 2879Sbill * In this way, decrementing the 2889Sbill * first entry has the effect of 2899Sbill * updating all entries. 2909Sbill * 2919Sbill * The panic is there because there is nothing 2929Sbill * intelligent to be done if an entry won't fit. 2939Sbill */ 2949Sbill timeout(fun, arg, tim) 2959Sbill int (*fun)(); 2969Sbill caddr_t arg; 2979Sbill { 2989Sbill register struct callo *p1, *p2; 2999Sbill register int t; 3009Sbill int s; 3019Sbill 3029Sbill t = tim; 3039Sbill p1 = &callout[0]; 3049Sbill s = spl7(); 3059Sbill while(p1->c_func != 0 && p1->c_time <= t) { 3069Sbill t -= p1->c_time; 3079Sbill p1++; 3089Sbill } 3099Sbill if (p1 >= &callout[NCALL-1]) 3109Sbill panic("Timeout table overflow"); 3119Sbill p1->c_time -= t; 3129Sbill p2 = p1; 3139Sbill while(p2->c_func != 0) 3149Sbill p2++; 3159Sbill while(p2 >= p1) { 3169Sbill (p2+1)->c_time = p2->c_time; 3179Sbill (p2+1)->c_func = p2->c_func; 3189Sbill (p2+1)->c_arg = p2->c_arg; 3199Sbill p2--; 3209Sbill } 3219Sbill p1->c_time = t; 3229Sbill p1->c_func = fun; 3239Sbill p1->c_arg = arg; 3249Sbill splx(s); 3259Sbill } 326