1*8624Sroot /* kern_synch.c 4.23 82/10/17 */ 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" 128102Sroot #ifdef MUSH 137485Skre #include "../h/quota.h" 148102Sroot #include "../h/share.h" 158102Sroot #endif 168102Sroot #include "../h/kernel.h" 178102Sroot #include "../h/buf.h" 188445Sroot #include "../vax/mtpr.h" /* XXX */ 1933Sbill 208102Sroot /* 218102Sroot * Force switch among equal priority processes every 100ms. 228102Sroot */ 238102Sroot roundrobin() 248102Sroot { 258102Sroot 268102Sroot runrun++; 278102Sroot aston(); 28*8624Sroot timeout(roundrobin, (caddr_t)0, hz / 10); 298102Sroot } 308102Sroot 318113Sroot /* constants to digital decay and forget 90% of usage in 5*loadav time */ 328102Sroot #undef ave 338102Sroot #define ave(a,b) ((int)(((int)(a*b))/(b+1))) 348102Sroot int nrscale = 2; 358102Sroot double avenrun[]; 368102Sroot double ccpu = 0.95122942450071400909; /* exp(-1/20) */ 378102Sroot 388102Sroot /* 398102Sroot * Recompute process priorities, once a second 408102Sroot */ 418102Sroot schedcpu() 428102Sroot { 438102Sroot register struct proc *p; 448102Sroot register int s, a; 458102Sroot 468102Sroot wakeup((caddr_t)&lbolt); 478102Sroot for (p = proc; p < procNPROC; p++) if (p->p_stat && p->p_stat!=SZOMB) { 488102Sroot #ifdef MUSH 498102Sroot if (p->p_quota->q_uid) 508102Sroot p->p_quota->q_cost += 518102Sroot shconsts.sc_click * p->p_rssize; 528102Sroot #endif 538102Sroot if (p->p_time != 127) 548102Sroot p->p_time++; 558102Sroot if (p->p_stat==SSLEEP || p->p_stat==SSTOP) 568102Sroot if (p->p_slptime != 127) 578102Sroot p->p_slptime++; 588102Sroot if (p->p_flag&SLOAD) 598102Sroot p->p_pctcpu = ccpu * p->p_pctcpu + 608102Sroot (1.0 - ccpu) * (p->p_cpticks/(float)hz); 618102Sroot p->p_cpticks = 0; 628102Sroot #ifdef MUSH 638102Sroot a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) + 648102Sroot p->p_nice - NZERO + p->p_quota->q_nice; 658102Sroot #else 668102Sroot a = ave((p->p_cpu & 0377), avenrun[0]*nrscale) + 678102Sroot p->p_nice - NZERO; 688102Sroot #endif 698102Sroot if (a < 0) 708102Sroot a = 0; 718102Sroot if (a > 255) 728102Sroot a = 255; 738102Sroot p->p_cpu = a; 748102Sroot (void) setpri(p); 758102Sroot s = spl6(); /* prevent state changes */ 768102Sroot if (p->p_pri >= PUSER) { 778102Sroot if ((p != u.u_procp || noproc) && 788102Sroot p->p_stat == SRUN && 798102Sroot (p->p_flag & SLOAD) && 808102Sroot p->p_pri != p->p_usrpri) { 818102Sroot remrq(p); 828102Sroot p->p_pri = p->p_usrpri; 838102Sroot setrq(p); 848102Sroot } else 858102Sroot p->p_pri = p->p_usrpri; 868102Sroot } 878102Sroot splx(s); 888102Sroot } 898102Sroot vmmeter(); 908102Sroot if (runin!=0) { 918102Sroot runin = 0; 928102Sroot wakeup((caddr_t)&runin); 938102Sroot } 948102Sroot if (bclnlist != NULL) 958102Sroot wakeup((caddr_t)&proc[2]); 96*8624Sroot timeout(schedcpu, (caddr_t)0, hz); 978102Sroot } 988102Sroot 9933Sbill #define SQSIZE 0100 /* Must be power of 2 */ 10033Sbill #define HASH(x) (( (int) x >> 5) & (SQSIZE-1)) 10133Sbill struct proc *slpque[SQSIZE]; 10233Sbill 10333Sbill /* 10433Sbill * Give up the processor till a wakeup occurs 10533Sbill * on chan, at which time the process 10633Sbill * enters the scheduling queue at priority pri. 10733Sbill * The most important effect of pri is that when 10833Sbill * pri<=PZERO a signal cannot disturb the sleep; 10933Sbill * if pri>PZERO signals will be processed. 11033Sbill * Callers of this routine must be prepared for 11133Sbill * premature return, and check that the reason for 11233Sbill * sleeping has gone away. 11333Sbill */ 11433Sbill sleep(chan, pri) 1158033Sroot caddr_t chan; 1168033Sroot int pri; 11733Sbill { 118187Sbill register struct proc *rp, **hp; 119207Sbill register s; 12033Sbill 12133Sbill rp = u.u_procp; 12233Sbill s = spl6(); 12333Sbill if (chan==0 || rp->p_stat != SRUN || rp->p_rlink) 12433Sbill panic("sleep"); 12533Sbill rp->p_wchan = chan; 12633Sbill rp->p_slptime = 0; 12733Sbill rp->p_pri = pri; 128187Sbill hp = &slpque[HASH(chan)]; 129187Sbill rp->p_link = *hp; 130187Sbill *hp = rp; 1314826Swnj if (pri > PZERO) { 1324826Swnj if (ISSIG(rp)) { 133187Sbill if (rp->p_wchan) 134187Sbill unsleep(rp); 13533Sbill rp->p_stat = SRUN; 136131Sbill (void) spl0(); 13733Sbill goto psig; 13833Sbill } 139187Sbill if (rp->p_wchan == 0) 140187Sbill goto out; 141187Sbill rp->p_stat = SSLEEP; 142131Sbill (void) spl0(); 1438033Sroot u.u_ru.ru_nvcsw++; 14433Sbill swtch(); 1454826Swnj if (ISSIG(rp)) 14633Sbill goto psig; 14733Sbill } else { 148207Sbill rp->p_stat = SSLEEP; 149131Sbill (void) spl0(); 1508033Sroot u.u_ru.ru_nvcsw++; 15133Sbill swtch(); 15233Sbill } 153187Sbill out: 15433Sbill splx(s); 15533Sbill return; 15633Sbill 15733Sbill /* 15833Sbill * If priority was low (>PZERO) and 1594826Swnj * there has been a signal, execute non-local goto through 1608113Sroot * u.u_qsave, aborting the system call in progress (see trap.c) 1614826Swnj * (or finishing a tsleep, see below) 16233Sbill */ 16333Sbill psig: 1648113Sroot longjmp(&u.u_qsave); 16533Sbill /*NOTREACHED*/ 16633Sbill } 16733Sbill 16833Sbill /* 169181Sbill * Remove a process from its wait queue 170181Sbill */ 171181Sbill unsleep(p) 1724826Swnj register struct proc *p; 173181Sbill { 174181Sbill register struct proc **hp; 175181Sbill register s; 176181Sbill 177181Sbill s = spl6(); 178181Sbill if (p->p_wchan) { 179181Sbill hp = &slpque[HASH(p->p_wchan)]; 180181Sbill while (*hp != p) 181181Sbill hp = &(*hp)->p_link; 182181Sbill *hp = p->p_link; 183181Sbill p->p_wchan = 0; 184181Sbill } 185181Sbill splx(s); 186181Sbill } 187181Sbill 188181Sbill /* 18933Sbill * Wake up all processes sleeping on chan. 19033Sbill */ 19133Sbill wakeup(chan) 1924826Swnj register caddr_t chan; 19333Sbill { 194187Sbill register struct proc *p, **q, **h; 19533Sbill int s; 19633Sbill 19733Sbill s = spl6(); 198187Sbill h = &slpque[HASH(chan)]; 19933Sbill restart: 200187Sbill for (q = h; p = *q; ) { 201181Sbill if (p->p_rlink || p->p_stat != SSLEEP && p->p_stat != SSTOP) 20233Sbill panic("wakeup"); 203207Sbill if (p->p_wchan==chan) { 20433Sbill p->p_wchan = 0; 205187Sbill *q = p->p_link; 20633Sbill p->p_slptime = 0; 207181Sbill if (p->p_stat == SSLEEP) { 208181Sbill /* OPTIMIZED INLINE EXPANSION OF setrun(p) */ 209181Sbill p->p_stat = SRUN; 2102702Swnj if (p->p_flag & SLOAD) 211181Sbill setrq(p); 2124826Swnj if (p->p_pri < curpri) { 213181Sbill runrun++; 2142443Swnj aston(); 2152443Swnj } 2163545Swnj if ((p->p_flag&SLOAD) == 0) { 2173545Swnj if (runout != 0) { 2183545Swnj runout = 0; 2193545Swnj wakeup((caddr_t)&runout); 2203545Swnj } 2213545Swnj wantin++; 222181Sbill } 223181Sbill /* END INLINE EXPANSION */ 224187Sbill goto restart; 22533Sbill } 226187Sbill } else 227187Sbill q = &p->p_link; 22833Sbill } 22933Sbill splx(s); 23033Sbill } 23133Sbill 23233Sbill /* 23333Sbill * Initialize the (doubly-linked) run queues 23433Sbill * to be empty. 23533Sbill */ 23633Sbill rqinit() 23733Sbill { 23833Sbill register int i; 23933Sbill 24033Sbill for (i = 0; i < NQS; i++) 24133Sbill qs[i].ph_link = qs[i].ph_rlink = (struct proc *)&qs[i]; 24233Sbill } 24333Sbill 24433Sbill /* 24533Sbill * Set the process running; 24633Sbill * arrange for it to be swapped in if necessary. 24733Sbill */ 24833Sbill setrun(p) 2494826Swnj register struct proc *p; 25033Sbill { 2514826Swnj register int s; 25233Sbill 25333Sbill s = spl6(); 25433Sbill switch (p->p_stat) { 25533Sbill 25633Sbill case 0: 25733Sbill case SWAIT: 25833Sbill case SRUN: 25933Sbill case SZOMB: 26033Sbill default: 26133Sbill panic("setrun"); 26233Sbill 263207Sbill case SSTOP: 26433Sbill case SSLEEP: 265181Sbill unsleep(p); /* e.g. when sending signals */ 26633Sbill break; 26733Sbill 26833Sbill case SIDL: 26933Sbill break; 27033Sbill } 27133Sbill p->p_stat = SRUN; 27233Sbill if (p->p_flag & SLOAD) 27333Sbill setrq(p); 27433Sbill splx(s); 2754826Swnj if (p->p_pri < curpri) { 27633Sbill runrun++; 2772443Swnj aston(); 2782443Swnj } 2793545Swnj if ((p->p_flag&SLOAD) == 0) { 2804826Swnj if (runout != 0) { 2813545Swnj runout = 0; 2823545Swnj wakeup((caddr_t)&runout); 2833545Swnj } 2843545Swnj wantin++; 28533Sbill } 28633Sbill } 28733Sbill 28833Sbill /* 28933Sbill * Set user priority. 29033Sbill * The rescheduling flag (runrun) 29133Sbill * is set if the priority is better 29233Sbill * than the currently running process. 29333Sbill */ 29433Sbill setpri(pp) 2954826Swnj register struct proc *pp; 29633Sbill { 2974826Swnj register int p; 29833Sbill 2993875Swnj p = (pp->p_cpu & 0377)/4; 3001543Sbill p += PUSER + 2*(pp->p_nice - NZERO); 3013530Swnj if (pp->p_rssize > pp->p_maxrss && freemem < desfree) 3023530Swnj p += 2*4; /* effectively, nice(4) */ 3034826Swnj if (p > 127) 30433Sbill p = 127; 3054826Swnj if (p < curpri) { 30633Sbill runrun++; 3072453Swnj aston(); 3082453Swnj } 30933Sbill pp->p_usrpri = p; 3104826Swnj return (p); 31133Sbill } 312