1*17093Sbloom /* kern_synch.c 6.4 84/08/29 */ 233Sbill 39756Ssam #include "../machine/pte.h" 49756Ssam 5*17093Sbloom #include "param.h" 6*17093Sbloom #include "systm.h" 7*17093Sbloom #include "dir.h" 8*17093Sbloom #include "user.h" 9*17093Sbloom #include "proc.h" 10*17093Sbloom #include "file.h" 11*17093Sbloom #include "inode.h" 12*17093Sbloom #include "vm.h" 13*17093Sbloom #include "kernel.h" 14*17093Sbloom #include "buf.h" 159756Ssam 169756Ssam #ifdef vax 178445Sroot #include "../vax/mtpr.h" /* XXX */ 189756Ssam #endif 198102Sroot /* 208102Sroot * Force switch among equal priority processes every 100ms. 218102Sroot */ 228102Sroot roundrobin() 238102Sroot { 248102Sroot 258102Sroot runrun++; 268102Sroot aston(); 278624Sroot timeout(roundrobin, (caddr_t)0, hz / 10); 288102Sroot } 298102Sroot 308113Sroot /* constants to digital decay and forget 90% of usage in 5*loadav time */ 318102Sroot #undef ave 328102Sroot #define ave(a,b) ((int)(((int)(a*b))/(b+1))) 338102Sroot int nrscale = 2; 348102Sroot double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 358102Sroot 368102Sroot /* 378102Sroot * Recompute process priorities, once a second 388102Sroot */ 398102Sroot schedcpu() 408102Sroot { 4116795Skarels register double ccpu1 = (1.0 - ccpu) / (double)hz; 428102Sroot register struct proc *p; 438102Sroot register int s, a; 448102Sroot 458102Sroot wakeup((caddr_t)&lbolt); 4616532Skarels for (p = allproc; p != NULL; p = p->p_nxt) { 478102Sroot if (p->p_time != 127) 488102Sroot p->p_time++; 498102Sroot if (p->p_stat==SSLEEP || p->p_stat==SSTOP) 508102Sroot if (p->p_slptime != 127) 518102Sroot p->p_slptime++; 528102Sroot if (p->p_flag&SLOAD) 5316795Skarels p->p_pctcpu = ccpu * p->p_pctcpu + ccpu1 * p->p_cpticks; 548102Sroot p->p_cpticks = 0; 558102Sroot a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) + 568102Sroot p->p_nice - NZERO; 578102Sroot if (a < 0) 588102Sroot a = 0; 598102Sroot if (a > 255) 608102Sroot a = 255; 618102Sroot p->p_cpu = a; 628102Sroot (void) setpri(p); 638102Sroot s = spl6(); /* prevent state changes */ 648102Sroot if (p->p_pri >= PUSER) { 6516795Skarels #define PPQ (128 / NQS) 668102Sroot if ((p != u.u_procp || noproc) && 678102Sroot p->p_stat == SRUN && 688102Sroot (p->p_flag & SLOAD) && 6916795Skarels (p->p_pri / PPQ) != (p->p_usrpri / PPQ)) { 708102Sroot remrq(p); 718102Sroot p->p_pri = p->p_usrpri; 728102Sroot setrq(p); 738102Sroot } else 748102Sroot p->p_pri = p->p_usrpri; 758102Sroot } 768102Sroot splx(s); 778102Sroot } 788102Sroot vmmeter(); 798102Sroot if (runin!=0) { 808102Sroot runin = 0; 818102Sroot wakeup((caddr_t)&runin); 828102Sroot } 838102Sroot if (bclnlist != NULL) 848102Sroot wakeup((caddr_t)&proc[2]); 858624Sroot timeout(schedcpu, (caddr_t)0, hz); 868102Sroot } 878102Sroot 8833Sbill #define SQSIZE 0100 /* Must be power of 2 */ 8933Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 9033Sbill struct proc *slpque[SQSIZE]; 9133Sbill 9233Sbill /* 9333Sbill * Give up the processor till a wakeup occurs 9433Sbill * on chan, at which time the process 9533Sbill * enters the scheduling queue at priority pri. 9633Sbill * The most important effect of pri is that when 9733Sbill * pri<=PZERO a signal cannot disturb the sleep; 9833Sbill * if pri>PZERO signals will be processed. 9933Sbill * Callers of this routine must be prepared for 10033Sbill * premature return, and check that the reason for 10133Sbill * sleeping has gone away. 10233Sbill */ 10333Sbill sleep(chan, pri) 1048033Sroot caddr_t chan; 1058033Sroot int pri; 10633Sbill { 107187Sbill register struct proc *rp, **hp; 108207Sbill register s; 10933Sbill 11033Sbill rp = u.u_procp; 11133Sbill s = spl6(); 11233Sbill if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 11333Sbill panic("sleep"); 11433Sbill rp->p_wchan = chan; 11533Sbill rp->p_slptime = 0; 11633Sbill rp->p_pri = pri; 117187Sbill hp = &slpque[HASH(chan)]; 118187Sbill rp->p_link = *hp; 119187Sbill *hp = rp; 1204826Swnj if (pri > PZERO) { 1214826Swnj if (ISSIG(rp)) { 122187Sbill if (rp->p_wchan) 123187Sbill unsleep(rp); 12433Sbill rp->p_stat = SRUN; 125131Sbill (void) spl0(); 12633Sbill goto psig; 12733Sbill } 128187Sbill if (rp->p_wchan == 0) 129187Sbill goto out; 130187Sbill rp->p_stat = SSLEEP; 131131Sbill (void) spl0(); 1328033Sroot u.u_ru.ru_nvcsw++; 13333Sbill swtch(); 1344826Swnj if (ISSIG(rp)) 13533Sbill goto psig; 13633Sbill } else { 137207Sbill rp->p_stat = SSLEEP; 138131Sbill (void) spl0(); 1398033Sroot u.u_ru.ru_nvcsw++; 14033Sbill swtch(); 14133Sbill } 14216795Skarels curpri = rp->p_usrpri; 143187Sbill out: 14433Sbill splx(s); 14533Sbill return; 14633Sbill 14733Sbill /* 14833Sbill * If priority was low (>PZERO) and 1494826Swnj * there has been a signal, execute non-local goto through 1508113Sroot * u.u_qsave, aborting the system call in progress (see trap.c) 1514826Swnj * (or finishing a tsleep, see below) 15233Sbill */ 15333Sbill psig: 1548113Sroot longjmp(&u.u_qsave); 15533Sbill /*NOTREACHED*/ 15633Sbill } 15733Sbill 15833Sbill /* 159181Sbill * Remove a process from its wait queue 160181Sbill */ 161181Sbill unsleep(p) 1624826Swnj register struct proc *p; 163181Sbill { 164181Sbill register struct proc **hp; 165181Sbill register s; 166181Sbill 167181Sbill s = spl6(); 168181Sbill if (p->p_wchan) { 169181Sbill hp = &slpque[HASH(p->p_wchan)]; 170181Sbill while (*hp != p) 171181Sbill hp = &(*hp)->p_link; 172181Sbill *hp = p->p_link; 173181Sbill p->p_wchan = 0; 174181Sbill } 175181Sbill splx(s); 176181Sbill } 177181Sbill 178181Sbill /* 17933Sbill * Wake up all processes sleeping on chan. 18033Sbill */ 18133Sbill wakeup(chan) 1824826Swnj register caddr_t chan; 18333Sbill { 184187Sbill register struct proc *p, **q, **h; 18533Sbill int s; 18633Sbill 18733Sbill s = spl6(); 188187Sbill h = &slpque[HASH(chan)]; 18933Sbill restart: 190187Sbill for (q = h; p = *q; ) { 191181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 19233Sbill panic("wakeup"); 193207Sbill if (p->p_wchan==chan) { 19433Sbill p->p_wchan = 0; 195187Sbill *q = p->p_link; 19633Sbill p->p_slptime = 0; 197181Sbill if (p->p_stat == SSLEEP) { 198181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 199181Sbill p->p_stat = SRUN; 2002702Swnj if (p->p_flag & SLOAD) 201181Sbill setrq(p); 20216795Skarels /* 20316795Skarels * Since curpri is a usrpri, 20416795Skarels * p->p_pri is always better than curpri. 20516795Skarels */ 20616795Skarels runrun++; 20716795Skarels aston(); 2083545Swnj if ((p->p_flag&SLOAD) == 0) { 2093545Swnj if (runout != 0) { 2103545Swnj runout = 0; 2113545Swnj wakeup((caddr_t)&runout); 2123545Swnj } 2133545Swnj wantin++; 214181Sbill } 215181Sbill /* END INLINE EXPANSION */ 216187Sbill goto restart; 21733Sbill } 218187Sbill } else 219187Sbill q = &p->p_link; 22033Sbill } 22133Sbill splx(s); 22233Sbill } 22333Sbill 22433Sbill /* 22533Sbill * Initialize the (doubly-linked) run queues 22633Sbill * to be empty. 22733Sbill */ 22833Sbill rqinit() 22933Sbill { 23033Sbill register int i; 23133Sbill 23233Sbill for (i = 0; i < NQS; i++) 23333Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 23433Sbill } 23533Sbill 23633Sbill /* 23733Sbill * Set the process running; 23833Sbill * arrange for it to be swapped in if necessary. 23933Sbill */ 24033Sbill setrun(p) 2414826Swnj register struct proc *p; 24233Sbill { 2434826Swnj register int s; 24433Sbill 24533Sbill s = spl6(); 24633Sbill switch (p->p_stat) { 24733Sbill 24833Sbill case 0: 24933Sbill case SWAIT: 25033Sbill case SRUN: 25133Sbill case SZOMB: 25233Sbill default: 25333Sbill panic("setrun"); 25433Sbill 255207Sbill case SSTOP: 25633Sbill case SSLEEP: 257181Sbill unsleep(p); /* e.g. when sending signals */ 25833Sbill break; 25933Sbill 26033Sbill case SIDL: 26133Sbill break; 26233Sbill } 26333Sbill p->p_stat = SRUN; 26433Sbill if (p->p_flag & SLOAD) 26533Sbill setrq(p); 26633Sbill splx(s); 2674826Swnj if (p->p_pri < curpri) { 26833Sbill runrun++; 2692443Swnj aston(); 2702443Swnj } 2713545Swnj if ((p->p_flag&SLOAD) == 0) { 2724826Swnj if (runout != 0) { 2733545Swnj runout = 0; 2743545Swnj wakeup((caddr_t)&runout); 2753545Swnj } 2763545Swnj wantin++; 27733Sbill } 27833Sbill } 27933Sbill 28033Sbill /* 28133Sbill * Set user priority. 28233Sbill * The rescheduling flag (runrun) 28333Sbill * is set if the priority is better 28433Sbill * than the currently running process. 28533Sbill */ 28633Sbill setpri(pp) 2874826Swnj register struct proc *pp; 28833Sbill { 2894826Swnj register int p; 29033Sbill 2913875Swnj p = (pp->p_cpu & 0377)/4; 2921543Sbill p += PUSER + 2*(pp->p_nice - NZERO); 2933530Swnj if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 2943530Swnj p += 2*4; /* effectively, nice(4) */ 2954826Swnj if (p > 127) 29633Sbill p = 127; 2974826Swnj if (p < curpri) { 29833Sbill runrun++; 2992453Swnj aston(); 3002453Swnj } 30133Sbill pp->p_usrpri = p; 3024826Swnj return (p); 30333Sbill } 304