1*9756Ssam /* kern_synch.c 4.25 82/12/17 */ 233Sbill 3*9756Ssam #include "../machine/pte.h" 4*9756Ssam 533Sbill #include "../h/param.h" 633Sbill #include "../h/systm.h" 733Sbill #include "../h/dir.h" 833Sbill #include "../h/user.h" 933Sbill #include "../h/proc.h" 1033Sbill #include "../h/file.h" 1133Sbill #include "../h/inode.h" 1233Sbill #include "../h/vm.h" 138102Sroot #ifdef MUSH 147485Skre #include "../h/quota.h" 158102Sroot #include "../h/share.h" 168102Sroot #endif 178102Sroot #include "../h/kernel.h" 188102Sroot #include "../h/buf.h" 19*9756Ssam 20*9756Ssam #ifdef vax 218445Sroot #include "../vax/mtpr.h" /* XXX */ 22*9756Ssam #endif 238102Sroot /* 248102Sroot * Force switch among equal priority processes every 100ms. 258102Sroot */ 268102Sroot roundrobin() 278102Sroot { 288102Sroot 298102Sroot runrun++; 308102Sroot aston(); 318624Sroot timeout(roundrobin, (caddr_t)0, hz / 10); 328102Sroot } 338102Sroot 348113Sroot /* constants to digital decay and forget 90% of usage in 5*loadav time */ 358102Sroot #undef ave 368102Sroot #define ave(a,b) ((int)(((int)(a*b))/(b+1))) 378102Sroot int nrscale = 2; 388102Sroot double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 398102Sroot 408102Sroot /* 418102Sroot * Recompute process priorities, once a second 428102Sroot */ 438102Sroot schedcpu() 448102Sroot { 458102Sroot register struct proc *p; 468102Sroot register int s, a; 478102Sroot 488102Sroot wakeup((caddr_t)&lbolt); 498102Sroot for (p = proc; p < procNPROC; p++) if (p->p_stat && p->p_stat!=SZOMB) { 508102Sroot #ifdef MUSH 518102Sroot if (p->p_quota->q_uid) 528102Sroot p->p_quota->q_cost += 538102Sroot shconsts.sc_click * p->p_rssize; 548102Sroot #endif 558102Sroot if (p->p_time != 127) 568102Sroot p->p_time++; 578102Sroot if (p->p_stat==SSLEEP || p->p_stat==SSTOP) 588102Sroot if (p->p_slptime != 127) 598102Sroot p->p_slptime++; 608102Sroot if (p->p_flag&SLOAD) 618102Sroot p->p_pctcpu = ccpu * p->p_pctcpu + 628102Sroot (1.0 - ccpu) * (p->p_cpticks/(float)hz); 638102Sroot p->p_cpticks = 0; 648102Sroot #ifdef MUSH 658102Sroot a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) + 668102Sroot p->p_nice - NZERO + p->p_quota->q_nice; 678102Sroot #else 688102Sroot a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) + 698102Sroot p->p_nice - NZERO; 708102Sroot #endif 718102Sroot if (a < 0) 728102Sroot a = 0; 738102Sroot if (a > 255) 748102Sroot a = 255; 758102Sroot p->p_cpu = a; 768102Sroot (void) setpri(p); 778102Sroot s = spl6(); /* prevent state changes */ 788102Sroot if (p->p_pri >= PUSER) { 798102Sroot if ((p != u.u_procp || noproc) && 808102Sroot p->p_stat == SRUN && 818102Sroot (p->p_flag & SLOAD) && 828102Sroot p->p_pri != p->p_usrpri) { 838102Sroot remrq(p); 848102Sroot p->p_pri = p->p_usrpri; 858102Sroot setrq(p); 868102Sroot } else 878102Sroot p->p_pri = p->p_usrpri; 888102Sroot } 898102Sroot splx(s); 908102Sroot } 918102Sroot vmmeter(); 928102Sroot if (runin!=0) { 938102Sroot runin = 0; 948102Sroot wakeup((caddr_t)&runin); 958102Sroot } 968102Sroot if (bclnlist != NULL) 978102Sroot wakeup((caddr_t)&proc[2]); 988624Sroot timeout(schedcpu, (caddr_t)0, hz); 998102Sroot } 1008102Sroot 10133Sbill #define SQSIZE 0100 /* Must be power of 2 */ 10233Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 10333Sbill struct proc *slpque[SQSIZE]; 10433Sbill 10533Sbill /* 10633Sbill * Give up the processor till a wakeup occurs 10733Sbill * on chan, at which time the process 10833Sbill * enters the scheduling queue at priority pri. 10933Sbill * The most important effect of pri is that when 11033Sbill * pri<=PZERO a signal cannot disturb the sleep; 11133Sbill * if pri>PZERO signals will be processed. 11233Sbill * Callers of this routine must be prepared for 11333Sbill * premature return, and check that the reason for 11433Sbill * sleeping has gone away. 11533Sbill */ 11633Sbill sleep(chan, pri) 1178033Sroot caddr_t chan; 1188033Sroot int pri; 11933Sbill { 120187Sbill register struct proc *rp, **hp; 121207Sbill register s; 12233Sbill 12333Sbill rp = u.u_procp; 12433Sbill s = spl6(); 12533Sbill if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 12633Sbill panic("sleep"); 12733Sbill rp->p_wchan = chan; 12833Sbill rp->p_slptime = 0; 12933Sbill rp->p_pri = pri; 130187Sbill hp = &slpque[HASH(chan)]; 131187Sbill rp->p_link = *hp; 132187Sbill *hp = rp; 1334826Swnj if (pri > PZERO) { 1344826Swnj if (ISSIG(rp)) { 135187Sbill if (rp->p_wchan) 136187Sbill unsleep(rp); 13733Sbill rp->p_stat = SRUN; 138131Sbill (void) spl0(); 13933Sbill goto psig; 14033Sbill } 141187Sbill if (rp->p_wchan == 0) 142187Sbill goto out; 143187Sbill rp->p_stat = SSLEEP; 144131Sbill (void) spl0(); 1458033Sroot u.u_ru.ru_nvcsw++; 14633Sbill swtch(); 1474826Swnj if (ISSIG(rp)) 14833Sbill goto psig; 14933Sbill } else { 150207Sbill rp->p_stat = SSLEEP; 151131Sbill (void) spl0(); 1528033Sroot u.u_ru.ru_nvcsw++; 15333Sbill swtch(); 15433Sbill } 155187Sbill out: 15633Sbill splx(s); 15733Sbill return; 15833Sbill 15933Sbill /* 16033Sbill * If priority was low (>PZERO) and 1614826Swnj * there has been a signal, execute non-local goto through 1628113Sroot * u.u_qsave, aborting the system call in progress (see trap.c) 1634826Swnj * (or finishing a tsleep, see below) 16433Sbill */ 16533Sbill psig: 1668113Sroot longjmp(&u.u_qsave); 16733Sbill /*NOTREACHED*/ 16833Sbill } 16933Sbill 17033Sbill /* 171181Sbill * Remove a process from its wait queue 172181Sbill */ 173181Sbill unsleep(p) 1744826Swnj register struct proc *p; 175181Sbill { 176181Sbill register struct proc **hp; 177181Sbill register s; 178181Sbill 179181Sbill s = spl6(); 180181Sbill if (p->p_wchan) { 181181Sbill hp = &slpque[HASH(p->p_wchan)]; 182181Sbill while (*hp != p) 183181Sbill hp = &(*hp)->p_link; 184181Sbill *hp = p->p_link; 185181Sbill p->p_wchan = 0; 186181Sbill } 187181Sbill splx(s); 188181Sbill } 189181Sbill 190181Sbill /* 19133Sbill * Wake up all processes sleeping on chan. 19233Sbill */ 19333Sbill wakeup(chan) 1944826Swnj register caddr_t chan; 19533Sbill { 196187Sbill register struct proc *p, **q, **h; 19733Sbill int s; 19833Sbill 19933Sbill s = spl6(); 200187Sbill h = &slpque[HASH(chan)]; 20133Sbill restart: 202187Sbill for (q = h; p = *q; ) { 203181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 20433Sbill panic("wakeup"); 205207Sbill if (p->p_wchan==chan) { 20633Sbill p->p_wchan = 0; 207187Sbill *q = p->p_link; 20833Sbill p->p_slptime = 0; 209181Sbill if (p->p_stat == SSLEEP) { 210181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 211181Sbill p->p_stat = SRUN; 2122702Swnj if (p->p_flag & SLOAD) 213181Sbill setrq(p); 2144826Swnj if (p->p_pri < curpri) { 215181Sbill runrun++; 2162443Swnj aston(); 2172443Swnj } 2183545Swnj if ((p->p_flag&SLOAD) == 0) { 2193545Swnj if (runout != 0) { 2203545Swnj runout = 0; 2213545Swnj wakeup((caddr_t)&runout); 2223545Swnj } 2233545Swnj wantin++; 224181Sbill } 225181Sbill /* END INLINE EXPANSION */ 226187Sbill goto restart; 22733Sbill } 228187Sbill } else 229187Sbill q = &p->p_link; 23033Sbill } 23133Sbill splx(s); 23233Sbill } 23333Sbill 23433Sbill /* 23533Sbill * Initialize the (doubly-linked) run queues 23633Sbill * to be empty. 23733Sbill */ 23833Sbill rqinit() 23933Sbill { 24033Sbill register int i; 24133Sbill 24233Sbill for (i = 0; i < NQS; i++) 24333Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 24433Sbill } 24533Sbill 24633Sbill /* 24733Sbill * Set the process running; 24833Sbill * arrange for it to be swapped in if necessary. 24933Sbill */ 25033Sbill setrun(p) 2514826Swnj register struct proc *p; 25233Sbill { 2534826Swnj register int s; 25433Sbill 25533Sbill s = spl6(); 25633Sbill switch (p->p_stat) { 25733Sbill 25833Sbill case 0: 25933Sbill case SWAIT: 26033Sbill case SRUN: 26133Sbill case SZOMB: 26233Sbill default: 26333Sbill panic("setrun"); 26433Sbill 265207Sbill case SSTOP: 26633Sbill case SSLEEP: 267181Sbill unsleep(p); /* e.g. when sending signals */ 26833Sbill break; 26933Sbill 27033Sbill case SIDL: 27133Sbill break; 27233Sbill } 27333Sbill p->p_stat = SRUN; 27433Sbill if (p->p_flag & SLOAD) 27533Sbill setrq(p); 27633Sbill splx(s); 2774826Swnj if (p->p_pri < curpri) { 27833Sbill runrun++; 2792443Swnj aston(); 2802443Swnj } 2813545Swnj if ((p->p_flag&SLOAD) == 0) { 2824826Swnj if (runout != 0) { 2833545Swnj runout = 0; 2843545Swnj wakeup((caddr_t)&runout); 2853545Swnj } 2863545Swnj wantin++; 28733Sbill } 28833Sbill } 28933Sbill 29033Sbill /* 29133Sbill * Set user priority. 29233Sbill * The rescheduling flag (runrun) 29333Sbill * is set if the priority is better 29433Sbill * than the currently running process. 29533Sbill */ 29633Sbill setpri(pp) 2974826Swnj register struct proc *pp; 29833Sbill { 2994826Swnj register int p; 30033Sbill 3013875Swnj p = (pp->p_cpu & 0377)/4; 3021543Sbill p += PUSER + 2*(pp->p_nice - NZERO); 3033530Swnj if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 3043530Swnj p += 2*4; /* effectively, nice(4) */ 3054826Swnj if (p > 127) 30633Sbill p = 127; 3074826Swnj if (p < curpri) { 30833Sbill runrun++; 3092453Swnj aston(); 3102453Swnj } 31133Sbill pp->p_usrpri = p; 3124826Swnj return (p); 31333Sbill } 314