1*8113Sroot /* kern_synch.c 4.21 82/09/08 */ 233Sbill 333Sbill #include "../h/param.h" 433Sbill #include "../h/systm.h" 533Sbill #include "../h/dir.h" 633Sbill #include "../h/user.h" 733Sbill #include "../h/proc.h" 833Sbill #include "../h/file.h" 933Sbill #include "../h/inode.h" 1033Sbill #include "../h/vm.h" 1133Sbill #include "../h/pte.h" 12181Sbill #include "../h/inline.h" 132443Swnj #include "../h/mtpr.h" 148102Sroot #ifdef MUSH 157485Skre #include "../h/quota.h" 168102Sroot #include "../h/share.h" 178102Sroot #endif 188102Sroot #include "../h/kernel.h" 198102Sroot #include "../h/buf.h" 2033Sbill 218102Sroot /* 228102Sroot * Force switch among equal priority processes every 100ms. 238102Sroot */ 248102Sroot roundrobin() 258102Sroot { 268102Sroot 278102Sroot runrun++; 288102Sroot aston(); 298102Sroot timeout(roundrobin, 0, hz / 10); 308102Sroot } 318102Sroot 32*8113Sroot /* constants to digital decay and forget 90% of usage in 5*loadav time */ 338102Sroot #undef ave 348102Sroot #define ave(a,b) ((int)(((int)(a*b))/(b+1))) 358102Sroot int nrscale = 2; 368102Sroot double avenrun[]; 378102Sroot double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 388102Sroot 398102Sroot /* 408102Sroot * Recompute process priorities, once a second 418102Sroot */ 428102Sroot schedcpu() 438102Sroot { 448102Sroot register struct proc *p; 458102Sroot register int s, a; 468102Sroot 478102Sroot wakeup((caddr_t)&lbolt); 488102Sroot for (p = proc; p < procNPROC; p++) if (p->p_stat && p->p_stat!=SZOMB) { 498102Sroot #ifdef MUSH 508102Sroot if (p->p_quota->q_uid) 518102Sroot p->p_quota->q_cost += 528102Sroot shconsts.sc_click * p->p_rssize; 538102Sroot #endif 548102Sroot if (p->p_time != 127) 558102Sroot p->p_time++; 568102Sroot if (p->p_stat==SSLEEP || p->p_stat==SSTOP) 578102Sroot if (p->p_slptime != 127) 588102Sroot p->p_slptime++; 598102Sroot if (p->p_flag&SLOAD) 608102Sroot p->p_pctcpu = ccpu * p->p_pctcpu + 618102Sroot (1.0 - ccpu) * (p->p_cpticks/(float)hz); 628102Sroot p->p_cpticks = 0; 638102Sroot #ifdef MUSH 648102Sroot a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) + 658102Sroot p->p_nice - NZERO + p->p_quota->q_nice; 668102Sroot #else 678102Sroot a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) + 688102Sroot p->p_nice - NZERO; 698102Sroot #endif 708102Sroot if (a < 0) 718102Sroot a = 0; 728102Sroot if (a > 255) 738102Sroot a = 255; 748102Sroot p->p_cpu = a; 758102Sroot (void) setpri(p); 768102Sroot s = spl6(); /* prevent state changes */ 778102Sroot if (p->p_pri >= PUSER) { 788102Sroot if ((p != u.u_procp || noproc) && 798102Sroot p->p_stat == SRUN && 808102Sroot (p->p_flag & SLOAD) && 818102Sroot p->p_pri != p->p_usrpri) { 828102Sroot remrq(p); 838102Sroot p->p_pri = p->p_usrpri; 848102Sroot setrq(p); 858102Sroot } else 868102Sroot p->p_pri = p->p_usrpri; 878102Sroot } 888102Sroot splx(s); 898102Sroot } 908102Sroot vmmeter(); 918102Sroot if (runin!=0) { 928102Sroot runin = 0; 938102Sroot wakeup((caddr_t)&runin); 948102Sroot } 958102Sroot if (bclnlist != NULL) 968102Sroot wakeup((caddr_t)&proc[2]); 978102Sroot timeout(schedcpu, 0, hz); 988102Sroot } 998102Sroot 10033Sbill #define SQSIZE 0100 /* Must be power of 2 */ 10133Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 10233Sbill struct proc *slpque[SQSIZE]; 10333Sbill 10433Sbill /* 10533Sbill * Give up the processor till a wakeup occurs 10633Sbill * on chan, at which time the process 10733Sbill * enters the scheduling queue at priority pri. 10833Sbill * The most important effect of pri is that when 10933Sbill * pri<=PZERO a signal cannot disturb the sleep; 11033Sbill * if pri>PZERO signals will be processed. 11133Sbill * Callers of this routine must be prepared for 11233Sbill * premature return, and check that the reason for 11333Sbill * sleeping has gone away. 11433Sbill */ 11533Sbill sleep(chan, pri) 1168033Sroot caddr_t chan; 1178033Sroot int pri; 11833Sbill { 119187Sbill register struct proc *rp, **hp; 120207Sbill register s; 12133Sbill 12233Sbill rp = u.u_procp; 12333Sbill s = spl6(); 12433Sbill if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 12533Sbill panic("sleep"); 12633Sbill rp->p_wchan = chan; 12733Sbill rp->p_slptime = 0; 12833Sbill rp->p_pri = pri; 129187Sbill hp = &slpque[HASH(chan)]; 130187Sbill rp->p_link = *hp; 131187Sbill *hp = rp; 1324826Swnj if (pri > PZERO) { 1334826Swnj if (ISSIG(rp)) { 134187Sbill if (rp->p_wchan) 135187Sbill unsleep(rp); 13633Sbill rp->p_stat = SRUN; 137131Sbill (void) spl0(); 13833Sbill goto psig; 13933Sbill } 140187Sbill if (rp->p_wchan == 0) 141187Sbill goto out; 142187Sbill rp->p_stat = SSLEEP; 143131Sbill (void) spl0(); 1448033Sroot u.u_ru.ru_nvcsw++; 14533Sbill swtch(); 1464826Swnj if (ISSIG(rp)) 14733Sbill goto psig; 14833Sbill } else { 149207Sbill rp->p_stat = SSLEEP; 150131Sbill (void) spl0(); 1518033Sroot u.u_ru.ru_nvcsw++; 15233Sbill swtch(); 15333Sbill } 154187Sbill out: 15533Sbill splx(s); 15633Sbill return; 15733Sbill 15833Sbill /* 15933Sbill * If priority was low (>PZERO) and 1604826Swnj * there has been a signal, execute non-local goto through 161*8113Sroot * u.u_qsave, aborting the system call in progress (see trap.c) 1624826Swnj * (or finishing a tsleep, see below) 16333Sbill */ 16433Sbill psig: 165*8113Sroot longjmp(&u.u_qsave); 16633Sbill /*NOTREACHED*/ 16733Sbill } 16833Sbill 16933Sbill /* 170181Sbill * Remove a process from its wait queue 171181Sbill */ 172181Sbill unsleep(p) 1734826Swnj register struct proc *p; 174181Sbill { 175181Sbill register struct proc **hp; 176181Sbill register s; 177181Sbill 178181Sbill s = spl6(); 179181Sbill if (p->p_wchan) { 180181Sbill hp = &slpque[HASH(p->p_wchan)]; 181181Sbill while (*hp != p) 182181Sbill hp = &(*hp)->p_link; 183181Sbill *hp = p->p_link; 184181Sbill p->p_wchan = 0; 185181Sbill } 186181Sbill splx(s); 187181Sbill } 188181Sbill 189181Sbill /* 19033Sbill * Wake up all processes sleeping on chan. 19133Sbill */ 19233Sbill wakeup(chan) 1934826Swnj register caddr_t chan; 19433Sbill { 195187Sbill register struct proc *p, **q, **h; 19633Sbill int s; 19733Sbill 19833Sbill s = spl6(); 199187Sbill h = &slpque[HASH(chan)]; 20033Sbill restart: 201187Sbill for (q = h; p = *q; ) { 202181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 20333Sbill panic("wakeup"); 204207Sbill if (p->p_wchan==chan) { 20533Sbill p->p_wchan = 0; 206187Sbill *q = p->p_link; 20733Sbill p->p_slptime = 0; 208181Sbill if (p->p_stat == SSLEEP) { 209181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 210181Sbill p->p_stat = SRUN; 2112702Swnj if (p->p_flag & SLOAD) 212181Sbill setrq(p); 2134826Swnj if (p->p_pri < curpri) { 214181Sbill runrun++; 2152443Swnj aston(); 2162443Swnj } 2173545Swnj if ((p->p_flag&SLOAD) == 0) { 2183545Swnj if (runout != 0) { 2193545Swnj runout = 0; 2203545Swnj wakeup((caddr_t)&runout); 2213545Swnj } 2223545Swnj wantin++; 223181Sbill } 224181Sbill /* END INLINE EXPANSION */ 225187Sbill goto restart; 22633Sbill } 227187Sbill } else 228187Sbill q = &p->p_link; 22933Sbill } 23033Sbill splx(s); 23133Sbill } 23233Sbill 23333Sbill /* 23433Sbill * Initialize the (doubly-linked) run queues 23533Sbill * to be empty. 23633Sbill */ 23733Sbill rqinit() 23833Sbill { 23933Sbill register int i; 24033Sbill 24133Sbill for (i = 0; i < NQS; i++) 24233Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 24333Sbill } 24433Sbill 24533Sbill /* 24633Sbill * Set the process running; 24733Sbill * arrange for it to be swapped in if necessary. 24833Sbill */ 24933Sbill setrun(p) 2504826Swnj register struct proc *p; 25133Sbill { 2524826Swnj register int s; 25333Sbill 25433Sbill s = spl6(); 25533Sbill switch (p->p_stat) { 25633Sbill 25733Sbill case 0: 25833Sbill case SWAIT: 25933Sbill case SRUN: 26033Sbill case SZOMB: 26133Sbill default: 26233Sbill panic("setrun"); 26333Sbill 264207Sbill case SSTOP: 26533Sbill case SSLEEP: 266181Sbill unsleep(p); /* e.g. when sending signals */ 26733Sbill break; 26833Sbill 26933Sbill case SIDL: 27033Sbill break; 27133Sbill } 27233Sbill p->p_stat = SRUN; 27333Sbill if (p->p_flag & SLOAD) 27433Sbill setrq(p); 27533Sbill splx(s); 2764826Swnj if (p->p_pri < curpri) { 27733Sbill runrun++; 2782443Swnj aston(); 2792443Swnj } 2803545Swnj if ((p->p_flag&SLOAD) == 0) { 2814826Swnj if (runout != 0) { 2823545Swnj runout = 0; 2833545Swnj wakeup((caddr_t)&runout); 2843545Swnj } 2853545Swnj wantin++; 28633Sbill } 28733Sbill } 28833Sbill 28933Sbill /* 29033Sbill * Set user priority. 29133Sbill * The rescheduling flag (runrun) 29233Sbill * is set if the priority is better 29333Sbill * than the currently running process. 29433Sbill */ 29533Sbill setpri(pp) 2964826Swnj register struct proc *pp; 29733Sbill { 2984826Swnj register int p; 29933Sbill 3003875Swnj p = (pp->p_cpu & 0377)/4; 3011543Sbill p += PUSER + 2*(pp->p_nice - NZERO); 3023530Swnj if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 3033530Swnj p += 2*4; /* effectively, nice(4) */ 3044826Swnj if (p > 127) 30533Sbill p = 127; 3064826Swnj if (p < curpri) { 30733Sbill runrun++; 3082453Swnj aston(); 3092453Swnj } 31033Sbill pp->p_usrpri = p; 3114826Swnj return (p); 31233Sbill } 313